aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorPaul Gilbert2012-10-31 09:34:38 +1100
committerPaul Gilbert2012-10-31 09:34:38 +1100
commit798ddfaab500bb212f620cf095328eee5eb140a4 (patch)
tree55b5d0b90affd88063c04b7ff62fea1616b83e80 /engines
parentef663f95a516d8fe47a245653d418c047361281a (diff)
parentfdc80fd952120ecb8a4941edd4c2e404cdc5fa33 (diff)
downloadscummvm-rg350-798ddfaab500bb212f620cf095328eee5eb140a4.tar.gz
scummvm-rg350-798ddfaab500bb212f620cf095328eee5eb140a4.tar.bz2
scummvm-rg350-798ddfaab500bb212f620cf095328eee5eb140a4.zip
Merge branch 'master' into hopkins
Diffstat (limited to 'engines')
-rw-r--r--engines/advancedDetector.h4
-rw-r--r--engines/agi/agi.cpp2
-rw-r--r--engines/agi/detection_tables.h4
-rw-r--r--engines/agi/loader_v1.cpp16
-rw-r--r--engines/agi/menu.cpp2
-rw-r--r--engines/agi/op_cmd.cpp6
-rw-r--r--engines/agi/op_test.cpp2
-rw-r--r--engines/agi/opcodes.cpp2
-rw-r--r--engines/agi/saveload.cpp2
-rw-r--r--engines/agi/sound_pcjr.cpp4
-rw-r--r--engines/agi/text.cpp4
-rw-r--r--engines/agi/words.cpp4
-rw-r--r--engines/agos/midiparser_s1d.cpp47
-rw-r--r--engines/agos/saveload.cpp4
-rw-r--r--engines/agos/sound.cpp2
-rw-r--r--engines/cge/bitmap.cpp4
-rw-r--r--engines/cge/cge_main.cpp8
-rw-r--r--engines/cge/detection.cpp4
-rw-r--r--engines/cge/events.h2
-rw-r--r--engines/cge/fileio.cpp2
-rw-r--r--engines/cge/text.cpp2
-rw-r--r--engines/cine/anim.cpp62
-rw-r--r--engines/cine/cine.cpp13
-rw-r--r--engines/cine/cine.h2
-rw-r--r--engines/cine/console.cpp2
-rw-r--r--engines/cine/gfx.cpp87
-rw-r--r--engines/cine/gfx.h3
-rw-r--r--engines/cine/main_loop.cpp29
-rw-r--r--engines/cine/object.cpp2
-rw-r--r--engines/cine/pal.cpp3
-rw-r--r--engines/cine/part.cpp2
-rw-r--r--engines/cine/saveload.cpp2
-rw-r--r--engines/cine/saveload.h2
-rw-r--r--engines/cine/script.h1
-rw-r--r--engines/cine/script_fw.cpp1640
-rw-r--r--engines/cine/sound.cpp161
-rw-r--r--engines/cine/sound.h36
-rw-r--r--engines/cine/texte.cpp2
-rw-r--r--engines/cine/texte.h2
-rw-r--r--engines/cine/various.cpp218
-rw-r--r--engines/composer/composer.cpp7
-rw-r--r--engines/composer/composer.h2
-rw-r--r--engines/composer/graphics.cpp14
-rw-r--r--engines/composer/resource.cpp2
-rw-r--r--engines/configure.engines28
-rw-r--r--engines/cruise/detection.cpp2
-rw-r--r--engines/dialogs.cpp2
-rw-r--r--engines/draci/detection.cpp2
-rw-r--r--engines/drascula/detection.cpp14
-rw-r--r--engines/dreamweb/dreamweb.cpp6
-rw-r--r--engines/dreamweb/dreamweb.h2
-rw-r--r--engines/dreamweb/monitor.cpp4
-rw-r--r--engines/dreamweb/object.cpp4
-rw-r--r--engines/dreamweb/people.cpp16
-rw-r--r--engines/dreamweb/print.cpp2
-rw-r--r--engines/dreamweb/sprite.cpp14
-rw-r--r--engines/dreamweb/vgagrafx.cpp72
-rw-r--r--engines/engines.mk5
-rw-r--r--engines/groovie/detection.cpp2
-rw-r--r--engines/groovie/roq.cpp27
-rw-r--r--engines/hugo/file.cpp82
-rw-r--r--engines/hugo/file.h5
-rw-r--r--engines/lure/decode.cpp4
-rw-r--r--engines/made/screenfx.cpp8
-rw-r--r--engines/mohawk/bitmap.cpp6
-rw-r--r--engines/mohawk/video.cpp2
-rw-r--r--engines/mohawk/video.h2
-rw-r--r--engines/parallaction/adlib.cpp808
-rw-r--r--engines/parallaction/callables_ns.cpp12
-rw-r--r--engines/parallaction/debug.cpp8
-rw-r--r--engines/parallaction/dialogue.cpp8
-rw-r--r--engines/parallaction/disk_br.cpp4
-rw-r--r--engines/parallaction/disk_ns.cpp11
-rw-r--r--engines/parallaction/exec.cpp6
-rw-r--r--engines/parallaction/exec_br.cpp8
-rw-r--r--engines/parallaction/exec_ns.cpp8
-rw-r--r--engines/parallaction/font.cpp4
-rw-r--r--engines/parallaction/gfxbase.cpp13
-rw-r--r--engines/parallaction/graphics.cpp4
-rw-r--r--engines/parallaction/graphics.h4
-rw-r--r--engines/parallaction/gui_ns.cpp2
-rw-r--r--engines/parallaction/input.cpp22
-rw-r--r--engines/parallaction/module.mk1
-rw-r--r--engines/parallaction/objects.cpp4
-rw-r--r--engines/parallaction/parallaction.cpp32
-rw-r--r--engines/parallaction/parallaction.h24
-rw-r--r--engines/parallaction/parallaction_br.cpp14
-rw-r--r--engines/parallaction/parallaction_ns.cpp20
-rw-r--r--engines/parallaction/parser_br.cpp4
-rw-r--r--engines/parallaction/parser_ns.cpp2
-rw-r--r--engines/parallaction/saveload.cpp6
-rw-r--r--engines/parallaction/sound.h2
-rw-r--r--engines/parallaction/sound_br.cpp34
-rw-r--r--engines/parallaction/sound_ns.cpp6
-rw-r--r--engines/parallaction/staticres.cpp28
-rw-r--r--engines/parallaction/walk.cpp28
-rw-r--r--engines/parallaction/walk.h8
-rw-r--r--engines/pegasus/ai/ai_action.cpp78
-rw-r--r--engines/pegasus/ai/ai_action.h136
-rw-r--r--engines/pegasus/ai/ai_area.cpp613
-rw-r--r--engines/pegasus/ai/ai_area.h172
-rw-r--r--engines/pegasus/ai/ai_condition.cpp290
-rw-r--r--engines/pegasus/ai/ai_condition.h287
-rw-r--r--engines/pegasus/ai/ai_rule.cpp78
-rw-r--r--engines/pegasus/ai/ai_rule.h86
-rw-r--r--engines/pegasus/compass.cpp82
-rw-r--r--engines/pegasus/compass.h58
-rw-r--r--engines/pegasus/console.cpp102
-rw-r--r--engines/pegasus/console.h46
-rw-r--r--engines/pegasus/constants.h729
-rw-r--r--engines/pegasus/cursor.cpp213
-rw-r--r--engines/pegasus/cursor.h84
-rw-r--r--engines/pegasus/detection.cpp157
-rw-r--r--engines/pegasus/elements.cpp568
-rw-r--r--engines/pegasus/elements.h254
-rw-r--r--engines/pegasus/energymonitor.cpp296
-rw-r--r--engines/pegasus/energymonitor.h111
-rw-r--r--engines/pegasus/fader.cpp218
-rw-r--r--engines/pegasus/fader.h130
-rw-r--r--engines/pegasus/gamestate.cpp2359
-rw-r--r--engines/pegasus/gamestate.h886
-rw-r--r--engines/pegasus/graphics.cpp346
-rw-r--r--engines/pegasus/graphics.h95
-rw-r--r--engines/pegasus/hotspot.cpp325
-rw-r--r--engines/pegasus/hotspot.h152
-rw-r--r--engines/pegasus/input.cpp373
-rw-r--r--engines/pegasus/input.h500
-rw-r--r--engines/pegasus/interaction.h110
-rw-r--r--engines/pegasus/interface.cpp667
-rw-r--r--engines/pegasus/interface.h148
-rw-r--r--engines/pegasus/items/autodragger.cpp91
-rw-r--r--engines/pegasus/items/autodragger.h57
-rw-r--r--engines/pegasus/items/biochips/aichip.cpp279
-rw-r--r--engines/pegasus/items/biochips/aichip.h69
-rw-r--r--engines/pegasus/items/biochips/biochipitem.cpp95
-rw-r--r--engines/pegasus/items/biochips/biochipitem.h54
-rw-r--r--engines/pegasus/items/biochips/mapchip.cpp106
-rw-r--r--engines/pegasus/items/biochips/mapchip.h64
-rw-r--r--engines/pegasus/items/biochips/mapimage.cpp443
-rw-r--r--engines/pegasus/items/biochips/mapimage.h84
-rw-r--r--engines/pegasus/items/biochips/opticalchip.cpp190
-rw-r--r--engines/pegasus/items/biochips/opticalchip.h71
-rw-r--r--engines/pegasus/items/biochips/pegasuschip.cpp198
-rw-r--r--engines/pegasus/items/biochips/pegasuschip.h55
-rw-r--r--engines/pegasus/items/biochips/retscanchip.cpp49
-rw-r--r--engines/pegasus/items/biochips/retscanchip.h43
-rw-r--r--engines/pegasus/items/biochips/shieldchip.cpp53
-rw-r--r--engines/pegasus/items/biochips/shieldchip.h46
-rw-r--r--engines/pegasus/items/inventory.cpp175
-rw-r--r--engines/pegasus/items/inventory.h80
-rw-r--r--engines/pegasus/items/inventory/airmask.cpp249
-rw-r--r--engines/pegasus/items/inventory/airmask.h76
-rw-r--r--engines/pegasus/items/inventory/gascanister.cpp46
-rw-r--r--engines/pegasus/items/inventory/gascanister.h44
-rw-r--r--engines/pegasus/items/inventory/inventoryitem.cpp110
-rw-r--r--engines/pegasus/items/inventory/inventoryitem.h67
-rw-r--r--engines/pegasus/items/inventory/keycard.cpp59
-rw-r--r--engines/pegasus/items/inventory/keycard.h48
-rw-r--r--engines/pegasus/items/inventorypicture.cpp370
-rw-r--r--engines/pegasus/items/inventorypicture.h125
-rw-r--r--engines/pegasus/items/item.cpp314
-rw-r--r--engines/pegasus/items/item.h363
-rw-r--r--engines/pegasus/items/itemdragger.cpp193
-rw-r--r--engines/pegasus/items/itemdragger.h96
-rw-r--r--engines/pegasus/items/itemlist.cpp67
-rw-r--r--engines/pegasus/items/itemlist.h59
-rw-r--r--engines/pegasus/menu.cpp1219
-rw-r--r--engines/pegasus/menu.h171
-rw-r--r--engines/pegasus/module.mk100
-rw-r--r--engines/pegasus/movie.cpp280
-rw-r--r--engines/pegasus/movie.h105
-rw-r--r--engines/pegasus/neighborhood/caldoria/caldoria.cpp1962
-rw-r--r--engines/pegasus/neighborhood/caldoria/caldoria.h523
-rw-r--r--engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp370
-rw-r--r--engines/pegasus/neighborhood/caldoria/caldoria4dsystem.h78
-rw-r--r--engines/pegasus/neighborhood/caldoria/caldoriabomb.cpp1442
-rw-r--r--engines/pegasus/neighborhood/caldoria/caldoriabomb.h156
-rw-r--r--engines/pegasus/neighborhood/caldoria/caldoriamessages.cpp115
-rw-r--r--engines/pegasus/neighborhood/caldoria/caldoriamessages.h60
-rw-r--r--engines/pegasus/neighborhood/caldoria/caldoriamirror.cpp135
-rw-r--r--engines/pegasus/neighborhood/caldoria/caldoriamirror.h54
-rw-r--r--engines/pegasus/neighborhood/door.cpp64
-rw-r--r--engines/pegasus/neighborhood/door.h90
-rw-r--r--engines/pegasus/neighborhood/exit.cpp70
-rw-r--r--engines/pegasus/neighborhood/exit.h93
-rw-r--r--engines/pegasus/neighborhood/extra.cpp58
-rw-r--r--engines/pegasus/neighborhood/extra.h67
-rw-r--r--engines/pegasus/neighborhood/hotspotinfo.cpp65
-rw-r--r--engines/pegasus/neighborhood/hotspotinfo.h77
-rw-r--r--engines/pegasus/neighborhood/mars/constants.h941
-rw-r--r--engines/pegasus/neighborhood/mars/energybeam.cpp70
-rw-r--r--engines/pegasus/neighborhood/mars/energybeam.h43
-rw-r--r--engines/pegasus/neighborhood/mars/gravitoncannon.cpp134
-rw-r--r--engines/pegasus/neighborhood/mars/gravitoncannon.h57
-rw-r--r--engines/pegasus/neighborhood/mars/hermite.cpp76
-rw-r--r--engines/pegasus/neighborhood/mars/hermite.h41
-rw-r--r--engines/pegasus/neighborhood/mars/mars.cpp3735
-rw-r--r--engines/pegasus/neighborhood/mars/mars.h238
-rw-r--r--engines/pegasus/neighborhood/mars/planetmover.cpp104
-rw-r--r--engines/pegasus/neighborhood/mars/planetmover.h57
-rw-r--r--engines/pegasus/neighborhood/mars/reactor.cpp297
-rw-r--r--engines/pegasus/neighborhood/mars/reactor.h108
-rw-r--r--engines/pegasus/neighborhood/mars/robotship.cpp267
-rw-r--r--engines/pegasus/neighborhood/mars/robotship.h84
-rw-r--r--engines/pegasus/neighborhood/mars/shuttleenergymeter.cpp116
-rw-r--r--engines/pegasus/neighborhood/mars/shuttleenergymeter.h73
-rw-r--r--engines/pegasus/neighborhood/mars/shuttlehud.cpp246
-rw-r--r--engines/pegasus/neighborhood/mars/shuttlehud.h60
-rw-r--r--engines/pegasus/neighborhood/mars/shuttleweapon.cpp129
-rw-r--r--engines/pegasus/neighborhood/mars/shuttleweapon.h68
-rw-r--r--engines/pegasus/neighborhood/mars/spacechase3d.cpp106
-rw-r--r--engines/pegasus/neighborhood/mars/spacechase3d.h91
-rw-r--r--engines/pegasus/neighborhood/mars/spacejunk.cpp212
-rw-r--r--engines/pegasus/neighborhood/mars/spacejunk.h78
-rw-r--r--engines/pegasus/neighborhood/mars/tractorbeam.cpp139
-rw-r--r--engines/pegasus/neighborhood/mars/tractorbeam.h43
-rw-r--r--engines/pegasus/neighborhood/neighborhood.cpp1774
-rw-r--r--engines/pegasus/neighborhood/neighborhood.h408
-rw-r--r--engines/pegasus/neighborhood/norad/alpha/ecrmonitor.cpp219
-rw-r--r--engines/pegasus/neighborhood/norad/alpha/ecrmonitor.h65
-rw-r--r--engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp445
-rw-r--r--engines/pegasus/neighborhood/norad/alpha/fillingstation.h91
-rw-r--r--engines/pegasus/neighborhood/norad/alpha/noradalpha.cpp763
-rw-r--r--engines/pegasus/neighborhood/norad/alpha/noradalpha.h115
-rw-r--r--engines/pegasus/neighborhood/norad/alpha/panorama.cpp239
-rw-r--r--engines/pegasus/neighborhood/norad/alpha/panorama.h98
-rw-r--r--engines/pegasus/neighborhood/norad/alpha/panoramascroll.cpp91
-rw-r--r--engines/pegasus/neighborhood/norad/alpha/panoramascroll.h60
-rw-r--r--engines/pegasus/neighborhood/norad/constants.h755
-rw-r--r--engines/pegasus/neighborhood/norad/delta/globegame.cpp1062
-rw-r--r--engines/pegasus/neighborhood/norad/delta/globegame.h169
-rw-r--r--engines/pegasus/neighborhood/norad/delta/noraddelta.cpp869
-rw-r--r--engines/pegasus/neighborhood/norad/delta/noraddelta.h117
-rw-r--r--engines/pegasus/neighborhood/norad/norad.cpp285
-rw-r--r--engines/pegasus/neighborhood/norad/norad.h121
-rw-r--r--engines/pegasus/neighborhood/norad/noradelevator.cpp130
-rw-r--r--engines/pegasus/neighborhood/norad/noradelevator.h67
-rw-r--r--engines/pegasus/neighborhood/norad/pressuredoor.cpp554
-rw-r--r--engines/pegasus/neighborhood/norad/pressuredoor.h93
-rw-r--r--engines/pegasus/neighborhood/norad/pressuretracker.cpp87
-rw-r--r--engines/pegasus/neighborhood/norad/pressuretracker.h69
-rw-r--r--engines/pegasus/neighborhood/norad/subcontrolroom.cpp1178
-rw-r--r--engines/pegasus/neighborhood/norad/subcontrolroom.h133
-rw-r--r--engines/pegasus/neighborhood/norad/subplatform.cpp205
-rw-r--r--engines/pegasus/neighborhood/norad/subplatform.h63
-rw-r--r--engines/pegasus/neighborhood/prehistoric/prehistoric.cpp689
-rw-r--r--engines/pegasus/neighborhood/prehistoric/prehistoric.h158
-rw-r--r--engines/pegasus/neighborhood/spot.cpp70
-rw-r--r--engines/pegasus/neighborhood/spot.h97
-rw-r--r--engines/pegasus/neighborhood/tsa/fulltsa.cpp3023
-rw-r--r--engines/pegasus/neighborhood/tsa/fulltsa.h159
-rw-r--r--engines/pegasus/neighborhood/tsa/tinytsa.cpp453
-rw-r--r--engines/pegasus/neighborhood/tsa/tinytsa.h71
-rw-r--r--engines/pegasus/neighborhood/turn.cpp63
-rw-r--r--engines/pegasus/neighborhood/turn.h69
-rw-r--r--engines/pegasus/neighborhood/view.cpp60
-rw-r--r--engines/pegasus/neighborhood/view.h68
-rw-r--r--engines/pegasus/neighborhood/wsc/moleculebin.cpp127
-rw-r--r--engines/pegasus/neighborhood/wsc/moleculebin.h72
-rw-r--r--engines/pegasus/neighborhood/wsc/wsc.cpp2546
-rw-r--r--engines/pegasus/neighborhood/wsc/wsc.h166
-rw-r--r--engines/pegasus/neighborhood/zoom.cpp74
-rw-r--r--engines/pegasus/neighborhood/zoom.h70
-rw-r--r--engines/pegasus/notification.cpp149
-rw-r--r--engines/pegasus/notification.h123
-rw-r--r--engines/pegasus/pegasus.cpp2347
-rw-r--r--engines/pegasus/pegasus.h327
-rw-r--r--engines/pegasus/scoring.h281
-rw-r--r--engines/pegasus/sound.cpp181
-rw-r--r--engines/pegasus/sound.h108
-rw-r--r--engines/pegasus/surface.cpp396
-rw-r--r--engines/pegasus/surface.h140
-rw-r--r--engines/pegasus/timers.cpp429
-rw-r--r--engines/pegasus/timers.h260
-rw-r--r--engines/pegasus/transition.cpp200
-rw-r--r--engines/pegasus/transition.h108
-rw-r--r--engines/pegasus/types.h161
-rw-r--r--engines/pegasus/util.cpp77
-rw-r--r--engines/pegasus/util.h117
-rw-r--r--engines/plugins_table.h3
-rw-r--r--engines/queen/display.cpp38
-rw-r--r--engines/queen/queen.cpp4
-rw-r--r--engines/saga/script.cpp2
-rw-r--r--engines/sci/console.cpp6
-rw-r--r--engines/sci/detection.cpp11
-rw-r--r--engines/sci/detection_tables.h22
-rw-r--r--engines/sci/engine/features.cpp8
-rw-r--r--engines/sci/engine/file.cpp4
-rw-r--r--engines/sci/engine/kernel_tables.h4
-rw-r--r--engines/sci/engine/kfile.cpp6
-rw-r--r--engines/sci/engine/kpathing.cpp647
-rw-r--r--engines/sci/engine/kstring.cpp1
-rw-r--r--engines/sci/engine/kvideo.cpp2
-rw-r--r--engines/sci/engine/script.cpp2
-rw-r--r--engines/sci/engine/script_patches.cpp81
-rw-r--r--engines/sci/engine/scriptdebug.cpp5
-rw-r--r--engines/sci/engine/seg_manager.cpp2
-rw-r--r--engines/sci/engine/vm.cpp2
-rw-r--r--engines/sci/engine/workarounds.cpp3
-rw-r--r--engines/sci/graphics/controls32.cpp6
-rw-r--r--engines/sci/graphics/frameout.cpp14
-rw-r--r--engines/sci/graphics/paint16.cpp4
-rw-r--r--engines/sci/graphics/ports.cpp41
-rw-r--r--engines/sci/sci.cpp1
-rw-r--r--engines/sci/sci.h21
-rw-r--r--engines/sci/sound/drivers/fmtowns.cpp12
-rw-r--r--engines/sci/sound/midiparser_sci.cpp80
-rw-r--r--engines/sci/sound/midiparser_sci.h2
-rw-r--r--engines/sci/sound/soundcmd.cpp6
-rw-r--r--engines/sci/video/robot_decoder.cpp6
-rw-r--r--engines/sci/video/robot_decoder.h4
-rw-r--r--engines/scumm/actor.cpp30
-rw-r--r--engines/scumm/actor.h2
-rw-r--r--engines/scumm/charset.cpp8
-rw-r--r--engines/scumm/charset.h4
-rw-r--r--engines/scumm/costume.cpp4
-rw-r--r--engines/scumm/cursor.cpp2
-rw-r--r--engines/scumm/debugger.cpp2
-rw-r--r--engines/scumm/detection.cpp9
-rw-r--r--engines/scumm/detection_tables.h2
-rw-r--r--engines/scumm/dialogs.cpp2
-rw-r--r--engines/scumm/he/logic/soccer.cpp4
-rw-r--r--engines/scumm/he/wiz_he.cpp3
-rw-r--r--engines/scumm/imuse/imuse.cpp41
-rw-r--r--engines/scumm/imuse/imuse_internal.h2
-rw-r--r--engines/scumm/imuse/imuse_part.cpp13
-rw-r--r--engines/scumm/imuse/imuse_player.cpp5
-rw-r--r--engines/scumm/imuse/instrument.cpp60
-rw-r--r--engines/scumm/imuse/instrument.h4
-rw-r--r--engines/scumm/imuse/mac_m68k.cpp514
-rw-r--r--engines/scumm/imuse/mac_m68k.h177
-rw-r--r--engines/scumm/imuse/sysex_scumm.cpp2
-rw-r--r--engines/scumm/midiparser_ro.cpp16
-rw-r--r--engines/scumm/module.mk1
-rw-r--r--engines/scumm/object.cpp4
-rw-r--r--engines/scumm/player_apple2.cpp68
-rw-r--r--engines/scumm/player_apple2.h10
-rw-r--r--engines/scumm/player_towns.cpp2
-rw-r--r--engines/scumm/player_v2cms.cpp64
-rw-r--r--engines/scumm/saveload.cpp2
-rw-r--r--engines/scumm/saveload.h2
-rw-r--r--engines/scumm/script_v0.cpp12
-rw-r--r--engines/scumm/script_v2.cpp6
-rw-r--r--engines/scumm/script_v5.cpp2
-rw-r--r--engines/scumm/scumm.cpp37
-rw-r--r--engines/scumm/scumm.h13
-rw-r--r--engines/scumm/sound.cpp9
-rw-r--r--engines/scumm/verbs.cpp4
-rw-r--r--engines/sky/detection.cpp4
-rw-r--r--engines/sword1/animation.cpp6
-rw-r--r--engines/sword1/control.cpp4
-rw-r--r--engines/sword1/objectman.cpp4
-rw-r--r--engines/sword1/sword1.cpp4
-rw-r--r--engines/sword1/sword1.h1
-rw-r--r--engines/sword2/sprite.cpp4
-rw-r--r--engines/sword25/sfx/soundengine.cpp2
-rw-r--r--engines/teenagent/actor.cpp87
-rw-r--r--engines/teenagent/actor.h17
-rw-r--r--engines/teenagent/animation.cpp120
-rw-r--r--engines/teenagent/animation.h8
-rw-r--r--engines/teenagent/callbacks.cpp4676
-rw-r--r--engines/teenagent/detection.cpp3
-rw-r--r--engines/teenagent/dialog.cpp117
-rw-r--r--engines/teenagent/dialog.h55
-rw-r--r--engines/teenagent/font.cpp83
-rw-r--r--engines/teenagent/font.h18
-rw-r--r--engines/teenagent/inventory.cpp160
-rw-r--r--engines/teenagent/inventory.h115
-rw-r--r--engines/teenagent/music.cpp48
-rw-r--r--engines/teenagent/music.h7
-rw-r--r--engines/teenagent/objects.cpp53
-rw-r--r--engines/teenagent/objects.h23
-rw-r--r--engines/teenagent/pack.cpp19
-rw-r--r--engines/teenagent/resources.cpp71
-rw-r--r--engines/teenagent/resources.h1149
-rw-r--r--engines/teenagent/scene.cpp884
-rw-r--r--engines/teenagent/scene.h74
-rw-r--r--engines/teenagent/segment.h12
-rw-r--r--engines/teenagent/surface.cpp70
-rw-r--r--engines/teenagent/surface.h11
-rw-r--r--engines/teenagent/surface_list.cpp23
-rw-r--r--engines/teenagent/surface_list.h8
-rw-r--r--engines/teenagent/teenagent.cpp442
-rw-r--r--engines/teenagent/teenagent.h106
-rw-r--r--engines/tinsel/actors.cpp4
-rw-r--r--engines/tinsel/pcode.cpp4
-rw-r--r--engines/tinsel/saveload.cpp2
-rw-r--r--engines/toltecs/animation.cpp14
-rw-r--r--engines/toltecs/animation.h2
-rw-r--r--engines/toltecs/menu.cpp110
-rw-r--r--engines/toltecs/menu.h21
-rw-r--r--engines/toltecs/microtiles.cpp2
-rw-r--r--engines/toltecs/movie.cpp58
-rw-r--r--engines/toltecs/movie.h8
-rw-r--r--engines/toltecs/music.cpp20
-rw-r--r--engines/toltecs/music.h2
-rw-r--r--engines/toltecs/palette.cpp18
-rw-r--r--engines/toltecs/palette.h2
-rw-r--r--engines/toltecs/render.cpp14
-rw-r--r--engines/toltecs/render.h4
-rw-r--r--engines/toltecs/resource.cpp8
-rw-r--r--engines/toltecs/saveload.cpp17
-rw-r--r--engines/toltecs/screen.cpp49
-rw-r--r--engines/toltecs/screen.h19
-rw-r--r--engines/toltecs/script.cpp41
-rw-r--r--engines/toltecs/script.h6
-rw-r--r--engines/toltecs/segmap.cpp20
-rw-r--r--engines/toltecs/segmap.h8
-rw-r--r--engines/toltecs/sound.cpp107
-rw-r--r--engines/toltecs/sound.h7
-rw-r--r--engines/toltecs/sprite.cpp20
-rw-r--r--engines/toltecs/toltecs.cpp82
-rw-r--r--engines/toltecs/toltecs.h23
-rw-r--r--engines/tony/custom.cpp825
-rw-r--r--engines/tony/custom.h18
-rw-r--r--engines/tony/detection_tables.h49
-rw-r--r--engines/tony/font.cpp71
-rw-r--r--engines/tony/font.h4
-rw-r--r--engines/tony/game.cpp35
-rw-r--r--engines/tony/gfxcore.cpp282
-rw-r--r--engines/tony/gfxcore.h40
-rw-r--r--engines/tony/gfxengine.cpp59
-rw-r--r--engines/tony/inventory.cpp49
-rw-r--r--engines/tony/loc.cpp368
-rw-r--r--engines/tony/loc.h10
-rw-r--r--engines/tony/mpal/expr.cpp92
-rw-r--r--engines/tony/mpal/expr.h61
-rw-r--r--engines/tony/mpal/loadmpc.cpp6
-rw-r--r--engines/tony/mpal/memory.cpp4
-rw-r--r--engines/tony/mpal/memory.h2
-rw-r--r--engines/tony/mpal/mpal.cpp55
-rw-r--r--engines/tony/mpal/mpal.h2
-rw-r--r--engines/tony/mpal/mpalutils.cpp2
-rw-r--r--engines/tony/mpal/mpalutils.h2
-rw-r--r--engines/tony/sound.cpp247
-rw-r--r--engines/tony/sound.h98
-rw-r--r--engines/tony/tony.cpp31
-rw-r--r--engines/tony/tony.h3
-rw-r--r--engines/tony/utils.cpp2
-rw-r--r--engines/tony/window.cpp2
-rw-r--r--engines/toon/detection.cpp2
-rw-r--r--engines/toon/movie.h2
-rw-r--r--engines/toon/picture.cpp2
-rw-r--r--engines/touche/staticres.cpp5
-rw-r--r--engines/tsage/blue_force/blueforce_scenes3.cpp8
-rw-r--r--engines/tsage/blue_force/blueforce_scenes7.cpp2
-rw-r--r--engines/tsage/blue_force/blueforce_speakers.cpp28
-rw-r--r--engines/tsage/blue_force/blueforce_speakers.h6
-rw-r--r--engines/tsage/detection.cpp2
-rw-r--r--engines/tsage/globals.cpp8
-rw-r--r--engines/tsage/ringworld/ringworld_logic.cpp2
-rw-r--r--engines/tsage/ringworld2/ringworld2_logic.cpp6
-rw-r--r--engines/tsage/scenes.h2
-rw-r--r--engines/tsage/tsage.cpp6
-rw-r--r--engines/tucker/resource.cpp33
-rw-r--r--engines/wintermute/ad/ad_actor.cpp34
-rw-r--r--engines/wintermute/ad/ad_actor.h2
-rw-r--r--engines/wintermute/ad/ad_entity.cpp47
-rw-r--r--engines/wintermute/ad/ad_entity.h2
-rw-r--r--engines/wintermute/ad/ad_game.cpp37
-rw-r--r--engines/wintermute/ad/ad_game.h2
-rw-r--r--engines/wintermute/ad/ad_inventory_box.cpp1
-rw-r--r--engines/wintermute/ad/ad_item.cpp28
-rw-r--r--engines/wintermute/ad/ad_item.h2
-rw-r--r--engines/wintermute/ad/ad_layer.cpp20
-rw-r--r--engines/wintermute/ad/ad_layer.h2
-rw-r--r--engines/wintermute/ad/ad_object.cpp37
-rw-r--r--engines/wintermute/ad/ad_object.h2
-rw-r--r--engines/wintermute/ad/ad_region.cpp20
-rw-r--r--engines/wintermute/ad/ad_region.h2
-rw-r--r--engines/wintermute/ad/ad_response.cpp2
-rw-r--r--engines/wintermute/ad/ad_response_box.cpp13
-rw-r--r--engines/wintermute/ad/ad_rot_level.cpp4
-rw-r--r--engines/wintermute/ad/ad_scale_level.cpp4
-rw-r--r--engines/wintermute/ad/ad_scene.cpp39
-rw-r--r--engines/wintermute/ad/ad_scene.h2
-rw-r--r--engines/wintermute/ad/ad_scene_state.cpp2
-rw-r--r--engines/wintermute/ad/ad_sentence.cpp9
-rw-r--r--engines/wintermute/ad/ad_sprite_set.cpp2
-rw-r--r--engines/wintermute/ad/ad_talk_def.cpp2
-rw-r--r--engines/wintermute/ad/ad_talk_holder.cpp10
-rw-r--r--engines/wintermute/ad/ad_talk_holder.h2
-rw-r--r--engines/wintermute/ad/ad_talk_node.cpp6
-rw-r--r--engines/wintermute/ad/ad_waypoint_group.cpp12
-rw-r--r--engines/wintermute/ad/ad_waypoint_group.h2
-rw-r--r--engines/wintermute/base/base_active_rect.cpp1
-rw-r--r--engines/wintermute/base/base_dynamic_buffer.h7
-rw-r--r--engines/wintermute/base/base_engine.cpp12
-rw-r--r--engines/wintermute/base/base_engine.h6
-rw-r--r--engines/wintermute/base/base_fader.cpp1
-rw-r--r--engines/wintermute/base/base_fader.h2
-rw-r--r--engines/wintermute/base/base_frame.cpp24
-rw-r--r--engines/wintermute/base/base_frame.h12
-rw-r--r--engines/wintermute/base/base_game.cpp103
-rw-r--r--engines/wintermute/base/base_game.h3
-rw-r--r--engines/wintermute/base/base_keyboard_state.cpp16
-rw-r--r--engines/wintermute/base/base_keyboard_state.h2
-rw-r--r--engines/wintermute/base/base_object.cpp48
-rw-r--r--engines/wintermute/base/base_object.h2
-rw-r--r--engines/wintermute/base/base_quick_msg.h6
-rw-r--r--engines/wintermute/base/base_region.cpp10
-rw-r--r--engines/wintermute/base/base_region.h9
-rw-r--r--engines/wintermute/base/base_save_thumb_helper.cpp1
-rw-r--r--engines/wintermute/base/base_script_holder.cpp8
-rw-r--r--engines/wintermute/base/base_script_holder.h2
-rw-r--r--engines/wintermute/base/base_scriptable.cpp4
-rw-r--r--engines/wintermute/base/base_scriptable.h2
-rw-r--r--engines/wintermute/base/base_sprite.cpp29
-rw-r--r--engines/wintermute/base/base_sprite.h39
-rw-r--r--engines/wintermute/base/base_sub_frame.cpp26
-rw-r--r--engines/wintermute/base/base_sub_frame.h5
-rw-r--r--engines/wintermute/base/base_surface_storage.cpp1
-rw-r--r--engines/wintermute/base/base_transition_manager.cpp1
-rw-r--r--engines/wintermute/base/base_viewport.cpp1
-rw-r--r--engines/wintermute/base/file/base_disk_file.cpp4
-rw-r--r--engines/wintermute/base/file/base_package.cpp8
-rw-r--r--engines/wintermute/base/file/base_save_thumb_file.cpp1
-rw-r--r--engines/wintermute/base/font/base_font_bitmap.cpp1
-rw-r--r--engines/wintermute/base/font/base_font_storage.cpp1
-rw-r--r--engines/wintermute/base/font/base_font_truetype.cpp8
-rw-r--r--engines/wintermute/base/gfx/base_renderer.cpp10
-rw-r--r--engines/wintermute/base/gfx/osystem/base_render_osystem.cpp7
-rw-r--r--engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp1
-rw-r--r--engines/wintermute/base/particles/part_emitter.cpp73
-rw-r--r--engines/wintermute/base/particles/part_emitter.h2
-rw-r--r--engines/wintermute/base/saveload.cpp47
-rw-r--r--engines/wintermute/base/saveload.h8
-rw-r--r--engines/wintermute/base/scriptables/script_engine.cpp1
-rw-r--r--engines/wintermute/base/scriptables/script_ext_array.cpp8
-rw-r--r--engines/wintermute/base/scriptables/script_ext_array.h2
-rw-r--r--engines/wintermute/base/scriptables/script_ext_date.cpp6
-rw-r--r--engines/wintermute/base/scriptables/script_ext_date.h2
-rw-r--r--engines/wintermute/base/scriptables/script_ext_file.cpp15
-rw-r--r--engines/wintermute/base/scriptables/script_ext_file.h2
-rw-r--r--engines/wintermute/base/scriptables/script_ext_math.cpp6
-rw-r--r--engines/wintermute/base/scriptables/script_ext_math.h2
-rw-r--r--engines/wintermute/base/scriptables/script_ext_mem_buffer.cpp6
-rw-r--r--engines/wintermute/base/scriptables/script_ext_mem_buffer.h2
-rw-r--r--engines/wintermute/base/scriptables/script_ext_string.cpp8
-rw-r--r--engines/wintermute/base/scriptables/script_ext_string.h2
-rw-r--r--engines/wintermute/base/sound/base_sound_buffer.cpp2
-rw-r--r--engines/wintermute/base/sound/base_sound_manager.cpp1
-rw-r--r--engines/wintermute/graphics/transparent_surface.cpp6
-rw-r--r--engines/wintermute/persistent.h4
-rw-r--r--engines/wintermute/readme.txt155
-rw-r--r--engines/wintermute/system/sys_class_registry.cpp1
-rw-r--r--engines/wintermute/ui/ui_button.cpp13
-rw-r--r--engines/wintermute/ui/ui_button.h2
-rw-r--r--engines/wintermute/ui/ui_edit.cpp19
-rw-r--r--engines/wintermute/ui/ui_edit.h2
-rw-r--r--engines/wintermute/ui/ui_entity.cpp6
-rw-r--r--engines/wintermute/ui/ui_entity.h2
-rw-r--r--engines/wintermute/ui/ui_object.cpp25
-rw-r--r--engines/wintermute/ui/ui_object.h2
-rw-r--r--engines/wintermute/ui/ui_text.cpp8
-rw-r--r--engines/wintermute/ui/ui_text.h2
-rw-r--r--engines/wintermute/ui/ui_tiled_image.cpp5
-rw-r--r--engines/wintermute/ui/ui_window.cpp23
-rw-r--r--engines/wintermute/ui/ui_window.h2
-rw-r--r--engines/wintermute/utils/string_util.cpp12
-rw-r--r--engines/wintermute/video/video_theora_player.cpp33
-rw-r--r--engines/wintermute/wintermute.cpp1
562 files changed, 65875 insertions, 7256 deletions
diff --git a/engines/advancedDetector.h b/engines/advancedDetector.h
index 8c19d03691..3eec33abe5 100644
--- a/engines/advancedDetector.h
+++ b/engines/advancedDetector.h
@@ -194,7 +194,7 @@ protected:
/**
* A map containing all the extra game GUI options the engine supports.
- */
+ */
const ADExtraGuiOptionsMap * const _extraGuiOptions;
/**
@@ -212,7 +212,7 @@ protected:
*
* Used to override gameid.
* This is a recommended setting to prevent global gameid pollution.
- * With this option set, the gameid effectively turns into engineid.
+ * With this option set, the gameid effectively turns into engineid.
*
* FIXME: This field actually removes a feature (gameid) in order to
* address a more generic problem. We should find a better way to
diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp
index 45c00a76ac..98ffca22ed 100644
--- a/engines/agi/agi.cpp
+++ b/engines/agi/agi.cpp
@@ -219,7 +219,7 @@ void AgiEngine::processEvents() {
case Common::KEYCODE_F6:
key = 0x4000;
break;
- case Common::KEYCODE_F7:
+ case Common::KEYCODE_F7:
key = 0x4100;
break;
case Common::KEYCODE_F8:
diff --git a/engines/agi/detection_tables.h b/engines/agi/detection_tables.h
index ab0e9a1fe4..9d67b15adb 100644
--- a/engines/agi/detection_tables.h
+++ b/engines/agi/detection_tables.h
@@ -706,10 +706,10 @@ static const AGIGameDescription gameDescriptions[] = {
FANMADE("Go West, Young Hippie", "ff31484ea465441cb5f3a0f8e956b716"),
FANMADE("Good Man (demo v3.41)", "3facd8a8f856b7b6e0f6c3200274d88c"),
- GAME_LVFPNF("agi-fanmade", "Groza (russian) [AGDS sample]", "logdir", "421da3a18004122a966d64ab6bd86d2e", -1,
+ GAME_LVFPNF("agi-fanmade", "Groza (russian) [AGDS sample]", "logdir", "421da3a18004122a966d64ab6bd86d2e", -1,
Common::RU_RUS, 0x2440, GF_AGDS, GID_FANMADE, Common::kPlatformPC,GType_V2),
- GAME_LVFPNF("agi-fanmade", "Get Outta Space Quest", "logdir", "aaea5b4a348acb669d13b0e6f22d4dc9", -1,
+ GAME_LVFPNF("agi-fanmade", "Get Outta Space Quest", "logdir", "aaea5b4a348acb669d13b0e6f22d4dc9", -1,
Common::EN_ANY, 0x2440, GF_FANMADE, GID_GETOUTTASQ, Common::kPlatformPC,GType_V2),
FANMADE_F("Half-Death - Terror At White-Mesa", "b62c05d0ace878261392073f57ae788c", GF_AGIMOUSE),
diff --git a/engines/agi/loader_v1.cpp b/engines/agi/loader_v1.cpp
index c6a3e66705..189c98ee98 100644
--- a/engines/agi/loader_v1.cpp
+++ b/engines/agi/loader_v1.cpp
@@ -64,7 +64,7 @@ int AgiLoader_v1::detectGame() {
int AgiLoader_v1::loadDir_DDP(AgiDir *agid, int offset, int max) {
Common::File fp;
-
+
if (!fp.open(_filenameDisk0))
return errBadFileOpen;
@@ -73,13 +73,13 @@ int AgiLoader_v1::loadDir_DDP(AgiDir *agid, int offset, int max) {
agid[i].volume = 0xFF;
agid[i].offset = _EMPTY;
}
-
+
fp.seek(offset, SEEK_SET);
for (int i = 0; i <= max; i++) {
int b0 = fp.readByte();
int b1 = fp.readByte();
int b2 = fp.readByte();
-
+
if (b0 == 0xFF && b1 == 0xFF && b2 == 0xFF) {
agid[i].volume = 0xFF;
agid[i].offset = _EMPTY;
@@ -98,7 +98,7 @@ int AgiLoader_v1::loadDir_DDP(AgiDir *agid, int offset, int max) {
int AgiLoader_v1::loadDir_BC(AgiDir *agid, int offset, int max) {
Common::File fp;
-
+
if (!fp.open(_filenameDisk0))
return errBadFileOpen;
@@ -107,13 +107,13 @@ int AgiLoader_v1::loadDir_BC(AgiDir *agid, int offset, int max) {
agid[i].volume = 0xFF;
agid[i].offset = _EMPTY;
}
-
+
fp.seek(offset, SEEK_SET);
for (int i = 0; i <= max; i++) {
int b0 = fp.readByte();
int b1 = fp.readByte();
int b2 = fp.readByte();
-
+
if (b0 == 0xFF && b1 == 0xFF && b2 == 0xFF) {
agid[i].volume = 0xFF;
agid[i].offset = _EMPTY;
@@ -171,7 +171,7 @@ uint8 *AgiLoader_v1::loadVolRes(struct AgiDir *agid) {
if (offset == _EMPTY)
return NULL;
-
+
if (offset > IMAGE_SIZE) {
fp.open(_filenameDisk1);
offset -= IMAGE_SIZE;
@@ -191,7 +191,7 @@ uint8 *AgiLoader_v1::loadVolRes(struct AgiDir *agid) {
agid->len = fp.readUint16LE();
data = (uint8 *)calloc(1, agid->len + 32);
fp.read(data, agid->len);
-
+
fp.close();
return data;
diff --git a/engines/agi/menu.cpp b/engines/agi/menu.cpp
index cac1701596..d23a5a2e27 100644
--- a/engines/agi/menu.cpp
+++ b/engines/agi/menu.cpp
@@ -289,7 +289,7 @@ bool Menu::keyhandler(int key) {
_vm->_game.clockEnabled = false;
drawMenuBar();
}
-
+
// Mouse handling
if (_vm->_mouse.button) {
int hmenu, vmenu;
diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index 7e04328a67..5334407eb8 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -1146,7 +1146,7 @@ void cmdFollowEgo(AgiGame *state, uint8 *p) {
vt.parm1 = p1 > vt.stepSize ? p1 : vt.stepSize;
vt.parm2 = p2;
vt.parm3 = 0xff;
-
+
if (getVersion() < 0x2000) {
_v[p2] = 0;
vt.flags |= fUpdate | fAnimated;
@@ -1270,7 +1270,7 @@ void cmdVersion(AgiGame *state, uint8 *p) {
// no Sierra as it wraps textbox
Common::String verMsg = TITLE " v%s";
-
+
int ver = getVersion();
int maj = (ver >> 12) & 0xf;
int min = ver & 0xfff;
@@ -1839,7 +1839,7 @@ int AgiEngine::runLogic(int n) {
// ip = 2;
// warning("running logic %d\n", n);
// }
-
+
if (_game.exitAllLogics)
break;
}
diff --git a/engines/agi/op_test.cpp b/engines/agi/op_test.cpp
index a44c68e0fc..4d5e6fffe1 100644
--- a/engines/agi/op_test.cpp
+++ b/engines/agi/op_test.cpp
@@ -403,7 +403,7 @@ int AgiEngine::testIfCode(int lognum) {
case 0xFF:
endTest = true;
continue;
-
+
default:
// Evaluate the command and skip the rest of the instruction
_agiCondCommands[op](state, p);
diff --git a/engines/agi/opcodes.cpp b/engines/agi/opcodes.cpp
index 29fb860635..7a427bd94f 100644
--- a/engines/agi/opcodes.cpp
+++ b/engines/agi/opcodes.cpp
@@ -130,7 +130,7 @@ AgiInstruction insV1[] = {
{ "...", "", &cmdUnknown }, // 4E # show.obj
{ "load.logics", "n", &cmdLoadLogic }, // 4F # load.global.logics
{ "display", "nnns", &cmdDisplay }, // 50 TODO: 4 vs 3 args
- { "prevent.input???", "", &cmdUnknown }, // 51
+ { "prevent.input???", "", &cmdUnknown }, // 51
{ "...", "", &cmdUnknown }, // 52 # nop
{ "...", "n", &cmdUnknown }, // 53 # text.screen
{ "...", "", &cmdUnknown }, // 54 ???
diff --git a/engines/agi/saveload.cpp b/engines/agi/saveload.cpp
index 3e63da756d..d451a799a0 100644
--- a/engines/agi/saveload.cpp
+++ b/engines/agi/saveload.cpp
@@ -821,7 +821,7 @@ int AgiEngine::scummVMSaveLoadDialog(bool isSave) {
if (slot < 0)
return true;
-
+
if (isSave)
return doSave(slot, desc);
else
diff --git a/engines/agi/sound_pcjr.cpp b/engines/agi/sound_pcjr.cpp
index d21baa450f..5bffca5765 100644
--- a/engines/agi/sound_pcjr.cpp
+++ b/engines/agi/sound_pcjr.cpp
@@ -234,7 +234,7 @@ int SoundGenPCJr::getNextNote(int ch)
// if tone isn't touched.. it should be inited so it just plays silence
// return 0 if it's passing more data
// return -1 if it's passing nothing (end of data)
-int SoundGenPCJr::getNextNote_v2(int ch) {
+int SoundGenPCJr::getNextNote_v2(int ch) {
ToneChan *tpcm;
SndGenChan *chan;
const byte *data;
@@ -308,7 +308,7 @@ int SoundGenPCJr::getNextNote_v1(int ch) {
_channel[ch].attenuationCopy = 0x0F;
return -1;
}
-
+
// In the V1 player the default duration for a row is 3 ticks
if (duration > 0) {
duration--;
diff --git a/engines/agi/text.cpp b/engines/agi/text.cpp
index 1886a74ab1..4877be2647 100644
--- a/engines/agi/text.cpp
+++ b/engines/agi/text.cpp
@@ -64,7 +64,7 @@ void AgiEngine::printText2(int l, const char *msg, int foff, int xoff, int yoff,
// Note: there were extra checks for *m being a cursor character
// here (1, 2 or 3), which have been removed, as the cursor
- // character is no longer printed via this function.
+ // character is no longer printed via this function.
if (*m >= 0x20) {
int ypos = (y1 * CHAR_LINES) + yoff;
@@ -73,7 +73,7 @@ void AgiEngine::printText2(int l, const char *msg, int foff, int xoff, int yoff,
if (xpos >= GFX_WIDTH)
continue;
-
+
_gfx->putTextCharacter(l, xpos, ypos, *m, fg, bg, checkerboard);
if (x1 > maxx)
diff --git a/engines/agi/words.cpp b/engines/agi/words.cpp
index 4400112247..9c5b3d349a 100644
--- a/engines/agi/words.cpp
+++ b/engines/agi/words.cpp
@@ -41,7 +41,7 @@ int AgiEngine::loadWords_v1(Common::File &f) {
int k;
debug(0, "Loading dictionary");
-
+
// Loop through alphabet, as words in the dictionary file are sorted by
// first character
f.seek(f.pos() + 26 * 2, SEEK_SET);
@@ -131,7 +131,7 @@ int AgiEngine::findWord(const char *word, int *flen) {
*flen = 0;
Common::Array<AgiWord *> &a = _game.words[c];
-
+
for (int i = 0; i < (int)a.size(); i++) {
int wlen = strlen(a[i]->word);
// Keep looking till we find the word itself, or the whole phrase.
diff --git a/engines/agos/midiparser_s1d.cpp b/engines/agos/midiparser_s1d.cpp
index 9ca87436fc..bef7199a98 100644
--- a/engines/agos/midiparser_s1d.cpp
+++ b/engines/agos/midiparser_s1d.cpp
@@ -35,7 +35,7 @@ namespace AGOS {
class MidiParser_S1D : public MidiParser {
private:
byte *_data;
- bool _no_delta;
+ bool _noDelta;
struct Loop {
uint16 timer;
@@ -49,7 +49,7 @@ protected:
void resetTracking();
public:
- MidiParser_S1D() : _data(0), _no_delta(false) {}
+ MidiParser_S1D() : _data(0), _noDelta(false) {}
bool loadMusic(byte *data, uint32 size);
};
@@ -75,14 +75,14 @@ void MidiParser_S1D::chainEvent(EventInfo &info) {
}
void MidiParser_S1D::parseNextEvent(EventInfo &info) {
- info.start = _position._play_pos;
+ info.start = _position._playPos;
info.length = 0;
- info.delta = _no_delta ? 0 : readVLQ2(_position._play_pos);
- _no_delta = false;
+ info.delta = _noDelta ? 0 : readVLQ2(_position._playPos);
+ _noDelta = false;
- info.event = *_position._play_pos++;
+ info.event = *_position._playPos++;
if (!(info.event & 0x80)) {
- _no_delta = true;
+ _noDelta = true;
info.event |= 0x80;
}
@@ -94,34 +94,43 @@ void MidiParser_S1D::parseNextEvent(EventInfo &info) {
} else {
switch (info.command()) {
case 0x8: // note off
- info.basic.param1 = *_position._play_pos++;
+ info.basic.param1 = *_position._playPos++;
info.basic.param2 = 0;
break;
case 0x9: // note on
- info.basic.param1 = *_position._play_pos++;
- info.basic.param2 = *_position._play_pos++;
+ info.basic.param1 = *_position._playPos++;
+ info.basic.param2 = *_position._playPos++;
+ // Rewrite note on events with velocity 0 as note off events.
+ // This is the actual meaning of this, but theoretically this
+ // should not need to be rewritten, since all MIDI devices should
+ // interpret it like that. On the other hand all our MidiParser
+ // implementations do it and there seems to be code in MidiParser
+ // which relies on this for tracking active notes.
+ if (info.basic.param2 == 0) {
+ info.event = info.channel() | 0x80;
+ }
break;
case 0xA: { // loop control
// In case the stop mode(?) is set to 0x80 this will stop the
// track over here.
- const int16 loopIterations = int8(*_position._play_pos++);
+ const int16 loopIterations = int8(*_position._playPos++);
if (!loopIterations) {
- _loops[info.channel()].start = _position._play_pos;
+ _loops[info.channel()].start = _position._playPos;
} else {
if (!_loops[info.channel()].timer) {
if (_loops[info.channel()].start) {
_loops[info.channel()].timer = uint16(loopIterations);
- _loops[info.channel()].end = _position._play_pos;
+ _loops[info.channel()].end = _position._playPos;
// Go to the start of the loop
- _position._play_pos = _loops[info.channel()].start;
+ _position._playPos = _loops[info.channel()].start;
}
} else {
if (_loops[info.channel()].timer)
- _position._play_pos = _loops[info.channel()].start;
+ _position._playPos = _loops[info.channel()].start;
--_loops[info.channel()].timer;
}
}
@@ -141,13 +150,13 @@ void MidiParser_S1D::parseNextEvent(EventInfo &info) {
break;
case 0xC: // program change
- info.basic.param1 = *_position._play_pos++;
+ info.basic.param1 = *_position._playPos++;
info.basic.param2 = 0;
break;
case 0xD: // jump to loop end
if (_loops[info.channel()].end)
- _position._play_pos = _loops[info.channel()].end;
+ _position._playPos = _loops[info.channel()].end;
// We need to read the next midi event here. Since we can not
// safely pass this event to the MIDI event processing.
@@ -178,7 +187,7 @@ bool MidiParser_S1D::loadMusic(byte *data, uint32 size) {
pos += 1;
// And now we're at the actual data. Only one track.
- _num_tracks = 1;
+ _numTracks = 1;
_data = pos;
_tracks[0] = pos;
@@ -194,7 +203,7 @@ bool MidiParser_S1D::loadMusic(byte *data, uint32 size) {
void MidiParser_S1D::resetTracking() {
MidiParser::resetTracking();
// The first event never contains any delta.
- _no_delta = true;
+ _noDelta = true;
memset(_loops, 0, sizeof(_loops));
}
diff --git a/engines/agos/saveload.cpp b/engines/agos/saveload.cpp
index c6bca1a6e6..e13fa214d1 100644
--- a/engines/agos/saveload.cpp
+++ b/engines/agos/saveload.cpp
@@ -142,7 +142,7 @@ void AGOSEngine_Feeble::quickLoadOrSave() {
}
#endif
-// The function uses segments of code from the original game scripts
+// 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,
@@ -1424,7 +1424,7 @@ bool AGOSEngine_Elvira2::loadGame(const char *filename, bool restartMode) {
// The floppy disk versions of Simon the Sorcerer 2 block changing
// to scrolling rooms, if the copy protection fails. But the copy
// protection flags are never set in the CD version.
- // Setting this copy protection flag, allows saved games to be shared
+ // Setting this copy protection flag, allows saved games to be shared
// between all versions of Simon the Sorcerer 2.
if (getGameType() == GType_SIMON2) {
setBitFlag(135, 1);
diff --git a/engines/agos/sound.cpp b/engines/agos/sound.cpp
index 85c449eafc..bec41bbbd3 100644
--- a/engines/agos/sound.cpp
+++ b/engines/agos/sound.cpp
@@ -297,7 +297,7 @@ Audio::AudioStream *RawSound::makeAudioStream(uint sound) {
warning("RawSound::makeAudioStream: Could not open file \"%s\"", _filename.c_str());
return NULL;
}
-
+
file->seek(_offsets[sound], SEEK_SET);
uint size = file->readUint32BE();
return Audio::makeRawStream(new Common::SeekableSubReadStream(file, _offsets[sound] + 4, _offsets[sound] + 4 + size, DisposeAfterUse::YES), 22050, _flags, DisposeAfterUse::YES);
diff --git a/engines/cge/bitmap.cpp b/engines/cge/bitmap.cpp
index 4f85957b3d..7089c8e0d1 100644
--- a/engines/cge/bitmap.cpp
+++ b/engines/cge/bitmap.cpp
@@ -94,7 +94,7 @@ Bitmap::Bitmap(CGEEngine *vm, uint16 w, uint16 h, uint8 fill)
// Replicate across the entire table
for (HideDesc *hdP = b + 1; hdP < (b + _h); hdP++)
*hdP = *b;
-
+
b->_skip = 0; // fix the first entry
_v = v;
_b = b;
@@ -357,7 +357,7 @@ bool Bitmap::loadVBM(EncryptedStream *f) {
// Read in the palette
byte palData[kPalSize];
f->read(palData, kPalSize);
-
+
const byte *srcP = palData;
for (int idx = 0; idx < kPalCount; idx++, srcP += 3) {
_vm->_bitmapPalette[idx]._r = *srcP;
diff --git a/engines/cge/cge_main.cpp b/engines/cge/cge_main.cpp
index ecbfba2502..f4f1cd3e0b 100644
--- a/engines/cge/cge_main.cpp
+++ b/engines/cge/cge_main.cpp
@@ -280,7 +280,7 @@ Common::Error CGEEngine::loadGameState(int slot) {
sceneDown();
_hero->park();
resetGame();
-
+
// If music is playing, kill it.
if (_music)
_midiPlayer->killMidi();
@@ -508,7 +508,7 @@ void CGEEngine::loadMapping() {
if (!cf.err()) {
// Move to the data for the given room
cf.seek((_now - 1) * kMapArrSize);
-
+
// Read in the data
for (int z = 0; z < kMapZCnt; ++z) {
cf.read(&_clusterMap[z][0], kMapXCnt);
@@ -772,7 +772,7 @@ void System::touch(uint16 mask, int x, int y, Common::KeyCode keyCode) {
if (mask & kEventKeyb) {
if (keyCode == Common::KEYCODE_ESCAPE) {
- // The original was calling keyClick()
+ // The original was calling keyClick()
// The sound is uselessly annoying and noisy, so it has been removed
_vm->killText();
if (_vm->_startupMode == 1) {
@@ -1044,7 +1044,7 @@ void CGEEngine::loadSprite(const char *fname, int ref, int scene, int col = 0, i
uint16 len;
for (line = sprf.readLine(); !sprf.eos(); line = sprf.readLine()) {
- len = line.size();
+ len = line.size();
lcnt++;
strcpy(tmpStr, line.c_str());
if (len == 0 || *tmpStr == '.')
diff --git a/engines/cge/detection.cpp b/engines/cge/detection.cpp
index 2e04b82026..3d6c24d68b 100644
--- a/engines/cge/detection.cpp
+++ b/engines/cge/detection.cpp
@@ -198,7 +198,7 @@ SaveStateList CGEMetaEngine::listSaves(const char *target) const {
SaveStateDescriptor CGEMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
Common::String fileName = Common::String::format("%s.%03d", target, slot);
Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(fileName);
-
+
if (f) {
CGE::SavegameHeader header;
@@ -229,7 +229,7 @@ SaveStateDescriptor CGEMetaEngine::querySaveMetaInfos(const char *target, int sl
return desc;
}
}
-
+
return SaveStateDescriptor();
}
diff --git a/engines/cge/events.h b/engines/cge/events.h
index 522aa67905..ab8d87212d 100644
--- a/engines/cge/events.h
+++ b/engines/cge/events.h
@@ -105,7 +105,7 @@ private:
void handleEvents();
public:
EventManager(CGEEngine *vm);
- void poll();
+ void poll();
void clearEvent(Sprite *spr);
CGEEvent &getNextEvent();
diff --git a/engines/cge/fileio.cpp b/engines/cge/fileio.cpp
index f23105d823..609d5e86aa 100644
--- a/engines/cge/fileio.cpp
+++ b/engines/cge/fileio.cpp
@@ -98,7 +98,7 @@ uint16 ResourceManager::XCrypt(void *buf, uint16 length) {
for (uint16 i = 0; i < length; i++)
*b++ ^= kCryptSeed;
-
+
return kCryptSeed;
}
diff --git a/engines/cge/text.cpp b/engines/cge/text.cpp
index fd4120d49d..a8ce8777c5 100644
--- a/engines/cge/text.cpp
+++ b/engines/cge/text.cpp
@@ -63,7 +63,7 @@ int16 Text::count() {
Common::String line;
char tmpStr[kLineMax + 1];
-
+
int counter = 0;
for (line = tf.readLine(); !tf.eos(); line = tf.readLine()) {
diff --git a/engines/cine/anim.cpp b/engines/cine/anim.cpp
index 60168831a1..075a59cfb6 100644
--- a/engines/cine/anim.cpp
+++ b/engines/cine/anim.cpp
@@ -202,13 +202,13 @@ AnimData::AnimData(const AnimData &src) : _width(src._width),
if (src._data) {
_data = new byte[_size];
assert(_data);
- memcpy(_data, src._data, _size*sizeof(byte));
+ memcpy(_data, src._data, _size * sizeof(byte));
}
if (src._mask) {
_mask = new byte[_size];
assert(_mask);
- memcpy(_mask, src._mask, _size*sizeof(byte));
+ memcpy(_mask, src._mask, _size * sizeof(byte));
}
memset(_name, 0, sizeof(_name));
@@ -272,8 +272,7 @@ byte AnimData::getColor(int x, int y) {
* @param transparent Transparent color (for ANIM_MASKSPRITE)
*/
void AnimData::load(byte *d, int type, uint16 w, uint16 h, int16 file,
- int16 frame, const char *n, byte transparent) {
-
+ int16 frame, const char *n, byte transparent) {
assert(d);
if (_data) {
@@ -299,7 +298,7 @@ void AnimData::load(byte *d, int type, uint16 w, uint16 h, int16 file,
_size = w * h;
_data = new byte[_size];
assert(_data);
- memcpy(_data, d, _size*sizeof(byte));
+ memcpy(_data, d, _size * sizeof(byte));
break;
case ANIM_MASK:
@@ -536,7 +535,7 @@ int loadSpl(const char *resourceName, int16 idx) {
entry = idx < 0 ? emptyAnimSpace() : idx;
assert(entry >= 0);
- g_cine->_animDataTable[entry].load(dataPtr, ANIM_RAW, g_cine->_partBuffer[foundFileIdx].unpackedSize, 1, foundFileIdx, 0, currentPartName);
+ g_cine->_animDataTable[entry].load(dataPtr + 0x16, ANIM_RAW, g_cine->_partBuffer[foundFileIdx].unpackedSize - 0x16, 1, foundFileIdx, 0, currentPartName);
free(dataPtr);
return entry + 1;
@@ -546,9 +545,10 @@ int loadSpl(const char *resourceName, int16 idx) {
* Load 1bpp mask
* @param resourceName Mask 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 mask (-1 if error)
*/
-int loadMsk(const char *resourceName, int16 idx) {
+int loadMsk(const char *resourceName, int16 idx, int16 frameIndex) {
int16 foundFileIdx = findFileInBundle(resourceName);
if (foundFileIdx < 0) {
return -1;
@@ -563,9 +563,18 @@ int loadMsk(const char *resourceName, int16 idx) {
loadAnimHeader(animHeader, readS);
ptr = dataPtr + 0x16;
+ int16 startFrame = 0;
+ int16 endFrame = animHeader.numFrames;
+
+ if (frameIndex >= 0) {
+ startFrame = frameIndex;
+ endFrame = frameIndex + 1;
+ ptr += frameIndex * animHeader.frameWidth * animHeader.frameHeight;
+ }
+
entry = idx < 0 ? emptyAnimSpace() : idx;
assert(entry >= 0);
- for (int16 i = 0; i < animHeader.numFrames; i++, entry++) {
+ for (int16 i = startFrame; i < endFrame; i++, entry++) {
g_cine->_animDataTable[entry].load(ptr, ANIM_MASK, animHeader.frameWidth, animHeader.frameHeight, foundFileIdx, i, currentPartName);
ptr += animHeader.frameWidth * animHeader.frameHeight;
}
@@ -578,9 +587,10 @@ int loadMsk(const char *resourceName, int16 idx) {
* Load animation
* @param resourceName Animation 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 animation (-1 if error)
*/
-int loadAni(const char *resourceName, int16 idx) {
+int loadAni(const char *resourceName, int16 idx, int16 frameIndex) {
int16 foundFileIdx = findFileInBundle(resourceName);
if (foundFileIdx < 0) {
return -1;
@@ -596,6 +606,15 @@ int loadAni(const char *resourceName, int16 idx) {
loadAnimHeader(animHeader, readS);
ptr = dataPtr + 0x16;
+ int16 startFrame = 0;
+ int16 endFrame = animHeader.numFrames;
+
+ if (frameIndex >= 0) {
+ startFrame = frameIndex;
+ endFrame = frameIndex + 1;
+ ptr += frameIndex * animHeader.frameWidth * animHeader.frameHeight;
+ }
+
transparentColor = getAnimTransparentColor(resourceName);
// TODO: Merge this special case hack into getAnimTransparentColor somehow.
@@ -609,7 +628,7 @@ int loadAni(const char *resourceName, int16 idx) {
entry = idx < 0 ? emptyAnimSpace() : idx;
assert(entry >= 0);
- for (int16 i = 0; i < animHeader.numFrames; i++, entry++) {
+ for (int16 i = startFrame; i < endFrame; i++, entry++) {
// special case transparency handling
if (!strcmp(resourceName, "L2202.ANI")) {
transparentColor = i < 2 ? 0 : 7;
@@ -669,13 +688,13 @@ void convert8BBP2(byte *dest, byte *source, int16 width, int16 height) {
*(source + k) <<= 1;
if (k > 0 + m)
color <<= 1;
- } // end k
+ } // end k
*(dest++) = color;
- } // end i
- } // end m
+ } // end i
+ } // end m
source += 0x10;
- } // end j
+ } // end j
}
/**
@@ -685,7 +704,7 @@ void convert8BBP2(byte *dest, byte *source, int16 width, int16 height) {
* @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, int16 frameIndex =-1 ) {
+int loadSet(const char *resourceName, int16 idx, int16 frameIndex = -1) {
AnimHeader2Struct header2;
uint16 numSpriteInAnim;
int16 foundFileIdx = findFileInBundle(resourceName);
@@ -712,10 +731,9 @@ int loadSet(const char *resourceName, int16 idx, int16 frameIndex =-1 ) {
int16 startFrame = 0;
int16 endFrame = numSpriteInAnim;
- if(frameIndex>=0)
- {
+ if (frameIndex >= 0) {
startFrame = frameIndex;
- endFrame = frameIndex+1;
+ endFrame = frameIndex + 1;
ptr += 0x10 * frameIndex;
}
@@ -766,7 +784,7 @@ int loadSeq(const char *resourceName, int16 idx) {
byte *dataPtr = readBundleFile(foundFileIdx);
int entry = idx < 0 ? emptyAnimSpace() : idx;
- g_cine->_animDataTable[entry].load(dataPtr+0x16, ANIM_RAW, g_cine->_partBuffer[foundFileIdx].unpackedSize-0x16, 1, foundFileIdx, 0, currentPartName);
+ g_cine->_animDataTable[entry].load(dataPtr + 0x16, ANIM_RAW, g_cine->_partBuffer[foundFileIdx].unpackedSize - 0x16, 1, foundFileIdx, 0, currentPartName);
free(dataPtr);
return entry + 1;
}
@@ -783,11 +801,11 @@ int loadResource(const char *resourceName, int16 idx, int16 frameIndex) {
if (strstr(resourceName, ".SPL")) {
result = loadSpl(resourceName, idx);
} else if (strstr(resourceName, ".MSK")) {
- result = loadMsk(resourceName, idx);
+ result = loadMsk(resourceName, idx, frameIndex);
} else if (strstr(resourceName, ".ANI")) {
- result = loadAni(resourceName, idx);
+ result = loadAni(resourceName, idx, frameIndex);
} else if (strstr(resourceName, ".ANM")) {
- result = loadAni(resourceName, idx);
+ result = loadAni(resourceName, idx, frameIndex);
} else if (strstr(resourceName, ".SET")) {
result = loadSet(resourceName, idx, frameIndex);
} else if (strstr(resourceName, ".SEQ")) {
diff --git a/engines/cine/cine.cpp b/engines/cine/cine.cpp
index bbe2cd4896..aa7221f733 100644
--- a/engines/cine/cine.cpp
+++ b/engines/cine/cine.cpp
@@ -189,7 +189,18 @@ void CineEngine::initialize() {
g_cine->_messageTable.clear();
resetObjectTable();
- disableSystemMenu = 1;
+ if (getGameType() == Cine::GType_OS) {
+ disableSystemMenu = 1;
+ } else {
+ // WORKAROUND: We do not save this variable in FW's savegames.
+ // Initializing this to 1, like we do it in the OS case, will
+ // cause the menu disabled when loading from the launcher or
+ // command line.
+ // A proper fix here would be to save this variable in FW's saves.
+ // Since it seems these are unversioned so far, there would be need
+ // to properly add versioning to them first.
+ disableSystemMenu = 0;
+ }
var8 = 0;
diff --git a/engines/cine/cine.h b/engines/cine/cine.h
index 55376dce29..47edf51c30 100644
--- a/engines/cine/cine.h
+++ b/engines/cine/cine.h
@@ -159,7 +159,7 @@ private:
bool _preLoad;
int _timerDelayMultiplier;
- public:
+public:
// TODO: These are pseudo-global vars
// They better belong to appropriate classes
Common::Array<AnimData> _animDataTable;
diff --git a/engines/cine/console.cpp b/engines/cine/console.cpp
index 0a24b2408a..4af28592e7 100644
--- a/engines/cine/console.cpp
+++ b/engines/cine/console.cpp
@@ -28,7 +28,7 @@ namespace Cine {
bool labyrinthCheat;
CineConsole::CineConsole(CineEngine *vm) : GUI::Debugger(), _vm(vm) {
- DCmd_Register("labyrinthCheat", WRAP_METHOD(CineConsole, Cmd_LabyrinthCheat));
+ DCmd_Register("labyrinthCheat", WRAP_METHOD(CineConsole, Cmd_LabyrinthCheat));
labyrinthCheat = false;
}
diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp
index 7a988227f6..636c0cf8d9 100644
--- a/engines/cine/gfx.cpp
+++ b/engines/cine/gfx.cpp
@@ -113,7 +113,7 @@ FWRenderer::FWRenderer() : _background(NULL), _backupPal(), _cmd(""),
assert(_backBuffer);
memset(_backBuffer, 0, _screenSize);
- memset(_bgName, 0, sizeof (_bgName));
+ memset(_bgName, 0, sizeof(_bgName));
}
@@ -249,7 +249,7 @@ void FWRenderer::drawCommand() {
unsigned int i;
int x = 10, y = _cmdY;
- if(disableSystemMenu == 0) {
+ if (disableSystemMenu == 0) {
drawPlainBox(x, y, 301, 11, 0);
drawBorder(x - 1, y - 1, 302, 12, 2);
@@ -307,7 +307,7 @@ void FWRenderer::drawMessage(const char *str, int x, int y, int width, int color
i++;
line = fitLine(str + i, tw, words, cw);
- if ( str[i + line] != '\0' && str[i + line] != 0x7C && words) {
+ if (str[i + line] != '\0' && str[i + line] != 0x7C && words) {
space = (tw - cw) / words;
extraSpace = (tw - cw) % words;
} else {
@@ -471,6 +471,41 @@ int FWRenderer::drawChar(char character, int x, int y) {
return x;
}
+/**
+ * Clears the character glyph to black
+ * This function is called "undrawChar", because the original only applies
+ * this drawing after the original glyph has been drawn.
+ * Possible TODO: Find a better name.
+ * @param character Character to undraw
+ * @param x Character coordinate
+ * @param y Character coordinate
+ */
+int FWRenderer::undrawChar(char character, int x, int y) {
+ int width, idx;
+
+ if (character == ' ') {
+ x += 5;
+ } else if ((width = g_cine->_textHandler.fontParamTable[(unsigned char)character].characterWidth)) {
+ idx = g_cine->_textHandler.fontParamTable[(unsigned char)character].characterIdx;
+ const byte *sprite = g_cine->_textHandler.textTable[idx][FONT_DATA];
+ for (uint i = 0; i < FONT_HEIGHT; ++i) {
+ byte *dst = _backBuffer + (y + i) * 320 + x;
+ for (uint j = 0; j < FONT_WIDTH; ++j, ++dst) {
+ // The original does this based on whether bit 1 of the pixel
+ // is set. Since that's the only bit ever set in (FW) this
+ // check should be fine.
+ // TODO: Check how Operation Stealth Amiga works
+ if (*sprite++) {
+ *dst = 0;
+ }
+ }
+ }
+ x += width + 1;
+ }
+
+ return x;
+}
+
int FWRenderer::getStringWidth(const char *str) {
const char *p = str;
int width = 0;
@@ -969,20 +1004,29 @@ void SelectionMenu::drawMenu(FWRenderer &r, bool top) {
charX = x + 4;
if (i == _selection) {
+ int color;
+
if (isAmiga) {
- // The original Amiga version is using a different highlight color here,
- // but with our current code it is not possible to change the text color,
- // thus we can not use the Amiga's color, since otherwise the text
- // wouldn't be visible anymore.
- r.drawPlainBox(charX, lineY, _width - 8, FONT_HEIGHT, top ? r._messageBg/*2*/ : 18);
+ if (top) {
+ color = 2;
+ } else {
+ color = 18;
+ }
} else {
- r.drawPlainBox(charX, lineY, _width - 8, 9, 0);
+ color = 0;
}
+
+ r.drawPlainBox(x + 2, lineY - 1, _width - 3, 9, color);
}
const int size = _elements[i].size();
- for (int j = 0; j < size; ++j)
- charX = r.drawChar(_elements[i][j], charX, lineY);
+ for (int j = 0; j < size; ++j) {
+ if (isAmiga && i == _selection) {
+ charX = r.undrawChar(_elements[i][j], charX, lineY);
+ } else {
+ charX = r.drawChar(_elements[i][j], charX, lineY);
+ }
+ }
}
}
@@ -1244,6 +1288,7 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) {
sprite = &g_cine->_animDataTable[g_cine->_objectTable[it->objIdx].frame];
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()) {
@@ -1300,7 +1345,7 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) {
height = obj->costume;
drawPlainBox(obj->x, obj->y, width, height, color);
debug(5, "renderOverlay: type=%d, x=%d, y=%d, width=%d, height=%d, color=%d",
- it->type, obj->x, obj->y, width, height, color);
+ it->type, obj->x, obj->y, width, height, color);
break;
// something else
@@ -1424,7 +1469,7 @@ void OSRenderer::selectBg(unsigned int idx) {
if (_bgTable[idx].bg) {
assert(_bgTable[idx].pal.isValid() && !(_bgTable[idx].pal.empty()));
- _currentBg = idx;
+ _currentBg = idx;
} else
warning("OSRenderer::selectBg(%d) - attempt to select null background", idx);
reloadPalette();
@@ -1750,23 +1795,23 @@ void OSRenderer::drawSprite(overlay *overlayPtr, const byte *spritePtr, int16 wi
// 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) {
+ for (it = g_cine->_overlayList.begin(); it != g_cine->_overlayList.end(); ++it) {
+ if (&(*it) == overlayPtr) {
break;
}
}
- while(it != g_cine->_overlayList.end()) {
+ 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];
+ 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];
+ byte spriteColor = spritePtr[width * i + j];
pMask[width * i + j] = spriteColor;
}
}
@@ -1777,7 +1822,7 @@ void OSRenderer::drawSprite(overlay *overlayPtr, const byte *spritePtr, int16 wi
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 (inMaskX >= 0 && inMaskX < width) {
if (inMaskY >= 0 && inMaskY < height) {
if (sprite->_bpp == 1) {
if (!sprite->getColor(i, j)) {
@@ -1793,7 +1838,7 @@ void OSRenderer::drawSprite(overlay *overlayPtr, const byte *spritePtr, int16 wi
}
// now, draw with the mask we created
- if(pMask) {
+ if (pMask) {
spritePtr = pMask;
}
@@ -1808,7 +1853,7 @@ void OSRenderer::drawSprite(overlay *overlayPtr, const byte *spritePtr, int16 wi
destPtr += i * 320;
for (int j = 0; j < width; j++) {
- byte color= *(spritePtr++);
+ byte color = *(spritePtr++);
if ((transparentColor != color) && x + j >= 0 && x + j < 320 && i + y >= 0 && i + y < 200) {
*(destPtr++) = color;
} else {
diff --git a/engines/cine/gfx.h b/engines/cine/gfx.h
index 3434cf9fc2..8b8843fd72 100644
--- a/engines/cine/gfx.h
+++ b/engines/cine/gfx.h
@@ -152,6 +152,7 @@ protected:
void drawBorder(int x, int y, int width, int height, byte color);
void drawDoubleBorder(int x, int y, int width, int height, byte color);
virtual int drawChar(char character, int x, int y);
+ virtual int undrawChar(char character, int x, int y);
void drawLine(int x, int y, int width, int height, byte color);
void remaskSprite(byte *mask, Common::List<overlay>::iterator it);
virtual void drawBackground();
@@ -287,7 +288,7 @@ byte gfxGetColor(int16 x, int16 y, const byte *ptr, int16 width);
void gfxResetRawPage(byte *pageRaw);
void gfxConvertSpriteToRaw(byte *dst, const byte *src, uint16 w, uint16 h);
-void gfxCopyRawPage(byte *source, byte * dest);
+void gfxCopyRawPage(byte *source, byte *dest);
void gfxFlipRawPage(byte *frontBuffer);
void drawSpriteRaw(const byte *spritePtr, const byte *maskPtr, int16 width, int16 height, byte *page, int16 x, int16 y);
void gfxDrawPlainBoxRaw(int16 x1, int16 y1, int16 x2, int16 y2, byte color, byte *page);
diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp
index f13f38a45e..c822f1cabd 100644
--- a/engines/cine/main_loop.cpp
+++ b/engines/cine/main_loop.cpp
@@ -180,19 +180,19 @@ static void processEvent(Common::Event &event) {
case Common::KEYCODE_F11:
renderer->showCollisionPage(false);
break;
- case Common::KEYCODE_KP5: // Emulated left mouse button click
- case Common::KEYCODE_LEFT: // Left
- case Common::KEYCODE_KP4: // Left
+ case Common::KEYCODE_KP5: // Emulated left mouse button click
+ case Common::KEYCODE_LEFT: // Left
+ case Common::KEYCODE_KP4: // Left
case Common::KEYCODE_RIGHT: // Right
- case Common::KEYCODE_KP6: // Right
- case Common::KEYCODE_UP: // Up
- case Common::KEYCODE_KP8: // Up
- case Common::KEYCODE_DOWN: // Down
- case Common::KEYCODE_KP2: // Down
- case Common::KEYCODE_KP9: // Up & Right
- case Common::KEYCODE_KP7: // Up & Left
- case Common::KEYCODE_KP1: // Down & Left
- case Common::KEYCODE_KP3: // Down & Right
+ case Common::KEYCODE_KP6: // Right
+ case Common::KEYCODE_UP: // Up
+ case Common::KEYCODE_KP8: // Up
+ case Common::KEYCODE_DOWN: // Down
+ case Common::KEYCODE_KP2: // Down
+ case Common::KEYCODE_KP9: // Up & Right
+ case Common::KEYCODE_KP7: // Up & Left
+ case Common::KEYCODE_KP1: // Down & Left
+ case Common::KEYCODE_KP3: // Down & Right
// Stop ego movement made with keyboard when releasing a known key
moveUsingKeyboard(0, 0);
break;
@@ -217,7 +217,6 @@ void manageEvents() {
g_system->delayMillis(20);
} while (g_system->getMillis() < nextFrame);
- g_sound->update();
mouseData.left = mouseLeft;
mouseData.right = mouseRight;
}
@@ -434,9 +433,9 @@ void CineEngine::mainLoop(int bootScriptIdx) {
hideMouse();
g_sound->stopMusic();
- // if (g_cine->getGameType() == Cine::GType_OS) {
+ //if (g_cine->getGameType() == Cine::GType_OS) {
// freeUnkList();
- // }
+ //}
closePart();
}
diff --git a/engines/cine/object.cpp b/engines/cine/object.cpp
index afd95c04b0..a75828abb1 100644
--- a/engines/cine/object.cpp
+++ b/engines/cine/object.cpp
@@ -59,7 +59,7 @@ void loadObject(char *pObjectName) {
assert(numEntry <= NUM_MAX_OBJECT);
for (i = 0; i < numEntry; i++) {
- if (g_cine->_objectTable[i].costume != -2 && g_cine->_objectTable[i].costume != -3) { // flag is keep ?
+ if (g_cine->_objectTable[i].costume != -2 && g_cine->_objectTable[i].costume != -3) { // flag is keep?
Common::MemoryReadStream readS(ptr, entrySize);
g_cine->_objectTable[i].x = readS.readSint16BE();
diff --git a/engines/cine/pal.cpp b/engines/cine/pal.cpp
index 779c279ea1..10077ecdc9 100644
--- a/engines/cine/pal.cpp
+++ b/engines/cine/pal.cpp
@@ -92,7 +92,8 @@ void loadRelatedPalette(const char *fileName) {
paletteIndex = findPaletteFromName(localName);
if (paletteIndex == -1) {
- for (i = 0; i < 16; i++) { // generate default palette
+ // generate default palette
+ for (i = 0; i < 16; i++) {
paletteBuffer1[i] = paletteBuffer2[i] = (i << 4) + i;
}
} else {
diff --git a/engines/cine/part.cpp b/engines/cine/part.cpp
index 03cb743b46..813cbe50af 100644
--- a/engines/cine/part.cpp
+++ b/engines/cine/part.cpp
@@ -263,7 +263,7 @@ byte *readBundleSoundFile(const char *entryName, uint32 *size) {
/** Rotate byte value to the left by n bits */
byte rolByte(byte value, uint n) {
n %= 8;
- return (byte) ((value << n) | (value >> (8 - n)));
+ return (byte)((value << n) | (value >> (8 - n)));
}
byte *readFile(const char *filename, bool crypted) {
diff --git a/engines/cine/saveload.cpp b/engines/cine/saveload.cpp
index 20952eea52..51d2c1f6be 100644
--- a/engines/cine/saveload.cpp
+++ b/engines/cine/saveload.cpp
@@ -1002,7 +1002,7 @@ void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGam
const int entrySize = ((saveGameFormat == ANIMSIZE_23) ? 23 : 30);
const int fileStartPos = fHandle.pos();
- for(int resourceIndex=0; resourceIndex<NUM_MAX_ANIMDATA; resourceIndex++) {
+ for (int resourceIndex = 0; resourceIndex < NUM_MAX_ANIMDATA; resourceIndex++) {
// Seek to the start of the current animation's entry
fHandle.seek(fileStartPos + resourceIndex * entrySize);
// Read in the current animation entry
diff --git a/engines/cine/saveload.h b/engines/cine/saveload.h
index 49c9c0cef7..fd661904af 100644
--- a/engines/cine/saveload.h
+++ b/engines/cine/saveload.h
@@ -68,7 +68,7 @@ enum CineSaveGameFormat {
};
/** Identifier for the temporary Operation Stealth savegame format. */
-static const uint32 TEMP_OS_FORMAT_ID = MKTAG('T','E','M','P');
+static const uint32 TEMP_OS_FORMAT_ID = MKTAG('T', 'E', 'M', 'P');
/** The current version number of Operation Stealth's savegame format. */
static const uint32 CURRENT_OS_SAVE_VER = 1;
diff --git a/engines/cine/script.h b/engines/cine/script.h
index 3fc86c585b..a07c8d6cfc 100644
--- a/engines/cine/script.h
+++ b/engines/cine/script.h
@@ -227,6 +227,7 @@ protected:
int o1_op72();
int o1_op73();
int o1_playSample();
+ int o1_playSampleSwapped();
int o1_disableSystemMenu();
int o1_loadMask5();
int o1_unloadMask5();
diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp
index 9cbe3c3fab..b4fe68c343 100644
--- a/engines/cine/script_fw.cpp
+++ b/engines/cine/script_fw.cpp
@@ -196,7 +196,7 @@ void FWScript::setupTable() {
{ 0, 0 },
{ &FWScript::o1_playSample, "bbwbww" },
/* 78 */
- { &FWScript::o1_playSample, "bbwbww" },
+ { &FWScript::o1_playSampleSwapped, "bbwbww" },
{ &FWScript::o1_disableSystemMenu, "b" },
{ &FWScript::o1_loadMask5, "b" },
{ &FWScript::o1_unloadMask5, "b" }
@@ -352,7 +352,7 @@ void ScriptVars::load(Common::SeekableReadStream &fHandle, unsigned int len) {
* Reset all values to 0
*/
void ScriptVars::reset() {
- memset( _vars, 0, _size * sizeof(int16));
+ memset(_vars, 0, _size * sizeof(int16));
}
/**
@@ -380,10 +380,10 @@ RawScript::RawScript(const FWScriptInfo &info, const byte *data, uint16 s) :
* Copy constructor
*/
RawScript::RawScript(const RawScript &src) : _size(src._size),
- _data(new byte[_size+1]), _labels(src._labels) {
+ _data(new byte[_size + 1]), _labels(src._labels) {
assert(_data);
- memcpy(_data, src._data, _size+1);
+ memcpy(_data, src._data, _size + 1);
}
/**
@@ -398,7 +398,7 @@ RawScript::~RawScript() {
*/
RawScript &RawScript::operator=(const RawScript &src) {
assert(src._data);
- byte *tmp = new byte[src._size+1];
+ byte *tmp = new byte[src._size + 1];
assert(tmp);
_labels = src._labels;
@@ -443,14 +443,14 @@ int RawScript::getNextLabel(const FWScriptInfo &info, int offset) const {
pos += 2;
break;
case 'c': { // byte != 0 ? byte : word
- uint8 test = _data[pos];
+ uint8 test = _data[pos];
+ pos++;
+ if (test) {
pos++;
- if (test) {
- pos++;
- } else {
- pos += 2;
- }
+ } else {
+ pos += 2;
}
+ }
break;
case 'l': // label
return pos;
@@ -459,7 +459,7 @@ int RawScript::getNextLabel(const FWScriptInfo &info, int offset) const {
;
break;
case 'x': // exit script
- return -pos-1;
+ return -pos - 1;
}
}
}
@@ -498,9 +498,7 @@ void RawScript::computeLabels(const FWScriptInfo &info) {
*
* computeScriptStackFromScript replacement
*/
-uint16 RawScript::getLabel(const FWScriptInfo &info, byte index, uint16 offset)
- const {
-
+uint16 RawScript::getLabel(const FWScriptInfo &info, byte index, uint16 offset) const {
assert(_data);
int pos = offset;
@@ -519,7 +517,7 @@ uint16 RawScript::getLabel(const FWScriptInfo &info, byte index, uint16 offset)
*/
void RawScript::setData(const FWScriptInfo &info, const byte *data) {
assert(!_data); // this function should be called only once per instance
- _data = new byte[_size+1];
+ _data = new byte[_size + 1];
assert(data && _data);
memcpy(_data, data, _size * sizeof(byte));
@@ -553,7 +551,7 @@ byte RawScript::getByte(unsigned int pos) const {
* @return Word of bytecode
*/
uint16 RawScript::getWord(unsigned int pos) const {
- assert(_data && pos+1 < _size);
+ assert(_data && pos + 1 < _size);
return READ_BE_UINT16(_data + pos);
}
@@ -566,7 +564,7 @@ uint16 RawScript::getWord(unsigned int pos) const {
const char *RawScript::getString(unsigned int pos) const {
assert(_data && pos < _size);
- return (const char*)(_data+pos);
+ return (const char *)(_data + pos);
}
/**
@@ -580,8 +578,8 @@ const char *RawScript::getString(unsigned int pos) const {
* instance can be used. It leaves the instance in partially invalid state.
*/
RawObjectScript::RawObjectScript(uint16 s, uint16 p1, uint16 p2, uint16 p3)
- : RawScript(s), _runCount(0), _param1(p1), _param2(p2), _param3(p3)
-{ }
+ : RawScript(s), _runCount(0), _param1(p1), _param2(p2), _param3(p3) {
+}
/**
* Complete constructor
@@ -592,8 +590,9 @@ RawObjectScript::RawObjectScript(uint16 s, uint16 p1, uint16 p2, uint16 p3)
* @param p3 Third object script parameter
*/
RawObjectScript::RawObjectScript(const FWScriptInfo &info, const byte *data,
- uint16 s, uint16 p1, uint16 p2, uint16 p3) : RawScript(info, data, s),
- _runCount(0), _param1(p1), _param2(p2), _param3(p3) { }
+ uint16 s, uint16 p1, uint16 p2, uint16 p3)
+ : RawScript(info, data, s), _runCount(0), _param1(p1), _param2(p2), _param3(p3) {
+}
/**
* Contructor for global scripts
@@ -603,7 +602,8 @@ RawObjectScript::RawObjectScript(const FWScriptInfo &info, const byte *data,
FWScript::FWScript(const RawScript &script, int16 idx) : _script(script),
_pos(0), _line(0), _compare(0), _index(idx),
_labels(script.labels()), _localVars(LOCAL_VARS_SIZE),
- _globalVars(g_cine->_globalVars), _info(new FWScriptInfo) { }
+ _globalVars(g_cine->_globalVars), _info(new FWScriptInfo) {
+}
/**
* Copy constructor
@@ -611,25 +611,27 @@ FWScript::FWScript(const RawScript &script, int16 idx) : _script(script),
FWScript::FWScript(const FWScript &src) : _script(src._script), _pos(src._pos),
_line(src._line), _compare(src._compare), _index(src._index),
_labels(src._labels), _localVars(src._localVars),
- _globalVars(src._globalVars), _info(new FWScriptInfo) { }
+ _globalVars(src._globalVars), _info(new FWScriptInfo) {
+}
/**
* Contructor for global scripts in derived classes
* @param script Script bytecode reference
* @param idx Script bytecode index
*/
-FWScript::FWScript(const RawScript &script, int16 idx, FWScriptInfo *info) :
- _script(script), _pos(0), _line(0), _compare(0), _index(idx),
+FWScript::FWScript(const RawScript &script, int16 idx, FWScriptInfo *info)
+ : _script(script), _pos(0), _line(0), _compare(0), _index(idx),
_labels(script.labels()), _localVars(LOCAL_VARS_SIZE),
- _globalVars(g_cine->_globalVars), _info(info) { }
+ _globalVars(g_cine->_globalVars), _info(info) {
+}
/**
* Constructor for object scripts in derived classes
* @param script Script bytecode reference
* @param idx Script bytecode index
*/
-FWScript::FWScript(RawObjectScript &script, int16 idx, FWScriptInfo *info) :
- _script(script), _pos(0), _line(0), _compare(0), _index(idx),
+FWScript::FWScript(RawObjectScript &script, int16 idx, FWScriptInfo *info)
+ : _script(script), _pos(0), _line(0), _compare(0), _index(idx),
_labels(script.labels()), _localVars(LOCAL_VARS_SIZE),
_globalVars(g_cine->_globalVars), _info(info) {
@@ -639,8 +641,8 @@ FWScript::FWScript(RawObjectScript &script, int16 idx, FWScriptInfo *info) :
/**
* Copy constructor for derived classes
*/
-FWScript::FWScript(const FWScript &src, FWScriptInfo *info) :
- _script(src._script), _pos(src._pos), _line(src._line),
+FWScript::FWScript(const FWScript &src, FWScriptInfo *info)
+ : _script(src._script), _pos(src._pos), _line(src._line),
_compare(src._compare), _index(src._index), _labels(src._labels),
_localVars(src._localVars), _globalVars(src._globalVars), _info(info) { }
@@ -704,7 +706,7 @@ void FWScript::load(const ScriptVars &labels, const ScriptVars &local, uint16 co
int FWScript::execute() {
int ret = 0;
- if(_script._size) {
+ if (_script._size) {
while (!ret) {
_line = _pos;
byte opcode = getNextByte();
@@ -1816,6 +1818,9 @@ int FWScript::o1_playSample() {
if (g_cine->getPlatform() == Common::kPlatformAmiga || g_cine->getPlatform() == Common::kPlatformAtariST) {
if (size == 0xFFFF) {
size = g_cine->_animDataTable[anim]._width * g_cine->_animDataTable[anim]._height;
+ } else if (size > g_cine->_animDataTable[anim]._width * g_cine->_animDataTable[anim]._height) {
+ warning("o1_playSample: Got invalid sample size %d for sample %d", size, anim);
+ size = g_cine->_animDataTable[anim]._width * g_cine->_animDataTable[anim]._height;
}
if (channel < 10) { // || _currentOpcode == 0x78
int channel1, channel2;
@@ -1823,8 +1828,8 @@ int FWScript::o1_playSample() {
channel1 = 0;
channel2 = 1;
} else {
- channel1 = 2;
- channel2 = 3;
+ channel1 = 3;
+ channel2 = 2;
}
g_sound->playSound(channel1, freq, data, size, -1, volume, 63, repeat);
g_sound->playSound(channel2, freq, data, size, 1, volume, 0, repeat);
@@ -1858,6 +1863,53 @@ int FWScript::o1_playSample() {
return 0;
}
+int FWScript::o1_playSampleSwapped() {
+ // TODO: The DOS version probably does not have any stereo support here
+ // since the only stereo output it supports should be the Roland MT-32.
+ // So it probably does the same as o1_playSample here. Checking this will
+ // be a good idea never the less.
+ if (g_cine->getPlatform() == Common::kPlatformPC) {
+ return o1_playSample();
+ }
+
+ debugC(5, kCineDebugScript, "Line: %d: playSampleInversed()", _line);
+
+ byte anim = getNextByte();
+ byte channel = getNextByte();
+
+ uint16 freq = getNextWord();
+ byte repeat = getNextByte();
+
+ int16 volume = getNextWord();
+ uint16 size = getNextWord();
+
+ const byte *data = g_cine->_animDataTable[anim].data();
+
+ if (!data) {
+ return 0;
+ }
+
+ if (size == 0xFFFF) {
+ size = g_cine->_animDataTable[anim]._width * g_cine->_animDataTable[anim]._height;
+ } else if (size > g_cine->_animDataTable[anim]._width * g_cine->_animDataTable[anim]._height) {
+ warning("o1_playSampleSwapped: Got invalid sample size %d for sample %d", size, anim);
+ size = g_cine->_animDataTable[anim]._width * g_cine->_animDataTable[anim]._height;
+ }
+
+ int channel1, channel2;
+ if (channel == 0) {
+ channel1 = 1;
+ channel2 = 0;
+ } else {
+ channel1 = 2;
+ channel2 = 3;
+ }
+
+ g_sound->playSound(channel1, freq, data, size, -1, volume, 63, repeat);
+ g_sound->playSound(channel2, freq, data, size, 1, volume, 0, repeat);
+ return 0;
+}
+
int FWScript::o1_disableSystemMenu() {
byte param = getNextByte();
@@ -2074,1034 +2126,970 @@ void decompileScript(const byte *scriptPtr, uint16 scriptSize, uint16 scriptIdx)
strcpy(lineBuffer, "");
switch (opcode - 1) {
- case -1:
- {
- break;
- }
- case 0x0:
- {
- byte param1;
- byte param2;
- int16 param3;
+ case -1: {
+ break;
+ }
+ case 0x0: {
+ byte param1;
+ byte param2;
+ int16 param3;
- param1 = *(localScriptPtr + position);
- position++;
+ param1 = *(localScriptPtr + position);
+ position++;
- param2 = *(localScriptPtr + position);
- position++;
+ param2 = *(localScriptPtr + position);
+ position++;
- param3 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param3 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- sprintf(lineBuffer, "obj[%d]%s = %d\n", param1, getObjPramName(param2), param3);
+ sprintf(lineBuffer, "obj[%d]%s = %d\n", param1, getObjPramName(param2), param3);
- break;
- }
- case 0x1:
- {
- byte param1;
- byte param2;
- byte param3;
+ break;
+ }
+ case 0x1: {
+ byte param1;
+ byte param2;
+ byte param3;
- param1 = *(localScriptPtr + position);
- position++;
+ param1 = *(localScriptPtr + position);
+ position++;
- param2 = *(localScriptPtr + position);
- position++;
+ param2 = *(localScriptPtr + position);
+ position++;
- param3 = *(localScriptPtr + position);
- position++;
+ param3 = *(localScriptPtr + position);
+ position++;
- sprintf(lineBuffer, "var[%d]=obj[%d]%s\n", param3, param1, getObjPramName(param2));
- break;
- }
+ sprintf(lineBuffer, "var[%d]=obj[%d]%s\n", param3, param1, getObjPramName(param2));
+ break;
+ }
case 0x2:
case 0x3:
case 0x4:
case 0x5:
- case 0x6:
- {
- byte param1;
- byte param2;
- int16 param3;
-
- param1 = *(localScriptPtr + position);
- position++;
-
- param2 = *(localScriptPtr + position);
- position++;
-
- param3 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
-
- if (opcode - 1 == 0x2) {
- sprintf(lineBuffer, "obj[%d]%s+=%d\n", param1, getObjPramName(param2), param3);
- } else if (opcode - 1 == 0x3) {
- sprintf(lineBuffer, "obj[%d]%s-=%d\n", param1, getObjPramName(param2), param3);
- } else if (opcode - 1 == 0x4) {
- sprintf(lineBuffer, "obj[%d]%s+=obj[%d]%s\n", param1, getObjPramName(param2), param3, getObjPramName(param2));
- } else if (opcode - 1 == 0x5) {
- sprintf(lineBuffer, "obj[%d]%s-=obj[%d]%s\n", param1, getObjPramName(param2), param3, getObjPramName(param2));
- } else if (opcode - 1 == 0x6) {
- sprintf(compareString1, "obj[%d]%s", param1, getObjPramName(param2));
- sprintf(compareString2, "%d", param3);
- }
- break;
+ case 0x6: {
+ byte param1;
+ byte param2;
+ int16 param3;
+
+ param1 = *(localScriptPtr + position);
+ position++;
+
+ param2 = *(localScriptPtr + position);
+ position++;
+
+ param3 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
+
+ if (opcode - 1 == 0x2) {
+ sprintf(lineBuffer, "obj[%d]%s+=%d\n", param1, getObjPramName(param2), param3);
+ } else if (opcode - 1 == 0x3) {
+ sprintf(lineBuffer, "obj[%d]%s-=%d\n", param1, getObjPramName(param2), param3);
+ } else if (opcode - 1 == 0x4) {
+ sprintf(lineBuffer, "obj[%d]%s+=obj[%d]%s\n", param1, getObjPramName(param2), param3, getObjPramName(param2));
+ } else if (opcode - 1 == 0x5) {
+ sprintf(lineBuffer, "obj[%d]%s-=obj[%d]%s\n", param1, getObjPramName(param2), param3, getObjPramName(param2));
+ } else if (opcode - 1 == 0x6) {
+ sprintf(compareString1, "obj[%d]%s", param1, getObjPramName(param2));
+ sprintf(compareString2, "%d", param3);
}
+ break;
+ }
case 0x7:
- case 0x8:
- {
- byte param1;
- int16 param2;
- int16 param3;
- int16 param4;
- int16 param5;
+ case 0x8: {
+ byte param1;
+ int16 param2;
+ int16 param3;
+ int16 param4;
+ int16 param5;
- param1 = *(localScriptPtr + position);
- position++;
+ param1 = *(localScriptPtr + position);
+ position++;
- param2 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param2 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- param3 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param3 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- param4 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param4 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- param5 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param5 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- if (opcode - 1 == 0x7) {
- sprintf(lineBuffer, "setupObject(Idx:%d,X:%d,Y:%d,mask:%d,frame:%d)\n", param1, param2, param3, param4, param5);
- } else if (opcode - 1 == 0x8) {
- sprintf(lineBuffer, "checkCollision(%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5);
- }
- break;
+ if (opcode - 1 == 0x7) {
+ sprintf(lineBuffer, "setupObject(Idx:%d,X:%d,Y:%d,mask:%d,frame:%d)\n", param1, param2, param3, param4, param5);
+ } else if (opcode - 1 == 0x8) {
+ sprintf(lineBuffer, "checkCollision(%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5);
}
- case 0x9:
- {
- byte param1;
- int16 param2;
+ break;
+ }
+ case 0x9: {
+ byte param1;
+ int16 param2;
- param1 = *(localScriptPtr + position);
- position++;
+ param1 = *(localScriptPtr + position);
+ position++;
- param2 = *(localScriptPtr + position);
- position++;
+ param2 = *(localScriptPtr + position);
+ position++;
- if (param2) {
- byte param3;
-
- param3 = *(localScriptPtr + position);
- position++;
-
- if (param2 == 1) {
- sprintf(lineBuffer, "var[%d]=var[%d]\n", param1, param3);
- } else if (param2 == 2) {
- sprintf(lineBuffer, "var[%d]=globalVar[%d]\n", param1, param3);
- } else if (param2 == 3) {
- sprintf(lineBuffer, "var[%d]=mouse.X\n", param1);
- } else if (param2 == 4) {
- sprintf(lineBuffer, "var[%d]=mouse.Y\n", param1);
- } else if (param2 == 5) {
- sprintf(lineBuffer, "var[%d]=rand() mod %d\n", param1, param3);
- } else if (param2 == 8) {
- sprintf(lineBuffer, "var[%d]=file[%d].packedSize\n", param1, param3);
- } else if (param2 == 9) {
- sprintf(lineBuffer, "var[%d]=file[%d].unpackedSize\n", param1, param3);
- } else {
- error("decompileScript: 0x09: param2 = %d", param2);
- }
- } else {
- int16 param3;
+ if (param2) {
+ byte param3;
- param3 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param3 = *(localScriptPtr + position);
+ position++;
- sprintf(lineBuffer, "var[%d]=%d\n", param1, param3);
+ if (param2 == 1) {
+ sprintf(lineBuffer, "var[%d]=var[%d]\n", param1, param3);
+ } else if (param2 == 2) {
+ sprintf(lineBuffer, "var[%d]=globalVar[%d]\n", param1, param3);
+ } else if (param2 == 3) {
+ sprintf(lineBuffer, "var[%d]=mouse.X\n", param1);
+ } else if (param2 == 4) {
+ sprintf(lineBuffer, "var[%d]=mouse.Y\n", param1);
+ } else if (param2 == 5) {
+ sprintf(lineBuffer, "var[%d]=rand() mod %d\n", param1, param3);
+ } else if (param2 == 8) {
+ sprintf(lineBuffer, "var[%d]=file[%d].packedSize\n", param1, param3);
+ } else if (param2 == 9) {
+ sprintf(lineBuffer, "var[%d]=file[%d].unpackedSize\n", param1, param3);
+ } else {
+ error("decompileScript: 0x09: param2 = %d", param2);
}
+ } else {
+ int16 param3;
- break;
+ param3 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
+
+ sprintf(lineBuffer, "var[%d]=%d\n", param1, param3);
}
+
+ break;
+ }
case 0xA:
case 0xB:
case 0xC:
- case 0xD:
- {
- byte param1;
- byte param2;
+ case 0xD: {
+ byte param1;
+ byte param2;
- param1 = *(localScriptPtr + position);
- position++;
+ param1 = *(localScriptPtr + position);
+ position++;
- param2 = *(localScriptPtr + position);
+ param2 = *(localScriptPtr + position);
+ position++;
+
+ if (param2) {
+ byte param3;
+
+ param3 = *(localScriptPtr + position);
position++;
- if (param2) {
- byte param3;
+ if (opcode - 1 == 0xA) {
+ sprintf(lineBuffer, "var[%d]+=var[%d]\n", param1, param3);
+ } else if (opcode - 1 == 0xB) {
+ sprintf(lineBuffer, "var[%d]-=var[%d]\n", param1, param3);
+ } else if (opcode - 1 == 0xC) {
+ sprintf(lineBuffer, "var[%d]*=var[%d]\n", param1, param3);
+ } else if (opcode - 1 == 0xD) {
+ sprintf(lineBuffer, "var[%d]/=var[%d]\n", param1, param3);
+ }
+ } else {
+ int16 param3;
- param3 = *(localScriptPtr + position);
- position++;
+ param3 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- if (opcode - 1 == 0xA) {
- sprintf(lineBuffer, "var[%d]+=var[%d]\n", param1, param3);
- } else if (opcode - 1 == 0xB) {
- sprintf(lineBuffer, "var[%d]-=var[%d]\n", param1, param3);
- } else if (opcode - 1 == 0xC) {
- sprintf(lineBuffer, "var[%d]*=var[%d]\n", param1, param3);
- } else if (opcode - 1 == 0xD) {
- sprintf(lineBuffer, "var[%d]/=var[%d]\n", param1, param3);
- }
- } else {
- int16 param3;
-
- param3 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
-
- if (opcode - 1 == 0xA) {
- sprintf(lineBuffer, "var[%d]+=%d\n", param1, param3);
- } else if (opcode - 1 == 0xB) {
- sprintf(lineBuffer, "var[%d]-=%d\n", param1, param3);
- } else if (opcode - 1 == 0xC) {
- sprintf(lineBuffer, "var[%d]*=%d\n", param1, param3);
- } else if (opcode - 1 == 0xD) {
- sprintf(lineBuffer, "var[%d]/=%d\n", param1, param3);
- }
+ if (opcode - 1 == 0xA) {
+ sprintf(lineBuffer, "var[%d]+=%d\n", param1, param3);
+ } else if (opcode - 1 == 0xB) {
+ sprintf(lineBuffer, "var[%d]-=%d\n", param1, param3);
+ } else if (opcode - 1 == 0xC) {
+ sprintf(lineBuffer, "var[%d]*=%d\n", param1, param3);
+ } else if (opcode - 1 == 0xD) {
+ sprintf(lineBuffer, "var[%d]/=%d\n", param1, param3);
}
- break;
}
- case 0xE:
- {
- byte param1;
- byte param2;
+ break;
+ }
+ case 0xE: {
+ byte param1;
+ byte param2;
- param1 = *(localScriptPtr + position);
- position++;
+ param1 = *(localScriptPtr + position);
+ position++;
- param2 = *(localScriptPtr + position);
- position++;
+ param2 = *(localScriptPtr + position);
+ position++;
- if (param2) {
- byte param3;
+ if (param2) {
+ byte param3;
- param3 = *(localScriptPtr + position);
- position++;
+ param3 = *(localScriptPtr + position);
+ position++;
- if (param2 == 1) {
- sprintf(compareString1, "var[%d]", param1);
- sprintf(compareString2, "var[%d]", param3);
+ if (param2 == 1) {
+ sprintf(compareString1, "var[%d]", param1);
+ sprintf(compareString2, "var[%d]", param3);
- } else if (param2 == 2) {
- sprintf(compareString1, "var[%d]", param1);
- sprintf(compareString2, "globalVar[%d]", param3);
- } else {
- error("decompileScript: 0x0E: param2 = %d", param2);
- }
+ } else if (param2 == 2) {
+ sprintf(compareString1, "var[%d]", param1);
+ sprintf(compareString2, "globalVar[%d]", param3);
} else {
- int16 param3;
+ error("decompileScript: 0x0E: param2 = %d", param2);
+ }
+ } else {
+ int16 param3;
- param3 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param3 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- sprintf(compareString1, "var[%d]", param1);
- sprintf(compareString2, "%d", param3);
- }
- break;
+ sprintf(compareString1, "var[%d]", param1);
+ sprintf(compareString2, "%d", param3);
}
- case 0xF:
- {
- byte param1;
- byte param2;
- byte param3;
+ break;
+ }
+ case 0xF: {
+ byte param1;
+ byte param2;
+ byte param3;
- param1 = *(localScriptPtr + position);
- position++;
+ param1 = *(localScriptPtr + position);
+ position++;
- param2 = *(localScriptPtr + position);
- position++;
+ param2 = *(localScriptPtr + position);
+ position++;
- param3 = *(localScriptPtr + position);
- position++;
+ param3 = *(localScriptPtr + position);
+ position++;
- sprintf(lineBuffer, "obj[%d]%s=var[%d]\n", param1, getObjPramName(param2), param3);
+ sprintf(lineBuffer, "obj[%d]%s=var[%d]\n", param1, getObjPramName(param2), param3);
- break;
- }
+ break;
+ }
case 0x13:
case 0x14:
case 0x15:
case 0x16:
case 0x17:
case 0x18:
- case 0x19:
- {
- byte param;
-
- param = *(localScriptPtr + position);
- position++;
-
- if (opcode - 1 == 0x13) {
- sprintf(lineBuffer, "loadMask0(%d)\n", param);
- } else if (opcode - 1 == 0x14) {
- sprintf(lineBuffer, "unloadMask0(%d)\n", param);
- } else if (opcode - 1 == 0x15) {
- sprintf(lineBuffer, "OP_15(%d)\n", param);
- } else if (opcode - 1 == 0x16) {
- sprintf(lineBuffer, "loadMask1(%d)\n", param);
- } else if (opcode - 1 == 0x17) {
- sprintf(lineBuffer, "unloadMask0(%d)\n", param);
- } else if (opcode - 1 == 0x18) {
- sprintf(lineBuffer, "loadMask4(%d)\n", param);
- } else if (opcode - 1 == 0x19) {
- sprintf(lineBuffer, "unloadMask4(%d)\n", param);
- }
- break;
+ case 0x19: {
+ byte param;
+
+ param = *(localScriptPtr + position);
+ position++;
+
+ if (opcode - 1 == 0x13) {
+ sprintf(lineBuffer, "loadMask0(%d)\n", param);
+ } else if (opcode - 1 == 0x14) {
+ sprintf(lineBuffer, "unloadMask0(%d)\n", param);
+ } else if (opcode - 1 == 0x15) {
+ sprintf(lineBuffer, "OP_15(%d)\n", param);
+ } else if (opcode - 1 == 0x16) {
+ sprintf(lineBuffer, "loadMask1(%d)\n", param);
+ } else if (opcode - 1 == 0x17) {
+ sprintf(lineBuffer, "unloadMask0(%d)\n", param);
+ } else if (opcode - 1 == 0x18) {
+ sprintf(lineBuffer, "loadMask4(%d)\n", param);
+ } else if (opcode - 1 == 0x19) {
+ sprintf(lineBuffer, "unloadMask4(%d)\n", param);
}
- case 0x1A:
- {
- byte param;
+ break;
+ }
+ case 0x1A: {
+ byte param;
- param = *(localScriptPtr + position);
- position++;
+ param = *(localScriptPtr + position);
+ position++;
- sprintf(lineBuffer, "OP_1A(%d)\n", param);
+ sprintf(lineBuffer, "OP_1A(%d)\n", param);
- break;
- }
- case 0x1B:
- {
- sprintf(lineBuffer, "bgIncrustList.clear()\n");
- break;
- }
- case 0x1D:
- {
- byte param;
+ break;
+ }
+ case 0x1B: {
+ sprintf(lineBuffer, "bgIncrustList.clear()\n");
+ break;
+ }
+ case 0x1D: {
+ byte param;
- param = *(localScriptPtr + position);
- position++;
+ param = *(localScriptPtr + position);
+ position++;
- sprintf(lineBuffer, "label(%d)\n", param);
+ sprintf(lineBuffer, "label(%d)\n", param);
- break;
- }
- case 0x1E:
- {
- byte param;
+ break;
+ }
+ case 0x1E: {
+ byte param;
- param = *(localScriptPtr + position);
- position++;
+ param = *(localScriptPtr + position);
+ position++;
- sprintf(lineBuffer, "goto(%d)\n", param);
+ sprintf(lineBuffer, "goto(%d)\n", param);
- break;
- }
+ break;
+ }
// If cases
case 0x1F:
case 0x20:
case 0x21:
case 0x22:
case 0x23:
- case 0x24:
- {
- byte param;
-
- param = *(localScriptPtr + position);
- position++;
-
- if (opcode - 1 == 0x1F) {
- sprintf(lineBuffer, "if(%s>%s) goto(%d)\n", compareString1, compareString2, param);
- } else if (opcode - 1 == 0x20) {
- sprintf(lineBuffer, "if(%s>=%s) goto(%d)\n", compareString1, compareString2, param);
- } else if (opcode - 1 == 0x21) {
- sprintf(lineBuffer, "if(%s<%s) goto(%d)\n", compareString1, compareString2, param);
- } else if (opcode - 1 == 0x22) {
- sprintf(lineBuffer, "if(%s<=%s) goto(%d)\n", compareString1, compareString2, param);
- } else if (opcode - 1 == 0x23) {
- sprintf(lineBuffer, "if(%s==%s) goto(%d)\n", compareString1, compareString2, param);
- } else if (opcode - 1 == 0x24) {
- sprintf(lineBuffer, "if(%s!=%s) goto(%d)\n", compareString1, compareString2, param);
- }
- break;
+ case 0x24: {
+ byte param;
+
+ param = *(localScriptPtr + position);
+ position++;
+
+ if (opcode - 1 == 0x1F) {
+ sprintf(lineBuffer, "if(%s>%s) goto(%d)\n", compareString1, compareString2, param);
+ } else if (opcode - 1 == 0x20) {
+ sprintf(lineBuffer, "if(%s>=%s) goto(%d)\n", compareString1, compareString2, param);
+ } else if (opcode - 1 == 0x21) {
+ sprintf(lineBuffer, "if(%s<%s) goto(%d)\n", compareString1, compareString2, param);
+ } else if (opcode - 1 == 0x22) {
+ sprintf(lineBuffer, "if(%s<=%s) goto(%d)\n", compareString1, compareString2, param);
+ } else if (opcode - 1 == 0x23) {
+ sprintf(lineBuffer, "if(%s==%s) goto(%d)\n", compareString1, compareString2, param);
+ } else if (opcode - 1 == 0x24) {
+ sprintf(lineBuffer, "if(%s!=%s) goto(%d)\n", compareString1, compareString2, param);
}
- case 0x25:
- {
- byte param;
+ break;
+ }
+ case 0x25: {
+ byte param;
- param = *(localScriptPtr + position);
- position++;
+ param = *(localScriptPtr + position);
+ position++;
- sprintf(lineBuffer, "removeLabel(%d)\n", param);
+ sprintf(lineBuffer, "removeLabel(%d)\n", param);
- break;
- }
- case 0x26:
- {
- byte param1;
- byte param2;
+ break;
+ }
+ case 0x26: {
+ byte param1;
+ byte param2;
- param1 = *(localScriptPtr + position);
- position++;
- param2 = *(localScriptPtr + position);
- position++;
+ param1 = *(localScriptPtr + position);
+ position++;
+ param2 = *(localScriptPtr + position);
+ position++;
- sprintf(lineBuffer, "loop(--var[%d]) -> label(%d)\n", param1, param2);
+ sprintf(lineBuffer, "loop(--var[%d]) -> label(%d)\n", param1, param2);
- break;
- }
+ break;
+ }
case 0x31:
- case 0x32:
- {
- byte param;
+ case 0x32: {
+ byte param;
- param = *(localScriptPtr + position);
- position++;
+ param = *(localScriptPtr + position);
+ position++;
- if (opcode - 1 == 0x31) {
- sprintf(lineBuffer, "startGlobalScript(%d)\n", param);
- } else if (opcode - 1 == 0x32) {
- sprintf(lineBuffer, "endGlobalScript(%d)\n", param);
- }
- break;
+ if (opcode - 1 == 0x31) {
+ sprintf(lineBuffer, "startGlobalScript(%d)\n", param);
+ } else if (opcode - 1 == 0x32) {
+ sprintf(lineBuffer, "endGlobalScript(%d)\n", param);
}
+ break;
+ }
case 0x3B:
case 0x3C:
case 0x3D:
- case OP_loadPart:
- {
- if (opcode - 1 == 0x3B) {
- sprintf(lineBuffer, "loadResource(%s)\n", localScriptPtr + position);
- } else if (opcode - 1 == 0x3C) {
- sprintf(lineBuffer, "loadBg(%s)\n", localScriptPtr + position);
- } else if (opcode - 1 == 0x3D) {
- sprintf(lineBuffer, "loadCt(%s)\n", localScriptPtr + position);
- } else if (opcode - 1 == OP_loadPart) {
- sprintf(lineBuffer, "loadPart(%s)\n", localScriptPtr + position);
- }
-
- position += strlen((const char *)localScriptPtr + position) + 1;
- break;
- }
- case 0x40:
- {
- sprintf(lineBuffer, "closePart()\n");
- break;
- }
- case OP_loadNewPrcName:
- {
- byte param;
+ case OP_loadPart: {
+ if (opcode - 1 == 0x3B) {
+ sprintf(lineBuffer, "loadResource(%s)\n", localScriptPtr + position);
+ } else if (opcode - 1 == 0x3C) {
+ sprintf(lineBuffer, "loadBg(%s)\n", localScriptPtr + position);
+ } else if (opcode - 1 == 0x3D) {
+ sprintf(lineBuffer, "loadCt(%s)\n", localScriptPtr + position);
+ } else if (opcode - 1 == OP_loadPart) {
+ sprintf(lineBuffer, "loadPart(%s)\n", localScriptPtr + position);
+ }
+
+ position += strlen((const char *)localScriptPtr + position) + 1;
+ break;
+ }
+ case 0x40: {
+ sprintf(lineBuffer, "closePart()\n");
+ break;
+ }
+ case OP_loadNewPrcName: {
+ byte param;
- param = *(localScriptPtr + position);
- position++;
+ param = *(localScriptPtr + position);
+ position++;
- sprintf(lineBuffer, "loadPrc(%d,%s)\n", param, localScriptPtr + position);
+ sprintf(lineBuffer, "loadPrc(%d,%s)\n", param, localScriptPtr + position);
- position += strlen((const char *)localScriptPtr + position) + 1;
- break;
- }
- case OP_requestCheckPendingDataLoad: // nop
- {
- sprintf(lineBuffer, "requestCheckPendingDataLoad()\n");
- break;
- }
- case 0x45:
- {
- sprintf(lineBuffer, "blitAndFade()\n");
- break;
- }
- case 0x46:
- {
- sprintf(lineBuffer, "fadeToBlack()\n");
- break;
- }
- case 0x47:
- {
- byte param1;
- byte param2;
- int16 param3;
- int16 param4;
- int16 param5;
+ position += strlen((const char *)localScriptPtr + position) + 1;
+ break;
+ }
+ case OP_requestCheckPendingDataLoad: { // nop
+ sprintf(lineBuffer, "requestCheckPendingDataLoad()\n");
+ break;
+ }
+ case 0x45: {
+ sprintf(lineBuffer, "blitAndFade()\n");
+ break;
+ }
+ case 0x46: {
+ sprintf(lineBuffer, "fadeToBlack()\n");
+ break;
+ }
+ case 0x47: {
+ byte param1;
+ byte param2;
+ int16 param3;
+ int16 param4;
+ int16 param5;
- param1 = *(localScriptPtr + position);
- position++;
+ param1 = *(localScriptPtr + position);
+ position++;
- param2 = *(localScriptPtr + position);
- position++;
+ param2 = *(localScriptPtr + position);
+ position++;
- param3 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param3 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- param4 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param4 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- param5 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param5 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- sprintf(lineBuffer, "transformPaletteRange(%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5);
+ sprintf(lineBuffer, "transformPaletteRange(%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5);
- break;
- }
- case 0x49:
- {
- byte param;
+ break;
+ }
+ case 0x49: {
+ byte param;
- param = *(localScriptPtr + position);
- position++;
+ param = *(localScriptPtr + position);
+ position++;
- sprintf(lineBuffer, "setDefaultMenuBgColor(%d)\n", param);
+ sprintf(lineBuffer, "setDefaultMenuBgColor(%d)\n", param);
- break;
- }
- case 0x4F:
- {
- sprintf(lineBuffer, "break()\n");
- exitScript = 1;
- break;
- }
- case 0x50:
- {
- sprintf(lineBuffer, "endScript()\n\n");
- break;
- }
- case 0x51:
- {
- byte param1;
- int16 param2;
- int16 param3;
- int16 param4;
- int16 param5;
+ break;
+ }
+ case 0x4F: {
+ sprintf(lineBuffer, "break()\n");
+ exitScript = 1;
+ break;
+ }
+ case 0x50: {
+ sprintf(lineBuffer, "endScript()\n\n");
+ break;
+ }
+ case 0x51: {
+ byte param1;
+ int16 param2;
+ int16 param3;
+ int16 param4;
+ int16 param5;
- param1 = *(localScriptPtr + position);
- position++;
+ param1 = *(localScriptPtr + position);
+ position++;
- param2 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param2 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- param3 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param3 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- param4 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param4 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- param5 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param5 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- sprintf(lineBuffer, "message(%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5);
+ sprintf(lineBuffer, "message(%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5);
- break;
- }
+ break;
+ }
case 0x52:
- case 0x53:
- {
- byte param1;
- byte param2;
+ case 0x53: {
+ byte param1;
+ byte param2;
- param1 = *(localScriptPtr + position);
- position++;
+ param1 = *(localScriptPtr + position);
+ position++;
- param2 = *(localScriptPtr + position);
- position++;
+ param2 = *(localScriptPtr + position);
+ position++;
- if (param2) {
- byte param3;
-
- param3 = *(localScriptPtr + position);
- position++;
-
- if (param2 == 1) {
- if (opcode - 1 == 0x52) {
- sprintf(lineBuffer, "globalVar[%d] = var[%d]\n", param1, param3);
- } else if (opcode - 1 == 0x53) {
- sprintf(compareString1, "globalVar[%d]", param1);
- sprintf(compareString2, "var[%d]", param3);
- }
- } else if (param2 == 2) {
- if (opcode - 1 == 0x52) {
- sprintf(lineBuffer, "globalVar[%d] = globalVar[%d]\n", param1, param3);
- } else if (opcode - 1 == 0x53) {
- sprintf(compareString1, "globalVar[%d]", param1);
- sprintf(compareString2, "globalVar[%d]", param3);
- }
- } else {
- if (opcode - 1 == 0x52) {
- error("decompileScript: 0x52: param2 = %d", param2);
- } else if (opcode - 1 == 0x53) {
- error("decompileScript: 0x53: param2 = %d", param2);
- }
- }
- } else {
- int16 param3;
+ if (param2) {
+ byte param3;
- param3 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param3 = *(localScriptPtr + position);
+ position++;
+ if (param2 == 1) {
if (opcode - 1 == 0x52) {
- sprintf(lineBuffer, "globalVar[%d] = %d\n", param1, param3);
+ sprintf(lineBuffer, "globalVar[%d] = var[%d]\n", param1, param3);
} else if (opcode - 1 == 0x53) {
sprintf(compareString1, "globalVar[%d]", param1);
- sprintf(compareString2, "%d", param3);
+ sprintf(compareString2, "var[%d]", param3);
+ }
+ } else if (param2 == 2) {
+ if (opcode - 1 == 0x52) {
+ sprintf(lineBuffer, "globalVar[%d] = globalVar[%d]\n", param1, param3);
+ } else if (opcode - 1 == 0x53) {
+ sprintf(compareString1, "globalVar[%d]", param1);
+ sprintf(compareString2, "globalVar[%d]", param3);
+ }
+ } else {
+ if (opcode - 1 == 0x52) {
+ error("decompileScript: 0x52: param2 = %d", param2);
+ } else if (opcode - 1 == 0x53) {
+ error("decompileScript: 0x53: param2 = %d", param2);
}
}
- break;
- }
- case 0x59:
- {
- sprintf(lineBuffer, "comment: %s\n", localScriptPtr + position);
+ } else {
+ int16 param3;
- position += strlen((const char *)localScriptPtr + position);
- break;
+ param3 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
+
+ if (opcode - 1 == 0x52) {
+ sprintf(lineBuffer, "globalVar[%d] = %d\n", param1, param3);
+ } else if (opcode - 1 == 0x53) {
+ sprintf(compareString1, "globalVar[%d]", param1);
+ sprintf(compareString2, "%d", param3);
+ }
}
- case 0x5A:
- {
- byte param1;
- byte param2;
+ break;
+ }
+ case 0x59: {
+ sprintf(lineBuffer, "comment: %s\n", localScriptPtr + position);
- param1 = *(localScriptPtr + position);
- position++;
+ position += strlen((const char *)localScriptPtr + position);
+ break;
+ }
+ case 0x5A: {
+ byte param1;
+ byte param2;
- param2 = *(localScriptPtr + position);
- position++;
+ param1 = *(localScriptPtr + position);
+ position++;
- sprintf(lineBuffer, "freePartRang(%d,%d)\n", param1, param2);
+ param2 = *(localScriptPtr + position);
+ position++;
- break;
- }
- case 0x5B:
- {
- sprintf(lineBuffer, "unloadAllMasks()\n");
- break;
- }
- case 0x65:
- {
- sprintf(lineBuffer, "setupTableUnk1()\n");
- break;
- }
- case 0x66:
- {
- byte param1;
- int16 param2;
+ sprintf(lineBuffer, "freePartRang(%d,%d)\n", param1, param2);
- param1 = *(localScriptPtr + position);
- position++;
+ break;
+ }
+ case 0x5B: {
+ sprintf(lineBuffer, "unloadAllMasks()\n");
+ break;
+ }
+ case 0x65: {
+ sprintf(lineBuffer, "setupTableUnk1()\n");
+ break;
+ }
+ case 0x66: {
+ byte param1;
+ int16 param2;
- param2 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param1 = *(localScriptPtr + position);
+ position++;
- sprintf(lineBuffer, "tableUnk1[%d] = %d\n", param1, param2);
+ param2 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- break;
- }
- case 0x68:
- {
- byte param;
+ sprintf(lineBuffer, "tableUnk1[%d] = %d\n", param1, param2);
- param = *(localScriptPtr + position);
- position++;
+ break;
+ }
+ case 0x68: {
+ byte param;
- sprintf(lineBuffer, "setPlayerCommandPosY(%d)\n", param);
+ param = *(localScriptPtr + position);
+ position++;
- break;
- }
- case 0x69:
- {
- sprintf(lineBuffer, "allowPlayerInput()\n");
- break;
- }
- case 0x6A:
- {
- sprintf(lineBuffer, "disallowPlayerInput()\n");
- break;
- }
- case 0x6B:
- {
- byte newDisk;
+ sprintf(lineBuffer, "setPlayerCommandPosY(%d)\n", param);
- newDisk = *(localScriptPtr + position);
- position++;
+ break;
+ }
+ case 0x69: {
+ sprintf(lineBuffer, "allowPlayerInput()\n");
+ break;
+ }
+ case 0x6A: {
+ sprintf(lineBuffer, "disallowPlayerInput()\n");
+ break;
+ }
+ case 0x6B: {
+ byte newDisk;
- sprintf(lineBuffer, "changeDataDisk(%d)\n", newDisk);
+ newDisk = *(localScriptPtr + position);
+ position++;
- break;
- }
- case 0x6D:
- {
- sprintf(lineBuffer, "loadDat(%s)\n", localScriptPtr + position);
+ sprintf(lineBuffer, "changeDataDisk(%d)\n", newDisk);
- position += strlen((const char *)localScriptPtr + position) + 1;
- break;
- }
- case 0x6E: // nop
- {
- sprintf(lineBuffer, "updateDat()\n");
- break;
- }
- case 0x6F:
- {
- sprintf(lineBuffer, "OP_6F() -> dat related\n");
- break;
- }
- case 0x70:
- {
- sprintf(lineBuffer, "stopSample()\n");
- break;
- }
- case 0x79:
- {
- byte param;
+ break;
+ }
+ case 0x6D: {
+ sprintf(lineBuffer, "loadDat(%s)\n", localScriptPtr + position);
- param = *(localScriptPtr + position);
- position++;
+ position += strlen((const char *)localScriptPtr + position) + 1;
+ break;
+ }
+ case 0x6E: { // nop
+ sprintf(lineBuffer, "updateDat()\n");
+ break;
+ }
+ case 0x6F: {
+ sprintf(lineBuffer, "OP_6F() -> dat related\n");
+ break;
+ }
+ case 0x70: {
+ sprintf(lineBuffer, "stopSample()\n");
+ break;
+ }
+ case 0x79: {
+ byte param;
- sprintf(lineBuffer, "disableSystemMenu(%d)\n", param);
+ param = *(localScriptPtr + position);
+ position++;
- break;
- }
+ sprintf(lineBuffer, "disableSystemMenu(%d)\n", param);
+
+ break;
+ }
case 0x77:
- case 0x78:
- {
- byte param1;
- byte param2;
- int16 param3;
- byte param4;
- int16 param5;
- int16 param6;
+ case 0x78: {
+ byte param1;
+ byte param2;
+ int16 param3;
+ byte param4;
+ int16 param5;
+ int16 param6;
- param1 = *(localScriptPtr + position);
- position++;
+ param1 = *(localScriptPtr + position);
+ position++;
- param2 = *(localScriptPtr + position);
- position++;
+ param2 = *(localScriptPtr + position);
+ position++;
- param3 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param3 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- param4 = *(localScriptPtr + position);
- position++;
+ param4 = *(localScriptPtr + position);
+ position++;
- param5 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param5 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- param6 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
-
- if (opcode - 1 == 0x77) {
- sprintf(lineBuffer, "playSample(%d,%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5, param6);
- } else if (opcode - 1 == 0x78) {
- sprintf(lineBuffer, "OP_78(%d,%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5, param6);
- }
+ param6 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- break;
+ if (opcode - 1 == 0x77) {
+ sprintf(lineBuffer, "playSample(%d,%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5, param6);
+ } else if (opcode - 1 == 0x78) {
+ sprintf(lineBuffer, "playSampleSwapped(%d,%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5, param6);
}
- case 0x7A:
- {
- byte param;
- param = *(localScriptPtr + position);
- position++;
+ break;
+ }
+ case 0x7A: {
+ byte param;
- sprintf(lineBuffer, "OP_7A(%d)\n", param);
+ param = *(localScriptPtr + position);
+ position++;
- break;
- }
- case 0x7B: // OS only
- {
- byte param;
+ sprintf(lineBuffer, "OP_7A(%d)\n", param);
- param = *(localScriptPtr + position);
- position++;
+ break;
+ }
+ case 0x7B: { // OS only
+ byte param;
- sprintf(lineBuffer, "OP_7B(%d)\n", param);
+ param = *(localScriptPtr + position);
+ position++;
- break;
- }
- case 0x7F: // OS only
- {
- byte param1;
- byte param2;
- byte param3;
- byte param4;
- int16 param5;
- int16 param6;
- int16 param7;
+ sprintf(lineBuffer, "OP_7B(%d)\n", param);
- param1 = *(localScriptPtr + position);
- position++;
+ break;
+ }
+ case 0x7F: { // OS only
+ byte param1;
+ byte param2;
+ byte param3;
+ byte param4;
+ int16 param5;
+ int16 param6;
+ int16 param7;
- param2 = *(localScriptPtr + position);
- position++;
+ param1 = *(localScriptPtr + position);
+ position++;
- param3 = *(localScriptPtr + position);
- position++;
+ param2 = *(localScriptPtr + position);
+ position++;
- param4 = *(localScriptPtr + position);
- position++;
+ param3 = *(localScriptPtr + position);
+ position++;
- param5 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param4 = *(localScriptPtr + position);
+ position++;
- param6 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param5 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- param7 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param6 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- sprintf(lineBuffer, "OP_7F(%d,%d,%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5, param6, param7);
+ param7 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- break;
- }
- case 0x80: // OS only
- {
- byte param1;
- byte param2;
+ sprintf(lineBuffer, "OP_7F(%d,%d,%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5, param6, param7);
- param1 = *(localScriptPtr + position);
- position++;
+ break;
+ }
+ case 0x80: { // OS only
+ byte param1;
+ byte param2;
- param2 = *(localScriptPtr + position);
- position++;
+ param1 = *(localScriptPtr + position);
+ position++;
- sprintf(lineBuffer, "OP_80(%d,%d)\n", param1, param2);
+ param2 = *(localScriptPtr + position);
+ position++;
- break;
- }
- case 0x82: // OS only
- {
- byte param1;
- byte param2;
- uint16 param3;
- uint16 param4;
- byte param5;
+ sprintf(lineBuffer, "OP_80(%d,%d)\n", param1, param2);
- param1 = *(localScriptPtr + position);
- position++;
+ break;
+ }
+ case 0x82: { // OS only
+ byte param1;
+ byte param2;
+ uint16 param3;
+ uint16 param4;
+ byte param5;
- param2 = *(localScriptPtr + position);
- position++;
+ param1 = *(localScriptPtr + position);
+ position++;
- param3 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param2 = *(localScriptPtr + position);
+ position++;
- param4 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param3 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- param5 = *(localScriptPtr + position);
- position++;
+ param4 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- sprintf(lineBuffer, "OP_82(%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5);
+ param5 = *(localScriptPtr + position);
+ position++;
- break;
- }
- case 0x83: // OS only
- {
- byte param1;
- byte param2;
+ sprintf(lineBuffer, "OP_82(%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5);
- param1 = *(localScriptPtr + position);
- position++;
+ break;
+ }
+ case 0x83: { // OS only
+ byte param1;
+ byte param2;
- param2 = *(localScriptPtr + position);
- position++;
+ param1 = *(localScriptPtr + position);
+ position++;
- sprintf(lineBuffer, "OP_83(%d,%d)\n", param1, param2);
+ param2 = *(localScriptPtr + position);
+ position++;
- break;
- }
- case 0x89: // OS only
- {
- byte param;
+ sprintf(lineBuffer, "OP_83(%d,%d)\n", param1, param2);
- param = *(localScriptPtr + position);
- position++;
+ break;
+ }
+ case 0x89: { // OS only
+ byte param;
- sprintf(lineBuffer, "if(%s!=%s) goto next label(%d)\n", compareString1, compareString2, param);
+ param = *(localScriptPtr + position);
+ position++;
- break;
- }
- case 0x8B: // OS only
- {
- byte param;
+ sprintf(lineBuffer, "if(%s!=%s) goto next label(%d)\n", compareString1, compareString2, param);
- param = *(localScriptPtr + position);
- position++;
+ break;
+ }
+ case 0x8B: { // OS only
+ byte param;
- sprintf(lineBuffer, "OP_8B(%d)\n", param);
+ param = *(localScriptPtr + position);
+ position++;
- break;
- }
- case 0x8C: // OS only
- {
- byte param;
+ sprintf(lineBuffer, "OP_8B(%d)\n", param);
- param = *(localScriptPtr + position);
- position++;
+ break;
+ }
+ case 0x8C: { // OS only
+ byte param;
- sprintf(lineBuffer, "OP_8C(%d)\n", param);
+ param = *(localScriptPtr + position);
+ position++;
- break;
- }
- case 0x8D: // OS only
- {
- int16 param1;
- int16 param2;
- int16 param3;
- int16 param4;
- int16 param5;
- int16 param6;
- int16 param7;
- int16 param8;
+ sprintf(lineBuffer, "OP_8C(%d)\n", param);
- param1 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ break;
+ }
+ case 0x8D: { // OS only
+ int16 param1;
+ int16 param2;
+ int16 param3;
+ int16 param4;
+ int16 param5;
+ int16 param6;
+ int16 param7;
+ int16 param8;
- param2 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param1 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- param3 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param2 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- param4 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param3 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- param5 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param4 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- param6 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param5 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- param7 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param6 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- param8 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ param7 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- sprintf(compareString1, "obj[%d]", param1);
- sprintf(compareString2, "{%d,%d,%d,%d,%d,%d,%d}", param2, param3, param4, param5, param6, param7, param8);
+ param8 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- break;
- }
- case 0x8E: // OS only
- {
- byte param1;
+ sprintf(compareString1, "obj[%d]", param1);
+ sprintf(compareString2, "{%d,%d,%d,%d,%d,%d,%d}", param2, param3, param4, param5, param6, param7, param8);
- param1 = *(localScriptPtr + position);
- position++;
+ break;
+ }
+ case 0x8E: { // OS only
+ byte param1;
- sprintf(lineBuffer, "ADDBG(%d,%s)\n", param1, localScriptPtr + position);
+ param1 = *(localScriptPtr + position);
+ position++;
- position += strlen((const char *)localScriptPtr + position);
+ sprintf(lineBuffer, "ADDBG(%d,%s)\n", param1, localScriptPtr + position);
- break;
- }
- case 0x8F: // OS only
- {
- byte param;
+ position += strlen((const char *)localScriptPtr + position);
- param = *(localScriptPtr + position);
- position++;
+ break;
+ }
+ case 0x8F: { // OS only
+ byte param;
- sprintf(lineBuffer, "OP_8F(%d)\n", param);
+ param = *(localScriptPtr + position);
+ position++;
- break;
- }
- case 0x90: // OS only
- {
- byte param1;
+ sprintf(lineBuffer, "OP_8F(%d)\n", param);
- param1 = *(localScriptPtr + position);
- position++;
+ break;
+ }
+ case 0x90: { // OS only
+ byte param1;
- sprintf(lineBuffer, "loadABS(%d,%s)\n", param1, localScriptPtr + position);
+ param1 = *(localScriptPtr + position);
+ position++;
- position += strlen((const char *)localScriptPtr + position);
+ sprintf(lineBuffer, "loadABS(%d,%s)\n", param1, localScriptPtr + position);
- break;
- }
- case 0x91: // OS only
- {
- byte param;
+ position += strlen((const char *)localScriptPtr + position);
- param = *(localScriptPtr + position);
- position++;
+ break;
+ }
+ case 0x91: { // OS only
+ byte param;
- sprintf(lineBuffer, "OP_91(%d)\n", param);
+ param = *(localScriptPtr + position);
+ position++;
- break;
- }
- case 0x9D: // OS only
- {
- byte param;
+ sprintf(lineBuffer, "OP_91(%d)\n", param);
- param = *(localScriptPtr + position);
- position++;
+ break;
+ }
+ case 0x9D: { // OS only
+ byte param;
- sprintf(lineBuffer, "OP_9D(%d) -> flip img idx\n", param);
+ param = *(localScriptPtr + position);
+ position++;
- break;
- }
- case 0x9E: // OS only
- {
- byte param;
+ sprintf(lineBuffer, "OP_9D(%d) -> flip img idx\n", param);
- param = *(localScriptPtr + position);
- position++;
+ break;
+ }
+ case 0x9E: { // OS only
+ byte param;
- if (param) {
- byte param2;
+ param = *(localScriptPtr + position);
+ position++;
- param2 = *(localScriptPtr + position);
- position++;
+ if (param) {
+ byte param2;
- sprintf(lineBuffer, "OP_9E(%d,%d)\n", param, param2);
- } else {
- int16 param2;
+ param2 = *(localScriptPtr + position);
+ position++;
- param2 = READ_BE_UINT16(localScriptPtr + position);
- position += 2;
+ sprintf(lineBuffer, "OP_9E(%d,%d)\n", param, param2);
+ } else {
+ int16 param2;
- sprintf(lineBuffer, "OP_9E(%d,%d)\n", param, param2);
- }
+ param2 = READ_BE_UINT16(localScriptPtr + position);
+ position += 2;
- break;
+ sprintf(lineBuffer, "OP_9E(%d,%d)\n", param, param2);
}
- case 0xA0: // OS only
- {
- byte param1;
- byte param2;
- param1 = *(localScriptPtr + position);
- position++;
+ break;
+ }
+ case 0xA0: { // OS only
+ byte param1;
+ byte param2;
- param2 = *(localScriptPtr + position);
- position++;
+ param1 = *(localScriptPtr + position);
+ position++;
- sprintf(lineBuffer, "OP_A0(%d,%d)\n", param1, param2);
+ param2 = *(localScriptPtr + position);
+ position++;
- break;
- }
- case 0xA1: // OS only
- {
- byte param1;
- byte param2;
+ sprintf(lineBuffer, "OP_A0(%d,%d)\n", param1, param2);
- param1 = *(localScriptPtr + position);
- position++;
+ break;
+ }
+ case 0xA1: { // OS only
+ byte param1;
+ byte param2;
- param2 = *(localScriptPtr + position);
- position++;
+ param1 = *(localScriptPtr + position);
+ position++;
- sprintf(lineBuffer, "OP_A1(%d,%d)\n", param1, param2);
+ param2 = *(localScriptPtr + position);
+ position++;
- break;
- }
- default:
- {
- sprintf(lineBuffer, "Unsupported opcode %X in decompileScript\n\n", opcode - 1);
- position = scriptSize;
- break;
- }
+ sprintf(lineBuffer, "OP_A1(%d,%d)\n", param1, param2);
+
+ break;
+ }
+ default: {
+ sprintf(lineBuffer, "Unsupported opcode %X in decompileScript\n\n", opcode - 1);
+ position = scriptSize;
+ break;
+ }
}
- // printf(lineBuffer);
+ //printf(lineBuffer);
strcpy(decompileBuffer[decompileBufferPosition++], lineBuffer);
exitScript = 0;
diff --git a/engines/cine/sound.cpp b/engines/cine/sound.cpp
index 52e1cdac7e..10404ae56b 100644
--- a/engines/cine/sound.cpp
+++ b/engines/cine/sound.cpp
@@ -153,7 +153,7 @@ const int AdLibSoundDriver::_freqTable[] = {
const int AdLibSoundDriver::_freqTableCount = ARRAYSIZE(_freqTable);
const int AdLibSoundDriver::_operatorsTable[] = {
- 0, 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21
+ 0, 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21
};
const int AdLibSoundDriver::_operatorsTableCount = ARRAYSIZE(_operatorsTable);
@@ -614,7 +614,7 @@ void AdLibSoundDriverADL::playSample(const byte *data, int size, int channel, in
}
MidiSoundDriverH32::MidiSoundDriverH32(MidiDriver *output)
- : _output(output), _callback(0), _mutex() {
+ : _output(output), _callback(0), _mutex() {
}
MidiSoundDriverH32::~MidiSoundDriverH32() {
@@ -731,13 +731,13 @@ void MidiSoundDriverH32::selectInstrument(int channel, int timbreGroup, int timb
0x00, 0x00, 0x00, // offset
0x00, // Timbre group _ timbreGroup * 64 + timbreNumber should be the
0x00, // Timbre number / MT-32 instrument in case timbreGroup is 0 or 1.
- 0x18, // Key shift (= 0)
+ 0x18, // Key shift (= 0)
0x32, // Fine tune (= 0)
0x0C, // Bender Range
0x03, // Assign Mode
0x01, // Reverb Switch (= enabled)
0x00, // dummy
- 0x00, // Output level
+ 0x00, // Output level
0x07, // Panpot (= balanced)
0x00, // dummy
0x00, // dummy
@@ -998,19 +998,55 @@ void PCSound::stopSound(int channel) {
}
PaulaSound::PaulaSound(Audio::Mixer *mixer, CineEngine *vm)
- : Sound(mixer, vm) {
+ : Sound(mixer, vm), _sfxTimer(0), _musicTimer(0), _musicFadeTimer(0) {
_moduleStream = 0;
+ // The original is using the following timer frequency:
+ // 0.709379Mhz / 8000 = 88.672375Hz
+ // 1000000 / 88.672375Hz = 11277.46944863us
+ g_system->getTimerManager()->installTimerProc(&PaulaSound::sfxTimerProc, 11277, this, "PaulaSound::sfxTimerProc");
+ // The original is using the following timer frequency:
+ // 0.709379Mhz / 14565 = 48.704359Hz
+ // 1000000 / 48.704359Hz = 20532.04313806us
+ g_system->getTimerManager()->installTimerProc(&PaulaSound::musicTimerProc, 20532, this, "PaulaSound::musicTimerProc");
}
PaulaSound::~PaulaSound() {
+ Common::StackLock sfxLock(_sfxMutex);
+ g_system->getTimerManager()->removeTimerProc(&PaulaSound::sfxTimerProc);
for (int i = 0; i < NUM_CHANNELS; ++i) {
stopSound(i);
}
+
+ Common::StackLock musicLock(_musicMutex);
+ g_system->getTimerManager()->removeTimerProc(&PaulaSound::musicTimerProc);
stopMusic();
}
void PaulaSound::loadMusic(const char *name) {
debugC(5, kCineDebugSound, "PaulaSound::loadMusic('%s')", name);
+ for (int i = 0; i < NUM_CHANNELS; ++i) {
+ stopSound(i);
+ }
+
+ // Fade music out when there is music playing.
+ _musicMutex.lock();
+ if (_mixer->isSoundHandleActive(_moduleHandle)) {
+ // Only start fade out when it is not in progress.
+ if (!_musicFadeTimer) {
+ _musicFadeTimer = 1;
+ }
+
+ _musicMutex.unlock();
+ while (_musicFadeTimer != 64) {
+ g_system->delayMillis(50);
+ }
+ } else {
+ _musicMutex.unlock();
+ }
+
+ Common::StackLock lock(_musicMutex);
+ assert(!_mixer->isSoundHandleActive(_moduleHandle));
+
if (_vm->getGameType() == GType_FW) {
// look for separate files
Common::File f;
@@ -1031,54 +1067,135 @@ void PaulaSound::loadMusic(const char *name) {
void PaulaSound::playMusic() {
debugC(5, kCineDebugSound, "PaulaSound::playMusic()");
+ Common::StackLock lock(_musicMutex);
+
_mixer->stopHandle(_moduleHandle);
if (_moduleStream) {
+ _musicFadeTimer = 0;
_mixer->playStream(Audio::Mixer::kMusicSoundType, &_moduleHandle, _moduleStream);
}
}
void PaulaSound::stopMusic() {
debugC(5, kCineDebugSound, "PaulaSound::stopMusic()");
+ Common::StackLock lock(_musicMutex);
+
_mixer->stopHandle(_moduleHandle);
}
void PaulaSound::fadeOutMusic() {
debugC(5, kCineDebugSound, "PaulaSound::fadeOutMusic()");
- // TODO
- stopMusic();
+ Common::StackLock lock(_musicMutex);
+
+ _musicFadeTimer = 1;
}
void PaulaSound::playSound(int channel, int frequency, const uint8 *data, int size, int volumeStep, int stepCount, int volume, int repeat) {
- // TODO: handle volume slides and repeat
debugC(5, kCineDebugSound, "PaulaSound::playSound() channel %d size %d", channel, size);
+ Common::StackLock lock(_sfxMutex);
+ assert(frequency > 0);
+
stopSound(channel);
- size = MIN<int>(size - SPL_HDR_SIZE, READ_BE_UINT16(data + 4));
- // TODO: consider skipping the header in loadSpl directly
if (size > 0) {
byte *sound = (byte *)malloc(size);
if (sound) {
- memcpy(sound, data + SPL_HDR_SIZE, size);
- playSoundChannel(channel, frequency, sound, size, volume);
+ // Create the audio stream
+ memcpy(sound, data, size);
+
+ // Clear the first and last 16 bits like in the original.
+ sound[0] = sound[1] = sound[size - 2] = sound[size - 1] = 0;
+
+ Audio::SeekableAudioStream *stream = Audio::makeRawStream(sound, size, PAULA_FREQ / frequency, 0);
+
+ // Initialize the volume control
+ _channelsTable[channel].initialize(volume, volumeStep, stepCount);
+
+ // Start the sfx
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &_channelsTable[channel].handle,
+ Audio::makeLoopingAudioStream(stream, repeat ? 0 : 1),
+ -1, volume * Audio::Mixer::kMaxChannelVolume / 63,
+ _channelBalance[channel]);
}
}
}
void PaulaSound::stopSound(int channel) {
debugC(5, kCineDebugSound, "PaulaSound::stopSound() channel %d", channel);
- _mixer->stopHandle(_channelsTable[channel]);
+ Common::StackLock lock(_sfxMutex);
+
+ _mixer->stopHandle(_channelsTable[channel].handle);
}
-void PaulaSound::update() {
- // process volume slides and start sound playback
- // TODO
+void PaulaSound::sfxTimerProc(void *param) {
+ PaulaSound *sound = (PaulaSound *)param;
+ sound->sfxTimerCallback();
}
-void PaulaSound::playSoundChannel(int channel, int frequency, uint8 *data, int size, int volume) {
- assert(frequency > 0);
- frequency = PAULA_FREQ / frequency;
- Audio::AudioStream *stream = Audio::makeRawStream(data, size, frequency, 0);
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &_channelsTable[channel], stream);
- _mixer->setChannelVolume(_channelsTable[channel], volume * Audio::Mixer::kMaxChannelVolume / 63);
+void PaulaSound::sfxTimerCallback() {
+ Common::StackLock lock(_sfxMutex);
+
+ if (_sfxTimer < 6) {
+ ++_sfxTimer;
+
+ for (int i = 0; i < NUM_CHANNELS; ++i) {
+ // Only process active channels
+ if (!_mixer->isSoundHandleActive(_channelsTable[i].handle)) {
+ continue;
+ }
+
+ if (_channelsTable[i].curStep) {
+ --_channelsTable[i].curStep;
+ } else {
+ _channelsTable[i].curStep = _channelsTable[i].stepCount;
+ const int volume = CLIP(_channelsTable[i].volume + _channelsTable[i].volumeStep, 0, 63);
+ _channelsTable[i].volume = volume;
+ // Unlike the original we stop silent sounds
+ if (volume) {
+ _mixer->setChannelVolume(_channelsTable[i].handle, volume * Audio::Mixer::kMaxChannelVolume / 63);
+ } else {
+ _mixer->stopHandle(_channelsTable[i].handle);
+ }
+ }
+ }
+ } else {
+ _sfxTimer = 0;
+ // Possible TODO: The original only ever started sounds here. This
+ // should not be noticable though. So we do not do it for now.
+ }
}
+void PaulaSound::musicTimerProc(void *param) {
+ PaulaSound *sound = (PaulaSound *)param;
+ sound->musicTimerCallback();
+}
+
+void PaulaSound::musicTimerCallback() {
+ Common::StackLock lock(_musicMutex);
+
+ ++_musicTimer;
+ if (_musicTimer == 6) {
+ _musicTimer = 0;
+ if (_musicFadeTimer) {
+ ++_musicFadeTimer;
+ if (_musicFadeTimer == 64) {
+ stopMusic();
+ } else {
+ if (_mixer->isSoundHandleActive(_moduleHandle)) {
+ _mixer->setChannelVolume(_moduleHandle, (64 - _musicFadeTimer) * Audio::Mixer::kMaxChannelVolume / 64);
+ }
+ }
+ }
+ }
+}
+
+const int PaulaSound::_channelBalance[NUM_CHANNELS] = {
+ // L/R/R/L This is according to the Hardware Reference Manual.
+ // TODO: It seems the order is swapped for some Amiga models:
+ // http://www.amiga.org/forums/archive/index.php/t-7862.html
+ // Maybe we should consider using R/L/L/R to match Amiga 500?
+ // This also is a bit more drastic to what WineUAE defaults,
+ // which is only 70% of full panning.
+ -127, 127, 127, -127
+};
+
} // End of namespace Cine
diff --git a/engines/cine/sound.h b/engines/cine/sound.h
index afc0994a26..fdb183ad34 100644
--- a/engines/cine/sound.h
+++ b/engines/cine/sound.h
@@ -24,6 +24,7 @@
#define CINE_SOUND_H_
#include "common/util.h"
+#include "common/mutex.h"
#include "audio/mixer.h"
namespace Audio {
@@ -47,7 +48,6 @@ public:
virtual void playSound(int channel, int frequency, const uint8 *data, int size, int volumeStep, int stepCount, int volume, int repeat) = 0;
virtual void stopSound(int channel) = 0;
- virtual void update() {}
protected:
@@ -91,19 +91,39 @@ public:
virtual void playSound(int channel, int frequency, const uint8 *data, int size, int volumeStep, int stepCount, int volume, int repeat);
virtual void stopSound(int channel);
- virtual void update();
enum {
- PAULA_FREQ = 7093789,
- NUM_CHANNELS = 4,
- SPL_HDR_SIZE = 22
+ PAULA_FREQ = 3579545,
+ NUM_CHANNELS = 4
};
protected:
- void playSoundChannel(int channel, int frequency, uint8 *data, int size, int volume);
-
- Audio::SoundHandle _channelsTable[NUM_CHANNELS];
+ struct SfxChannel {
+ Audio::SoundHandle handle;
+ int volume;
+ int volumeStep;
+ int curStep;
+ int stepCount;
+
+ void initialize(int vol, int volStep, int stepCnt) {
+ volume = vol;
+ volumeStep = volStep;
+ curStep = stepCount = stepCnt;
+ }
+ };
+ SfxChannel _channelsTable[NUM_CHANNELS];
+ static const int _channelBalance[NUM_CHANNELS];
+ Common::Mutex _sfxMutex;
+ int _sfxTimer;
+ static void sfxTimerProc(void *param);
+ void sfxTimerCallback();
+
+ Common::Mutex _musicMutex;
+ int _musicTimer;
+ int _musicFadeTimer;
+ static void musicTimerProc(void *param);
+ void musicTimerCallback();
Audio::SoundHandle _moduleHandle;
Audio::AudioStream *_moduleStream;
};
diff --git a/engines/cine/texte.cpp b/engines/cine/texte.cpp
index 33ea569df7..998075c6ce 100644
--- a/engines/cine/texte.cpp
+++ b/engines/cine/texte.cpp
@@ -88,7 +88,7 @@ static const CharacterEntry fontParamTable_standard[NUM_FONT_CHARS] = {
{64, 3}, {65, 3}, { 0, 0}, { 0, 0}, {62, 2}, {74, 6}, {66, 1}, {67, 6},
{52, 6}, {53, 6}, {54, 6}, {55, 6}, {56, 6}, {57, 6}, {58, 6}, {59, 6},
{60, 6}, {61, 6}, {76, 3}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, {75, 6},
- { 0, 0}, { 0, 6}, //a
+ { 0, 0}, { 0, 6}, //a
{ 1, 6}, { 2, 6}, { 3, 6}, { 4, 6}, { 5, 6}, { 6, 6},
{ 7, 6}, { 8, 3}, { 9, 6}, {10, 6}, {11, 6}, {12, 7}, {13, 6}, {14, 6},
{15, 6}, {16, 6}, {17, 6}, {18, 6}, {19, 6}, {20, 6}, {21, 6}, {22, 7},
diff --git a/engines/cine/texte.h b/engines/cine/texte.h
index dd4b7e06ee..185dc53bfd 100644
--- a/engines/cine/texte.h
+++ b/engines/cine/texte.h
@@ -46,7 +46,7 @@ struct CharacterEntry {
};
struct TextHandler {
- byte textTable[NUM_FONT_CHARS][2][FONT_WIDTH * FONT_HEIGHT];
+ byte textTable[NUM_FONT_CHARS][2][FONT_WIDTH *FONT_HEIGHT];
CharacterEntry fontParamTable[NUM_FONT_CHARS];
};
diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp
index eccd71cf05..23f439a7a7 100644
--- a/engines/cine/various.cpp
+++ b/engines/cine/various.cpp
@@ -99,8 +99,7 @@ byte isInPause = 0;
* Bit on = mouse button down
* Bit off = mouse button up
*/
-enum MouseButtonState
-{
+enum MouseButtonState {
kLeftMouseButton = (1 << 0),
kRightMouseButton = (1 << 1)
};
@@ -271,7 +270,7 @@ int16 getObjectUnderCursor(uint16 x, uint16 y) {
} else if (it->type == 1 && gfxGetBit(xdif, ydif, g_cine->_animDataTable[frame].data(), g_cine->_animDataTable[frame]._width * 4)) {
return it->objIdx;
}
- } else if (it->type == 0) { // use generated mask
+ } else if (it->type == 0) { // use generated mask
if (gfxGetBit(xdif, ydif, g_cine->_animDataTable[frame].mask(), g_cine->_animDataTable[frame]._width)) {
return it->objIdx;
}
@@ -358,128 +357,122 @@ void CineEngine::makeSystemMenu() {
systemCommand = makeMenuChoice(systemMenu, numEntry, mouseX, mouseY, 140);
switch (systemCommand) {
- case 0: // Pause
- {
- renderer->drawString(otherMessages[2], 0);
- waitPlayerInput();
- break;
- }
- case 1: // Restart Game
- {
- getMouseData(mouseUpdateStatus, (uint16 *)&mouseButton, (uint16 *)&mouseX, (uint16 *)&mouseY);
- if (!makeMenuChoice(confirmMenu, 2, mouseX, mouseY + 8, 100)) {
- _restartRequested = true;
- }
- break;
- }
- case 2: // Quit
- {
- getMouseData(mouseUpdateStatus, (uint16 *)&mouseButton, (uint16 *)&mouseX, (uint16 *)&mouseY);
- if (!makeMenuChoice(confirmMenu, 2, mouseX, mouseY + 8, 100)) {
- quitGame();
- }
- break;
+ case 0: { // Pause
+ renderer->drawString(otherMessages[2], 0);
+ waitPlayerInput();
+ break;
+ }
+ case 1: { // Restart Game
+ getMouseData(mouseUpdateStatus, (uint16 *)&mouseButton, (uint16 *)&mouseX, (uint16 *)&mouseY);
+ if (!makeMenuChoice(confirmMenu, 2, mouseX, mouseY + 8, 100)) {
+ _restartRequested = true;
}
- case 3: // Select save drive... change ?
- {
- break;
+ break;
+ }
+ case 2: { // Quit
+ getMouseData(mouseUpdateStatus, (uint16 *)&mouseButton, (uint16 *)&mouseX, (uint16 *)&mouseY);
+ if (!makeMenuChoice(confirmMenu, 2, mouseX, mouseY + 8, 100)) {
+ quitGame();
}
- case 4: // load game
- {
- if (loadSaveDirectory()) {
+ break;
+ }
+ case 3: { // Select save drive... change ?
+ break;
+ }
+ case 4: { // load game
+ if (loadSaveDirectory()) {
// int16 selectedSave;
- getMouseData(mouseUpdateStatus, (uint16 *)&mouseButton, (uint16 *)&mouseX, (uint16 *)&mouseY);
- selectedSave = makeMenuChoice(currentSaveName, 10, mouseX, mouseY + 8, 180);
+ getMouseData(mouseUpdateStatus, (uint16 *)&mouseButton, (uint16 *)&mouseX, (uint16 *)&mouseY);
+ selectedSave = makeMenuChoice(currentSaveName, 10, mouseX, mouseY + 8, 180);
- if (selectedSave >= 0) {
- char saveNameBuffer[256];
- sprintf(saveNameBuffer, "%s.%1d", _targetName.c_str(), selectedSave);
+ if (selectedSave >= 0) {
+ char saveNameBuffer[256];
+ sprintf(saveNameBuffer, "%s.%1d", _targetName.c_str(), selectedSave);
- getMouseData(mouseUpdateStatus, (uint16 *)&mouseButton, (uint16 *)&mouseX, (uint16 *)&mouseY);
- if (!makeMenuChoice(confirmMenu, 2, mouseX, mouseY + 8, 100)) {
- char loadString[256];
+ getMouseData(mouseUpdateStatus, (uint16 *)&mouseButton, (uint16 *)&mouseX, (uint16 *)&mouseY);
+ if (!makeMenuChoice(confirmMenu, 2, mouseX, mouseY + 8, 100)) {
+ char loadString[256];
- sprintf(loadString, otherMessages[3], currentSaveName[selectedSave]);
- renderer->drawString(loadString, 0);
+ sprintf(loadString, otherMessages[3], currentSaveName[selectedSave]);
+ renderer->drawString(loadString, 0);
- makeLoad(saveNameBuffer);
- } else {
- renderer->drawString(otherMessages[4], 0);
- waitPlayerInput();
- checkDataDisk(-1);
- }
+ makeLoad(saveNameBuffer);
} else {
renderer->drawString(otherMessages[4], 0);
waitPlayerInput();
checkDataDisk(-1);
}
} else {
- renderer->drawString(otherMessages[5], 0);
+ renderer->drawString(otherMessages[4], 0);
waitPlayerInput();
checkDataDisk(-1);
}
- break;
+ } else {
+ renderer->drawString(otherMessages[5], 0);
+ waitPlayerInput();
+ checkDataDisk(-1);
}
- case 5: // Save game
- {
- loadSaveDirectory();
- selectedSave = makeMenuChoice(currentSaveName, 10, mouseX, mouseY + 8, 180);
+ break;
+ }
+ case 5: { // Save game
+ loadSaveDirectory();
+ selectedSave = makeMenuChoice(currentSaveName, 10, mouseX, mouseY + 8, 180);
- if (selectedSave >= 0) {
- char saveFileName[256];
- char saveName[20];
- saveName[0] = 0;
+ if (selectedSave >= 0) {
+ char saveFileName[256];
+ char saveName[20];
+ saveName[0] = 0;
- if (!makeTextEntryMenu(otherMessages[6], saveName, 20, 120))
- break;
+ if (!makeTextEntryMenu(otherMessages[6], saveName, 20, 120))
+ break;
- strncpy(currentSaveName[selectedSave], saveName, 20);
+ strncpy(currentSaveName[selectedSave], saveName, 20);
- sprintf(saveFileName, "%s.%1d", _targetName.c_str(), selectedSave);
+ sprintf(saveFileName, "%s.%1d", _targetName.c_str(), selectedSave);
- getMouseData(mouseUpdateStatus, (uint16 *)&mouseButton, (uint16 *)&mouseX, (uint16 *)&mouseY);
- if (!makeMenuChoice(confirmMenu, 2, mouseX, mouseY + 8, 100)) {
- char saveString[256];
- Common::String tmp = Common::String::format("%s.dir", _targetName.c_str());
+ getMouseData(mouseUpdateStatus, (uint16 *)&mouseButton, (uint16 *)&mouseX, (uint16 *)&mouseY);
+ if (!makeMenuChoice(confirmMenu, 2, mouseX, mouseY + 8, 100)) {
+ char saveString[256];
+ Common::String tmp = Common::String::format("%s.dir", _targetName.c_str());
- Common::OutSaveFile *fHandle = _saveFileMan->openForSaving(tmp);
- if (!fHandle) {
- warning("Unable to open file %s for saving", tmp.c_str());
- break;
- }
+ Common::OutSaveFile *fHandle = _saveFileMan->openForSaving(tmp);
+ if (!fHandle) {
+ warning("Unable to open file %s for saving", tmp.c_str());
+ break;
+ }
- fHandle->write(currentSaveName, 200);
- delete fHandle;
+ fHandle->write(currentSaveName, 200);
+ delete fHandle;
- sprintf(saveString, otherMessages[3], currentSaveName[selectedSave]);
- renderer->drawString(saveString, 0);
+ sprintf(saveString, otherMessages[3], currentSaveName[selectedSave]);
+ renderer->drawString(saveString, 0);
- makeSave(saveFileName);
+ makeSave(saveFileName);
- checkDataDisk(-1);
- } else {
- renderer->drawString(otherMessages[4], 0);
- waitPlayerInput();
- checkDataDisk(-1);
- }
+ checkDataDisk(-1);
+ } else {
+ renderer->drawString(otherMessages[4], 0);
+ waitPlayerInput();
+ checkDataDisk(-1);
}
- break;
}
+ break;
+ }
}
inMenu = false;
}
}
-void drawMessageBox(int16 x, int16 y, int16 width, int16 currentY, int16 offset, int16 color, byte* page) {
- gfxDrawLine(x + offset, y + offset, x + width - offset, y + offset, color, page); // top
- gfxDrawLine(x + offset, currentY + 4 - offset, x + width - offset, currentY + 4 - offset, color, page); // bottom
- gfxDrawLine(x + offset, y + offset, x + offset, currentY + 4 - offset, color, page); // left
- gfxDrawLine(x + width - offset, y + offset, x + width - offset, currentY + 4 - offset, color, page); // right
+void drawMessageBox(int16 x, int16 y, int16 width, int16 currentY, int16 offset, int16 color, byte *page) {
+ gfxDrawLine(x + offset, y + offset, x + width - offset, y + offset, color, page); // top
+ gfxDrawLine(x + offset, currentY + 4 - offset, x + width - offset, currentY + 4 - offset, color, page); // bottom
+ gfxDrawLine(x + offset, y + offset, x + offset, currentY + 4 - offset, color, page); // left
+ gfxDrawLine(x + width - offset, y + offset, x + width - offset, currentY + 4 - offset, color, page); // right
}
-void drawDoubleMessageBox(int16 x, int16 y, int16 width, int16 currentY, int16 color, byte* page) {
+void drawDoubleMessageBox(int16 x, int16 y, int16 width, int16 currentY, int16 color, byte *page) {
drawMessageBox(x, y, width, currentY, 1, 0, page);
drawMessageBox(x, y, width, currentY, 0, color, page);
}
@@ -581,7 +574,7 @@ void makeCommandLine() {
g_cine->_commandBuffer = "";
}
- if ((playerCommand != -1) && (choiceResultTable[playerCommand] == 2)) { // need object selection ?
+ if ((playerCommand != -1) && (choiceResultTable[playerCommand] == 2)) { // need object selection?
int16 si;
getMouseData(mouseUpdateStatus, &dummyU16, &x, &y);
@@ -635,7 +628,7 @@ void makeCommandLine() {
}
if (g_cine->getGameType() == Cine::GType_OS && playerCommand != 2) {
- if (playerCommand != -1 && canUseOnObject != 0) { // call use on sub object
+ if (playerCommand != -1 && canUseOnObject != 0) { // call use on sub object
int16 si;
getMouseData(mouseUpdateStatus, &dummyU16, &x, &y);
@@ -742,11 +735,11 @@ int16 makeMenuChoice(const CommandeType commandList[], uint16 height, uint16 X,
mainLoopSub6();
}
- if (menuVar4 && currentSelection > 0) { // go up
+ if (menuVar4 && currentSelection > 0) { // go up
currentSelection--;
}
- if (menuVar5) { // go down
+ if (menuVar5) { // go down
if (height - 1 > currentSelection) {
currentSelection++;
}
@@ -763,7 +756,7 @@ int16 makeMenuChoice(const CommandeType commandList[], uint16 height, uint16 X,
}
}
- if (currentSelection != oldSelection) { // old != new
+ if (currentSelection != oldSelection) { // old != new
if (needMouseSave) {
hideMouse();
}
@@ -789,7 +782,7 @@ int16 makeMenuChoice(const CommandeType commandList[], uint16 height, uint16 X,
getMouseData(mouseUpdateStatus, &button, &dummyU16, &dummyU16);
} while (button && !g_cine->shouldQuit());
- if (var_4 == 2) { // recheck
+ if (var_4 == 2) { // recheck
if (!recheckValue)
return -1;
else
@@ -809,7 +802,7 @@ void makeActionMenu() {
getMouseData(mouseUpdateStatus, &mouseButton, &mouseX, &mouseY);
if (g_cine->getGameType() == Cine::GType_OS) {
- if(disableSystemMenu == 0) {
+ if (disableSystemMenu == 0) {
playerCommand = makeMenuChoice(defaultActionCommand, 6, mouseX, mouseY, 70, true);
}
@@ -818,7 +811,7 @@ void makeActionMenu() {
canUseOnObject = canUseOnItemTable[playerCommand];
}
} else {
- if(disableSystemMenu == 0) {
+ if (disableSystemMenu == 0) {
playerCommand = makeMenuChoice(defaultActionCommand, 6, mouseX, mouseY, 70);
}
}
@@ -1185,7 +1178,7 @@ void removeMessages() {
Common::List<overlay>::iterator it;
bool remove;
- for (it = g_cine->_overlayList.begin(); it != g_cine->_overlayList.end(); ) {
+ for (it = g_cine->_overlayList.begin(); it != g_cine->_overlayList.end();) {
if (g_cine->getGameType() == Cine::GType_OS) {
// NOTE: These are really removeOverlay calls that have been deferred.
// In Operation Stealth's disassembly elements are removed from the
@@ -1348,7 +1341,7 @@ void modifySeqListElement(uint16 objIdx, int16 var4Test, int16 param1, int16 par
}
void computeMove1(SeqListElement &element, int16 x, int16 y, int16 param1,
- int16 param2, int16 x2, int16 y2) {
+ int16 param2, int16 x2, int16 y2) {
element.var16 = 0;
element.var14 = 0;
@@ -1397,7 +1390,7 @@ uint16 addAni(uint16 param1, uint16 objIdx, const int8 *ptr, SeqListElement &ele
int16 di;
debug(5, "addAni: param1 = %d, objIdx = %d, ptr = %p, element.var8 = %d, element.var14 = %d param3 = %d",
- param1, objIdx, ptr, element.var8, element.var14, param3);
+ param1, objIdx, ptr, element.var8, element.var14, param3);
// In the original an error string is set and 0 is returned if the following doesn't hold
assert(ptr);
@@ -1413,16 +1406,16 @@ uint16 addAni(uint16 param1, uint16 objIdx, const int8 *ptr, SeqListElement &ele
di = (g_cine->_objectTable[objIdx].costume + 1) % (*ptrData);
++ptrData; // Jump over the just read byte
// Here ptr2 seems to be indexing a table of structs (8 bytes per struct):
- // struct {
- // int8 x; // 0 (Used with checkCollision)
- // int8 y; // 1 (Used with checkCollision)
- // int8 numZones; // 2 (Used with checkCollision)
- // int8 var3; // 3 (Not used in this function)
- // int8 xAdd; // 4 (Used with an object)
- // int8 yAdd; // 5 (Used with an object)
- // int8 maskAdd; // 6 (Used with an object)
- // int8 frameAdd; // 7 (Used with an object)
- // };
+ // struct {
+ // int8 x; // 0 (Used with checkCollision)
+ // int8 y; // 1 (Used with checkCollision)
+ // int8 numZones; // 2 (Used with checkCollision)
+ // int8 var3; // 3 (Not used in this function)
+ // int8 xAdd; // 4 (Used with an object)
+ // int8 yAdd; // 5 (Used with an object)
+ // int8 maskAdd; // 6 (Used with an object)
+ // int8 frameAdd; // 7 (Used with an object)
+ // };
ptr2 = ptrData + di * 8;
// We might probably safely discard the AND by 1 here because
@@ -1572,8 +1565,7 @@ void processSeqListElement(SeqListElement &element) {
var_4 = -1;
if ((element.var16 == 1
- && !addAni(3, element.objIdx, ptr1, element, 0, &var_4)) || (element.var16 == 2 && !addAni(2, element.objIdx, ptr1, element, 0,
- &var_4))) {
+ && !addAni(3, element.objIdx, ptr1, element, 0, &var_4)) || (element.var16 == 2 && !addAni(2, element.objIdx, ptr1, element, 0, &var_4))) {
if (element.varC == 255) {
g_cine->_globalVars[VAR_MOUSE_Y_POS] = 0;
}
@@ -1702,9 +1694,9 @@ bool makeTextEntryMenu(const char *messagePtr, char *inputString, int stringMaxL
}
break;
default:
- if (((keycode >= 'a') && (keycode <='z')) ||
- ((keycode >= '0') && (keycode <='9')) ||
- ((keycode >= 'A') && (keycode <='Z')) ||
+ if (((keycode >= 'a') && (keycode <= 'z')) ||
+ ((keycode >= '0') && (keycode <= '9')) ||
+ ((keycode >= 'A') && (keycode <= 'Z')) ||
(keycode == ' ')) {
if (inputLength < stringMaxLength - 1) {
ch[0] = keycode;
diff --git a/engines/composer/composer.cpp b/engines/composer/composer.cpp
index 23a9d2ff85..5db778dfda 100644
--- a/engines/composer/composer.cpp
+++ b/engines/composer/composer.cpp
@@ -20,7 +20,7 @@
*
*/
#include "common/scummsys.h"
-
+
#include "common/config-manager.h"
#include "common/events.h"
#include "common/file.h"
@@ -102,13 +102,14 @@ Common::Error ComposerEngine::run() {
if (_bookIni.hasKey("Height", "Common"))
height = atoi(getStringFromConfig("Common", "Height").c_str());
initGraphics(width, height, true);
- _surface.create(width, height, Graphics::PixelFormat::createFormatCLUT8());
+ _screen.create(width, height, Graphics::PixelFormat::createFormatCLUT8());
_needsUpdate = true;
Graphics::Cursor *cursor = Graphics::makeDefaultWinCursor();
CursorMan.replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(), cursor->getHotspotX(),
cursor->getHotspotY(), cursor->getKeyColor());
CursorMan.replaceCursorPalette(cursor->getPalette(), cursor->getPaletteStartIndex(), cursor->getPaletteCount());
+ delete cursor;
loadLibrary(0);
@@ -213,6 +214,8 @@ Common::Error ComposerEngine::run() {
_system->delayMillis(20);
}
+ _screen.free();
+
return Common::kNoError;
}
diff --git a/engines/composer/composer.h b/engines/composer/composer.h
index 0f53258289..33a5356b3a 100644
--- a/engines/composer/composer.h
+++ b/engines/composer/composer.h
@@ -170,7 +170,7 @@ private:
bool _needsUpdate;
Common::Array<Common::Rect> _dirtyRects;
- Graphics::Surface _surface;
+ Graphics::Surface _screen;
Common::List<Sprite> _sprites;
uint _directoriesToStrip;
diff --git a/engines/composer/graphics.cpp b/engines/composer/graphics.cpp
index 1314e903ae..2b68fac233 100644
--- a/engines/composer/graphics.cpp
+++ b/engines/composer/graphics.cpp
@@ -507,7 +507,7 @@ const Sprite *ComposerEngine::getSpriteAtPos(const Common::Point &pos) {
void ComposerEngine::dirtySprite(const Sprite &sprite) {
Common::Rect rect(sprite._pos.x, sprite._pos.y, sprite._pos.x + sprite._surface.w, sprite._pos.y + sprite._surface.h);
- rect.clip(_surface.w, _surface.h);
+ rect.clip(_screen.w, _screen.h);
if (rect.isEmpty())
return;
@@ -541,8 +541,8 @@ void ComposerEngine::redraw() {
for (uint i = 0; i < _dirtyRects.size(); i++) {
const Common::Rect &rect = _dirtyRects[i];
- byte *pixels = (byte *)_surface.pixels + (rect.top * _surface.pitch) + rect.left;
- _system->copyRectToScreen(pixels, _surface.pitch, rect.left, rect.top, rect.width(), rect.height());
+ byte *pixels = (byte *)_screen.pixels + (rect.top * _screen.pitch) + rect.left;
+ _system->copyRectToScreen(pixels, _screen.pitch, rect.left, rect.top, rect.width(), rect.height());
}
_system->updateScreen();
@@ -814,16 +814,16 @@ void ComposerEngine::drawSprite(const Sprite &sprite) {
int y = sprite._pos.y;
// incoming data is BMP-style (bottom-up), so flip it
- byte *pixels = (byte *)_surface.pixels;
+ byte *pixels = (byte *)_screen.pixels;
for (int j = 0; j < sprite._surface.h; j++) {
if (j + y < 0)
continue;
- if (j + y >= _surface.h)
+ if (j + y >= _screen.h)
break;
byte *in = (byte *)sprite._surface.pixels + (sprite._surface.h - j - 1) * sprite._surface.w;
- byte *out = pixels + ((j + y) * _surface.w) + x;
+ byte *out = pixels + ((j + y) * _screen.w) + x;
for (int i = 0; i < sprite._surface.w; i++)
- if ((x + i >= 0) && (x + i < _surface.w) && in[i])
+ if ((x + i >= 0) && (x + i < _screen.w) && in[i])
out[i] = in[i];
}
}
diff --git a/engines/composer/resource.cpp b/engines/composer/resource.cpp
index a4e292747c..83e49971fb 100644
--- a/engines/composer/resource.cpp
+++ b/engines/composer/resource.cpp
@@ -240,7 +240,7 @@ bool ComposerArchive::openStream(Common::SeekableReadStream *stream) {
res.flags = flags;
debug(4, "Id %d, offset %d, size %d, flags %08x", id, offset, size, flags);
}
-
+
stream->seek(oldPos);
}
diff --git a/engines/configure.engines b/engines/configure.engines
index e0052c52ee..e17e2f67e0 100644
--- a/engines/configure.engines
+++ b/engines/configure.engines
@@ -1,9 +1,10 @@
# This file is included from the main "configure" script
-add_engine scumm "SCUMM" yes "scumm_7_8 he"
+# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
+add_engine scumm "SCUMM" yes "scumm_7_8 he" "v0-v6 games"
add_engine scumm_7_8 "v7 & v8 games" yes
add_engine he "HE71+ games" yes
add_engine agi "AGI" yes
-add_engine agos "AGOS" yes "agos2"
+add_engine agos "AGOS" yes "agos2" "AGOS 1 games"
add_engine agos2 "AGOS 2 games" yes
add_engine cge "CGE" yes
add_engine cine "Cinematique evo 1" yes
@@ -13,38 +14,39 @@ add_engine draci "Dragon History" yes
add_engine drascula "Drascula: The Vampire Strikes Back" yes
add_engine dreamweb "Dreamweb" yes
add_engine gob "Gobli*ns" yes
-add_engine groovie "Groovie" yes "groovie2"
+add_engine groovie "Groovie" yes "groovie2" "7th Guest"
add_engine groovie2 "Groovie 2 games" no
add_engine hopkins "Hopkins FBI" no
add_engine hugo "Hugo Trilogy" yes
-add_engine kyra "Legend of Kyrandia" yes "lol eob"
+add_engine kyra "Kyra" yes "lol eob" "Legend of Kyrandia 1-3"
add_engine lol "Lands of Lore" yes
add_engine eob "Eye of the Beholder" no
-add_engine lastexpress "The Last Express" no
+add_engine lastexpress "The Last Express" no "" "" "16bit"
add_engine lure "Lure of the Temptress" yes
add_engine made "MADE" yes
-add_engine mohawk "Mohawk" yes "cstime myst riven"
+add_engine mohawk "Mohawk" yes "cstime myst riven" "Living Books"
add_engine cstime "Where in Time is Carmen Sandiego?" no
-add_engine riven "Riven: The Sequel to Myst" no
-add_engine myst "Myst" no
+add_engine riven "Riven: The Sequel to Myst" no "" "" "16bit"
+add_engine myst "Myst" no "" "" "16bit"
add_engine parallaction "Parallaction" yes
+add_engine pegasus "The Journeyman Project: Pegasus Prime" no "" "" "16bit"
add_engine queen "Flight of the Amazon Queen" yes
-add_engine saga "SAGA" yes "ihnm saga2"
+add_engine saga "SAGA" yes "ihnm saga2" "ITE"
add_engine ihnm "IHNM" yes
add_engine saga2 "SAGA 2 games" no
-add_engine sci "SCI" yes "sci32"
+add_engine sci "SCI" yes "sci32" "SCI 0-1.1 games"
add_engine sci32 "SCI32 games" no
add_engine sky "Beneath a Steel Sky" yes
add_engine sword1 "Broken Sword" yes
add_engine sword2 "Broken Sword II" yes
-add_engine sword25 "Broken Sword 2.5" no "" "png zlib"
+add_engine sword25 "Broken Sword 2.5" no "" "" "png zlib 16bit"
add_engine teenagent "Teen Agent" yes
add_engine testbed "TestBed: the Testing framework" no
add_engine tinsel "Tinsel" yes
add_engine toltecs "3 Skulls of the Toltecs" no
add_engine toon "Toonstruck" yes
add_engine touche "Touche: The Adventures of the Fifth Musketeer" yes
-add_engine tony "Tony Tough and the Night of Roasted Moths" no
+add_engine tony "Tony Tough and the Night of Roasted Moths" yes "" "" "16bit"
add_engine tsage "TsAGE" yes
add_engine tucker "Bud Tucker in Double Trouble" yes
-add_engine wintermute "Wintermute" no "" "png zlib vorbis"
+add_engine wintermute "Wintermute" no "" "" "png zlib vorbis 16bit"
diff --git a/engines/cruise/detection.cpp b/engines/cruise/detection.cpp
index cbe17ea4d3..ba79df4822 100644
--- a/engines/cruise/detection.cpp
+++ b/engines/cruise/detection.cpp
@@ -295,7 +295,7 @@ void CruiseMetaEngine::removeSaveState(const char *target, int slot) const {
SaveStateDescriptor CruiseMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(
Cruise::CruiseEngine::getSavegameFile(slot));
-
+
if (f) {
Cruise::CruiseSavegameHeader header;
Cruise::readSavegameHeader(f, header);
diff --git a/engines/dialogs.cpp b/engines/dialogs.cpp
index cf3dfaa44b..c884075093 100644
--- a/engines/dialogs.cpp
+++ b/engines/dialogs.cpp
@@ -229,7 +229,7 @@ void MainMenuDialog::save() {
"Please consult the README for basic information, and for "
"instructions on how to obtain further assistance."), status.getDesc().c_str());
GUI::MessageDialog dialog(failMessage);
- dialog.runModal();
+ dialog.runModal();
}
close();
diff --git a/engines/draci/detection.cpp b/engines/draci/detection.cpp
index 61705a1e59..2d78d05933 100644
--- a/engines/draci/detection.cpp
+++ b/engines/draci/detection.cpp
@@ -153,7 +153,7 @@ void DraciMetaEngine::removeSaveState(const char *target, int slot) const {
SaveStateDescriptor DraciMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(
Draci::DraciEngine::getSavegameFile(slot));
-
+
if (f) {
Draci::DraciSavegameHeader header;
Draci::readSavegameHeader(f, header);
diff --git a/engines/drascula/detection.cpp b/engines/drascula/detection.cpp
index 6e38d49b94..760d8b7d98 100644
--- a/engines/drascula/detection.cpp
+++ b/engines/drascula/detection.cpp
@@ -284,7 +284,7 @@ public:
Common::StringArray filenames = saveFileMan->listSavefiles(pattern);
Common::Array<int> slots;
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
-
+
// Obtain the last 2 digits of the filename, since they correspond to the save slot
int slotNum = atoi(file->c_str() + file->size() - 2);
@@ -299,7 +299,7 @@ public:
// Load save index
Common::String fileEpa = Common::String::format("%s.epa", target);
- Common::InSaveFile *epa = saveFileMan->openForLoading(fileEpa);
+ Common::InSaveFile *epa = saveFileMan->openForLoading(fileEpa);
// Get savegame names from index
Common::String saveDesc;
@@ -307,19 +307,19 @@ public:
int line = 1;
for (size_t i = 0; i < slots.size(); i++) {
// ignore lines corresponding to unused saveslots
- for (; line < slots[i]; line++)
- epa->readLine();
+ for (; line < slots[i]; line++)
+ epa->readLine();
// copy the name in the line corresponding to the save slot and truncate to 22 characters
saveDesc = Common::String(epa->readLine().c_str(), 22);
// handle cases where the save directory and save index are detectably out of sync
- if (saveDesc == "*")
+ if (saveDesc == "*")
saveDesc = "No name specified.";
// increment line number to keep it in sync with slot number
- line++;
-
+ line++;
+
// Insert savegame name into list
saveList.push_back(SaveStateDescriptor(slots[i], saveDesc));
}
diff --git a/engines/dreamweb/dreamweb.cpp b/engines/dreamweb/dreamweb.cpp
index 0ca98d5a7b..5f5d627553 100644
--- a/engines/dreamweb/dreamweb.cpp
+++ b/engines/dreamweb/dreamweb.cpp
@@ -516,7 +516,7 @@ uint8 DreamWebEngine::modifyChar(uint8 c) const {
case Common::IT_ITA:
switch(c) {
case 133:
- return 'Z' + 1;
+ return 'Z' + 1;
case 130:
return 'Z' + 2;
case 138:
@@ -548,10 +548,10 @@ uint8 DreamWebEngine::modifyChar(uint8 c) const {
return c;
}
}
-
+
Common::String DreamWebEngine::modifyFileName(const char *name) {
Common::String fileName(name);
-
+
// Sanity check
if (!fileName.hasPrefix("DREAMWEB."))
return fileName;
diff --git a/engines/dreamweb/dreamweb.h b/engines/dreamweb/dreamweb.h
index 1f6deb8566..a4597b1867 100644
--- a/engines/dreamweb/dreamweb.h
+++ b/engines/dreamweb/dreamweb.h
@@ -196,7 +196,7 @@ protected:
// from monitor.cpp
char _inputLine[64];
- char _operand1[14];
+ char _operand1[64];
char _currentFile[14];
// from newplace.cpp
diff --git a/engines/dreamweb/monitor.cpp b/engines/dreamweb/monitor.cpp
index 4e9d8eecc1..1886a80b6a 100644
--- a/engines/dreamweb/monitor.cpp
+++ b/engines/dreamweb/monitor.cpp
@@ -194,7 +194,7 @@ void DreamWebEngine::printLogo() {
}
void DreamWebEngine::input() {
- memset(_inputLine, 0, 64);
+ memset(_inputLine, 0, sizeof(_inputLine));
_curPos = 0;
printChar(_monitorCharset, _monAdX, _monAdY, '>', 0, NULL, NULL);
multiDump(_monAdX, _monAdY, 6, 8);
@@ -665,7 +665,7 @@ void DreamWebEngine::searchForFiles(const char *filesString) {
const char *DreamWebEngine::parser() {
char *output = _operand1;
- memset(output, 0, 14);
+ memset(output, 0, sizeof(_operand1));
*output++ = '=';
diff --git a/engines/dreamweb/object.cpp b/engines/dreamweb/object.cpp
index b42591ef91..1e84aba6bd 100644
--- a/engines/dreamweb/object.cpp
+++ b/engines/dreamweb/object.cpp
@@ -516,7 +516,7 @@ void DreamWebEngine::inToInv() {
if (_mouseButton == _oldButton || !(_mouseButton & 1))
return; // notletgo2
-
+
delPointer();
DynObject *object = getExAd(_itemFrame);
object->mapad[0] = 4;
@@ -1034,7 +1034,7 @@ void DreamWebEngine::fillOpen() {
size = 4;
findAllOpen();
for (uint8 i = 0; i < size; ++i) {
- uint8 index = _openInvList[i]._index;
+ uint8 index = _openInvList[i]._index;
uint8 type = _openInvList[i]._type;
obToInv(index, type, kInventx + i * kItempicsize, kInventy + 96);
}
diff --git a/engines/dreamweb/people.cpp b/engines/dreamweb/people.cpp
index 36a756a49b..dbb81406cd 100644
--- a/engines/dreamweb/people.cpp
+++ b/engines/dreamweb/people.cpp
@@ -411,7 +411,7 @@ void DreamWebEngine::interviewer(ReelRoutine &routine) {
if (routine.reelPointer() != 250 && routine.reelPointer() != 259 && checkSpeed(routine))
routine.incReelPointer();
-
+
showGameReel(&routine);
}
@@ -745,7 +745,7 @@ void DreamWebEngine::introMonks2(ReelRoutine &routine) {
if (nextReelPointer == 110) {
_introCount++;
monks2text();
-
+
if (_introCount == 35)
nextReelPointer = 111;
else
@@ -895,7 +895,7 @@ void DreamWebEngine::helicopter(ReelRoutine &routine) {
nextReelPointer = 9;
}
}
- }
+ }
routine.setReelPointer(nextReelPointer);
}
@@ -1002,7 +1002,7 @@ void DreamWebEngine::businessMan(ReelRoutine &routine) {
nextReelPointer = 92;
}
}
-
+
routine.setReelPointer(nextReelPointer);
}
@@ -1037,7 +1037,7 @@ void DreamWebEngine::endGameSeq(ReelRoutine &routine) {
showGameReel(&routine);
routine.mapY = _mapY;
-
+
if (routine.reelPointer() == 145) {
routine.setReelPointer(146);
rollEndCreditsGameWon();
@@ -1070,7 +1070,7 @@ void DreamWebEngine::poolGuard(ReelRoutine &routine) {
if (checkSpeed(routine)) {
uint16 nextReelPointer = routine.reelPointer() + 1;
-
+
if (nextReelPointer != 122) {
// Not end guard 1
if (nextReelPointer == 147) {
@@ -1103,12 +1103,12 @@ void DreamWebEngine::poolGuard(ReelRoutine &routine) {
}
}
}
-
+
routine.setReelPointer(nextReelPointer);
}
showGameReel(&routine);
-
+
if (routine.reelPointer() != 121 && routine.reelPointer() != 146) {
_pointerMode = 0;
_vars._watchingTime = 2;
diff --git a/engines/dreamweb/print.cpp b/engines/dreamweb/print.cpp
index 3a2c45e07b..64b9849980 100644
--- a/engines/dreamweb/print.cpp
+++ b/engines/dreamweb/print.cpp
@@ -212,7 +212,7 @@ const char *DreamWebEngine::monPrint(const char *string) {
while (!done) {
uint16 count = getNumber(_monitorCharset, (const uint8 *)iterator, 166, false, &x);
- do {
+ do {
char c = *iterator++;
if (c == ':')
break;
diff --git a/engines/dreamweb/sprite.cpp b/engines/dreamweb/sprite.cpp
index 5b6cf6a6ac..01570c907a 100644
--- a/engines/dreamweb/sprite.cpp
+++ b/engines/dreamweb/sprite.cpp
@@ -52,7 +52,7 @@ void DreamWebEngine::printASprite(const Sprite *sprite) {
} else {
x = sprite->x + _mapAdX;
}
-
+
uint8 c;
if (sprite->walkFrame != 0)
c = 8;
@@ -97,7 +97,7 @@ void DreamWebEngine::spriteUpdate() {
else {
backObject(&sprite);
}
-
+
if (_nowInNewRoom == 1)
break;
}
@@ -373,7 +373,7 @@ void DreamWebEngine::lockedDoorway(Sprite *sprite, SetObject *objData) {
if (sprite->animFrame != 0)
--sprite->animFrame;
-
+
_vars._throughDoor = 0;
sprite->frameNumber = objData->index = objData->frames[sprite->animFrame];
@@ -407,7 +407,7 @@ void DreamWebEngine::liftSprite(Sprite *sprite, SetObject *objData) {
}
sprite->animFrame = 12;
sprite->frameNumber = objData->index = objData->frames[sprite->animFrame];
- }
+ }
else if (liftFlag == 3) { //openlift
if (sprite->animFrame == 12) {
_vars._liftFlag = 1;
@@ -672,7 +672,7 @@ static const ReelSound g_roomSound6[] = {
{ 255,0 }
};
static const ReelSound g_roomSound8[] = {
-
+
{ 12, 51 },
{ 13, 53 },
{ 14, 14 },
@@ -691,7 +691,7 @@ static const ReelSound g_roomSound10[] = {
{ 13, 16 },
{ 255,0 }
};
-
+
static const ReelSound g_roomSound11[] = {
{ 13, 20 },
{ 255,0 }
@@ -779,7 +779,7 @@ static const ReelSound g_roomSound26[] = {
{ 15, 102 }, // was 90, should be mine cart
{ 255,0 }
};
-
+
static const ReelSound g_roomSound27[] = {
{ 22, 36 },
{ 13, 125 },
diff --git a/engines/dreamweb/vgagrafx.cpp b/engines/dreamweb/vgagrafx.cpp
index ec306c4924..d2390fb1fd 100644
--- a/engines/dreamweb/vgagrafx.cpp
+++ b/engines/dreamweb/vgagrafx.cpp
@@ -23,6 +23,7 @@
#include "dreamweb/dreamweb.h"
#include "engines/util.h"
#include "graphics/surface.h"
+#include "graphics/decoders/pcx.h"
namespace DreamWeb {
@@ -152,70 +153,33 @@ void DreamWebEngine::setMode() {
void DreamWebEngine::showPCX(const Common::String &suffix) {
Common::String name = getDatafilePrefix() + suffix;
Common::File pcxFile;
-
if (!pcxFile.open(name)) {
warning("showpcx: Could not open '%s'", name.c_str());
return;
}
- uint8 *mainGamePal;
- int i, j;
+ Graphics::PCXDecoder pcx;
+ if (!pcx.loadStream(pcxFile)) {
+ warning("showpcx: Could not process '%s'", name.c_str());
+ return;
+ }
// Read the 16-color palette into the 'maingamepal' buffer. Note that
// the color components have to be adjusted from 8 to 6 bits.
-
- pcxFile.seek(16, SEEK_SET);
- mainGamePal = _mainPal;
- pcxFile.read(mainGamePal, 48);
-
- memset(mainGamePal + 48, 0xff, 720);
- for (i = 0; i < 48; i++) {
- mainGamePal[i] >>= 2;
+ memset(_mainPal, 0xff, 256 * 3);
+ memcpy(_mainPal, pcx.getPalette(), 48);
+ for (int i = 0; i < 48; i++) {
+ _mainPal[i] >>= 2;
}
- // Decode the image data.
-
Graphics::Surface *s = g_system->lockScreen();
- Common::Rect rect(640, 480);
-
- s->fillRect(rect, 0);
- pcxFile.seek(128, SEEK_SET);
-
- for (int y = 0; y < 480; y++) {
- byte *dst = (byte *)s->getBasePtr(0, y);
- int decoded = 0;
-
- while (decoded < 320) {
- byte col = pcxFile.readByte();
- byte len;
-
- if ((col & 0xc0) == 0xc0) {
- len = col & 0x3f;
- col = pcxFile.readByte();
- } else {
- len = 1;
- }
-
- // The image uses 16 colors and is stored as four bit
- // planes, one for each bit of the color, least
- // significant bit plane first.
-
- for (i = 0; i < len; i++) {
- int plane = decoded / 80;
- int pos = decoded % 80;
-
- for (j = 0; j < 8; j++) {
- byte bit = (col >> (7 - j)) & 1;
- dst[8 * pos + j] |= (bit << plane);
- }
-
- decoded++;
- }
- }
- }
-
+ s->fillRect(Common::Rect(640, 480), 0);
+ const Graphics::Surface *pcxSurface = pcx.getSurface();
+ if (pcxSurface->format.bytesPerPixel != 1)
+ error("Invalid bytes per pixel in PCX surface (%d)", pcxSurface->format.bytesPerPixel);
+ for (uint16 y = 0; y < pcxSurface->h; y++)
+ memcpy((byte *)s->getBasePtr(0, y), pcxSurface->getBasePtr(0, y), pcxSurface->w);
g_system->unlockScreen();
- pcxFile.close();
}
void DreamWebEngine::frameOutV(uint8 *dst, const uint8 *src, uint16 pitch, uint16 width, uint16 height, int16 x, int16 y) {
@@ -370,9 +334,9 @@ void DreamWebEngine::zoom() {
for (size_t j = 0; j < 23; ++j) {
uint8 v = src[j];
dst[2*j+0] = v;
- dst[2*j+1] = v;
+ dst[2*j+1] = v;
dst[2*j+320] = v;
- dst[2*j+321] = v;
+ dst[2*j+321] = v;
}
src += 320;
dst += 320*2;
diff --git a/engines/engines.mk b/engines/engines.mk
index 6022a05f8a..bcf97df991 100644
--- a/engines/engines.mk
+++ b/engines/engines.mk
@@ -135,6 +135,11 @@ DEFINES += -DENABLE_PARALLACTION=$(ENABLE_PARALLACTION)
MODULES += engines/parallaction
endif
+ifdef ENABLE_PEGASUS
+DEFINES += -DENABLE_PEGASUS=$(ENABLE_PEGASUS)
+MODULES += engines/pegasus
+endif
+
ifdef ENABLE_QUEEN
DEFINES += -DENABLE_QUEEN=$(ENABLE_QUEEN)
MODULES += engines/queen
diff --git a/engines/groovie/detection.cpp b/engines/groovie/detection.cpp
index 1a3b313649..895686b5e0 100644
--- a/engines/groovie/detection.cpp
+++ b/engines/groovie/detection.cpp
@@ -142,7 +142,7 @@ static const GroovieGameDescription gameDescriptions[] = {
{
"11h", "Demo",
AD_ENTRY1s("disk.1", "aacb32ce07e0df2894bd83a3dee40c12", 70),
- Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO | ADGF_UNSTABLE,
+ Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO | ADGF_UNSTABLE,
GUIO5(GUIO_NOLAUNCHLOAD, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT)
},
kGroovieV2, 1
diff --git a/engines/groovie/roq.cpp b/engines/groovie/roq.cpp
index 35d7ecf886..72a61fefb2 100644
--- a/engines/groovie/roq.cpp
+++ b/engines/groovie/roq.cpp
@@ -288,19 +288,18 @@ bool ROQPlayer::processBlockInfo(ROQBlockHeader &blockHeader) {
// them it should be just fine.
_currBuf->create(width, height, Graphics::PixelFormat(3, 0, 0, 0, 0, 0, 0, 0, 0));
_prevBuf->create(width, height, Graphics::PixelFormat(3, 0, 0, 0, 0, 0, 0, 0, 0));
+ }
- // Clear the buffers with black YUV values
- byte *ptr1 = (byte *)_currBuf->getBasePtr(0, 0);
- byte *ptr2 = (byte *)_prevBuf->getBasePtr(0, 0);
- for (int i = 0; i < width * height; i++) {
- *ptr1++ = 0;
- *ptr1++ = 128;
- *ptr1++ = 128;
- *ptr2++ = 0;
- *ptr2++ = 128;
- *ptr2++ = 128;
- }
-
+ // Clear the buffers with black YUV values
+ byte *ptr1 = (byte *)_currBuf->getBasePtr(0, 0);
+ byte *ptr2 = (byte *)_prevBuf->getBasePtr(0, 0);
+ for (int i = 0; i < width * height; i++) {
+ *ptr1++ = 0;
+ *ptr1++ = 128;
+ *ptr1++ = 128;
+ *ptr2++ = 0;
+ *ptr2++ = 128;
+ *ptr2++ = 128;
}
return true;
@@ -405,7 +404,7 @@ void ROQPlayer::processBlockQuadVectorBlock(int baseX, int baseY, int8 Mx, int8
}
void ROQPlayer::processBlockQuadVectorBlockSub(int baseX, int baseY, int8 Mx, int8 My) {
- debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Processing quad vector sub block");
+ debugC(6, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Processing quad vector sub block");
uint16 codingType = getCodingType();
switch (codingType) {
@@ -433,7 +432,7 @@ void ROQPlayer::processBlockQuadVectorBlockSub(int baseX, int baseY, int8 Mx, in
bool ROQPlayer::processBlockStill(ROQBlockHeader &blockHeader) {
debugC(5, kGroovieDebugVideo | kGroovieDebugAll, "Groovie::ROQ: Processing still (JPEG) block");
- warning("Groovie::ROQ: JPEG frame (unfinshed)");
+ warning("Groovie::ROQ: JPEG frame (unfinished)");
Graphics::JPEGDecoder *jpg = new Graphics::JPEGDecoder();
jpg->loadStream(*_file);
diff --git a/engines/hugo/file.cpp b/engines/hugo/file.cpp
index 15ee06c82a..1758f3f6a5 100644
--- a/engines/hugo/file.cpp
+++ b/engines/hugo/file.cpp
@@ -32,7 +32,11 @@
#include "common/savefile.h"
#include "common/textconsole.h"
#include "common/config-manager.h"
+
+#include "graphics/surface.h"
+#include "graphics/decoders/pcx.h"
#include "graphics/thumbnail.h"
+
#include "gui/saveload.h"
#include "hugo/hugo.h"
@@ -88,66 +92,33 @@ const char *FileManager::getUifFilename() const {
}
/**
- * Convert 4 planes (RGBI) data to 8-bit DIB format
- * Return original plane data ptr
- */
-byte *FileManager::convertPCC(byte *p, const uint16 y, const uint16 bpl, ImagePtr dataPtr) const {
- debugC(2, kDebugFile, "convertPCC(byte *p, %d, %d, ImagePtr dataPtr)", y, bpl);
-
- dataPtr += y * bpl * 8; // Point to correct DIB line
- for (int16 r = 0, g = bpl, b = g + bpl, i = b + bpl; r < bpl; r++, g++, b++, i++) { // Each byte in all planes
- for (int8 bit = 7; bit >= 0; bit--) { // Each bit in byte
- *dataPtr++ = (((p[r] >> bit & 1) << 0) |
- ((p[g] >> bit & 1) << 1) |
- ((p[b] >> bit & 1) << 2) |
- ((p[i] >> bit & 1) << 3));
- }
- }
- return p;
-}
-
-/**
* Read a pcx file of length len. Use supplied seqPtr and image_p or
* allocate space if NULL. Name used for errors. Returns address of seqPtr
* Set first TRUE to initialize b_index (i.e. not reading a sequential image in file).
*/
-Seq *FileManager::readPCX(Common::ReadStream &f, Seq *seqPtr, byte *imagePtr, const bool firstFl, const char *name) {
+Seq *FileManager::readPCX(Common::SeekableReadStream &f, Seq *seqPtr, byte *imagePtr, const bool firstFl, const char *name) {
debugC(1, kDebugFile, "readPCX(..., %s)", name);
- // Read in the PCC header and check consistency
- _PCCHeader._mfctr = f.readByte();
- _PCCHeader._vers = f.readByte();
- _PCCHeader._enc = f.readByte();
- _PCCHeader._bpx = f.readByte();
- _PCCHeader._x1 = f.readUint16LE();
- _PCCHeader._y1 = f.readUint16LE();
- _PCCHeader._x2 = f.readUint16LE();
- _PCCHeader._y2 = f.readUint16LE();
- _PCCHeader._xres = f.readUint16LE();
- _PCCHeader._yres = f.readUint16LE();
- f.read(_PCCHeader._palette, sizeof(_PCCHeader._palette));
- _PCCHeader._vmode = f.readByte();
- _PCCHeader._planes = f.readByte();
- _PCCHeader._bytesPerLine = f.readUint16LE();
- f.read(_PCCHeader._fill2, sizeof(_PCCHeader._fill2));
-
- if (_PCCHeader._mfctr != 10)
- error("Bad data file format: %s", name);
-
// Allocate memory for Seq if 0
if (seqPtr == 0) {
if ((seqPtr = (Seq *)malloc(sizeof(Seq))) == 0)
error("Insufficient memory to run game.");
}
+ Graphics::PCXDecoder pcx;
+ if (!pcx.loadStream(f))
+ error("Error while reading PCX image");
+
+ const Graphics::Surface *pcxSurface = pcx.getSurface();
+ if (pcxSurface->format.bytesPerPixel != 1)
+ error("Invalid bytes per pixel in PCX surface (%d)", pcxSurface->format.bytesPerPixel);
+
// Find size of image data in 8-bit DIB format
// Note save of x2 - marks end of valid data before garbage
- uint16 bytesPerLine4 = _PCCHeader._bytesPerLine * 4; // 4-bit bpl
- seqPtr->_bytesPerLine8 = bytesPerLine4 * 2; // 8-bit bpl
- seqPtr->_lines = _PCCHeader._y2 - _PCCHeader._y1 + 1;
- seqPtr->_x2 = _PCCHeader._x2 - _PCCHeader._x1 + 1;
+ seqPtr->_lines = pcxSurface->h;
+ seqPtr->_x2 = seqPtr->_bytesPerLine8 = pcxSurface->w;
// Size of the image
- uint16 size = seqPtr->_lines * seqPtr->_bytesPerLine8;
+ uint16 size = pcxSurface->w * pcxSurface->h;
// Allocate memory for image data if NULL
if (imagePtr == 0)
@@ -156,26 +127,9 @@ Seq *FileManager::readPCX(Common::ReadStream &f, Seq *seqPtr, byte *imagePtr, co
assert(imagePtr);
seqPtr->_imagePtr = imagePtr;
+ for (uint16 y = 0; y < pcxSurface->h; y++)
+ memcpy(imagePtr + y * pcxSurface->w, pcxSurface->getBasePtr(0, y), pcxSurface->w);
- // Process the image data, converting to 8-bit DIB format
- uint16 y = 0; // Current line index
- byte pline[kXPix]; // Hold 4 planes of data
- byte *p = pline; // Ptr to above
- while (y < seqPtr->_lines) {
- byte c = f.readByte();
- if ((c & kRepeatMask) == kRepeatMask) {
- byte d = f.readByte(); // Read data byte
- for (int i = 0; i < (c & kLengthMask); i++) {
- *p++ = d;
- if ((uint16)(p - pline) == bytesPerLine4)
- p = convertPCC(pline, y++, _PCCHeader._bytesPerLine, imagePtr);
- }
- } else {
- *p++ = c;
- if ((uint16)(p - pline) == bytesPerLine4)
- p = convertPCC(pline, y++, _PCCHeader._bytesPerLine, imagePtr);
- }
- }
return seqPtr;
}
diff --git a/engines/hugo/file.h b/engines/hugo/file.h
index 1438bd2054..44f257a2af 100644
--- a/engines/hugo/file.h
+++ b/engines/hugo/file.h
@@ -112,16 +112,13 @@ protected:
Common::File _sceneryArchive1; // Handle for scenery file
Common::File _objectsArchive; // Handle for objects file
- PCCHeader _PCCHeader;
-
- Seq *readPCX(Common::ReadStream &f, Seq *seqPtr, byte *imagePtr, const bool firstFl, const char *name);
+ Seq *readPCX(Common::SeekableReadStream &f, Seq *seqPtr, byte *imagePtr, const bool firstFl, const char *name);
// If this is the first call, read the lookup table
bool _hasReadHeader;
SoundHdr _soundHdr[kMaxSounds]; // Sound lookup table
private:
- byte *convertPCC(byte *p, const uint16 y, const uint16 bpl, ImagePtr dataPtr) const;
UifHdr *getUIFHeader(const Uif id);
};
diff --git a/engines/lure/decode.cpp b/engines/lure/decode.cpp
index 1338559534..484126c43f 100644
--- a/engines/lure/decode.cpp
+++ b/engines/lure/decode.cpp
@@ -255,7 +255,7 @@ MemoryBlock *PictureDecoder::vgaDecode(MemoryBlock *src, uint32 maxOutputSize) {
decrCtr();
if (shlCarry())
break;
-
+
AL = dataIn->data()[BP + 3];
} else {
decrCtr();
@@ -375,7 +375,7 @@ uint32 AnimationDecoder::decode_data(MemoryBlock *src, MemoryBlock *dest, uint32
// Main loop
bool loopFlag = true;
while (loopFlag) {
- for (;;) {
+ for (;;) {
carry = false;
rcl(currData, carry);
if (--bitCtr == 0) {
diff --git a/engines/made/screenfx.cpp b/engines/made/screenfx.cpp
index de9231a158..ad71f1fb49 100644
--- a/engines/made/screenfx.cpp
+++ b/engines/made/screenfx.cpp
@@ -200,10 +200,10 @@ void ScreenEffects::stepBlendedPalette() {
setBlendedPalette(_blendedPaletteStatus._palette, _blendedPaletteStatus._newPalette,
_blendedPaletteStatus._colorCount, _blendedPaletteStatus._value, _blendedPaletteStatus._maxValue);
if (_blendedPaletteStatus._value == _blendedPaletteStatus._maxValue)
- _blendedPaletteStatus._value++;
- else
- _blendedPaletteStatus._value = MIN<int16>(_blendedPaletteStatus._value + _blendedPaletteStatus._incr, _blendedPaletteStatus._maxValue);
- }
+ _blendedPaletteStatus._value++;
+ else
+ _blendedPaletteStatus._value = MIN<int16>(_blendedPaletteStatus._value + _blendedPaletteStatus._incr, _blendedPaletteStatus._maxValue);
+ }
}
void ScreenEffects::copyFxRect(Graphics::Surface *surface, int16 x1, int16 y1, int16 x2, int16 y2) {
diff --git a/engines/mohawk/bitmap.cpp b/engines/mohawk/bitmap.cpp
index 952b6daec2..bc19fe2d3e 100644
--- a/engines/mohawk/bitmap.cpp
+++ b/engines/mohawk/bitmap.cpp
@@ -630,7 +630,7 @@ void MohawkBitmap::drawRLE8(Graphics::Surface *surface, bool isLE) {
// Myst Bitmap Decoder
//////////////////////////////////////////
-MohawkSurface *MystBitmap::decodeImage(Common::SeekableReadStream* stream) {
+MohawkSurface *MystBitmap::decodeImage(Common::SeekableReadStream *stream) {
uint32 uncompressedSize = stream->readUint32LE();
Common::SeekableReadStream *bmpStream = decompressLZ(stream, uncompressedSize);
delete stream;
@@ -652,10 +652,10 @@ MohawkSurface *MystBitmap::decodeImage(Common::SeekableReadStream* stream) {
}
// Copy the palette to one of our own
- const byte *palette = bitmapDecoder.getPalette();
byte *newPal = 0;
- if (palette) {
+ if (bitmapDecoder.hasPalette()) {
+ const byte *palette = bitmapDecoder.getPalette();
newPal = (byte *)malloc(256 * 3);
memcpy(newPal, palette, 256 * 3);
}
diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp
index 0ed4f38b53..b1b99722d5 100644
--- a/engines/mohawk/video.cpp
+++ b/engines/mohawk/video.cpp
@@ -478,7 +478,7 @@ VideoHandle VideoManager::findVideoHandle(const Common::String &filename) {
return NULL_VID_HANDLE;
}
-int32 VideoManager::getCurFrame(VideoHandle handle) {
+int VideoManager::getCurFrame(VideoHandle handle) {
assert(handle != NULL_VID_HANDLE);
return _videoStreams[handle]->getCurFrame();
}
diff --git a/engines/mohawk/video.h b/engines/mohawk/video.h
index 9dddcde09b..6d2783936d 100644
--- a/engines/mohawk/video.h
+++ b/engines/mohawk/video.h
@@ -98,7 +98,7 @@ public:
// Handle functions
VideoHandle findVideoHandle(uint16 id);
VideoHandle findVideoHandle(const Common::String &filename);
- int32 getCurFrame(VideoHandle handle);
+ int getCurFrame(VideoHandle handle);
uint32 getFrameCount(VideoHandle handle);
uint32 getTime(VideoHandle handle);
uint32 getDuration(VideoHandle videoHandle);
diff --git a/engines/parallaction/adlib.cpp b/engines/parallaction/adlib.cpp
new file mode 100644
index 0000000000..134e5cfbf3
--- /dev/null
+++ b/engines/parallaction/adlib.cpp
@@ -0,0 +1,808 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/debug.h"
+#include "common/system.h"
+
+#include "audio/fmopl.h"
+#include "audio/mpu401.h"
+#include "audio/softsynth/emumidi.h"
+
+namespace Parallaction {
+
+const uint kNumVoices = 9;
+// adlib FM voices 0-5
+const uint kNumMelodic = 6;
+// adlib FM voice 6 and 7-8
+const uint kNumPercussion = 5;
+
+// mask for maximum volume level
+#define LEVEL_MASK 0x7f
+
+struct OPLOperator {
+ uint8 characteristic; // amplitude modulation, vibrato, envelope, keyboard scaling, modulator frequency
+ uint8 levels;
+ uint8 attackDecay;
+ uint8 sustainRelease;
+ uint8 waveform;
+};
+
+struct MelodicProgram {
+ OPLOperator op[2];
+ uint8 feedbackAlgo;
+};
+
+struct PercussionNote {
+ OPLOperator op[2];
+ uint8 feedbackAlgo;
+ uint8 percussion;
+ uint8 valid;
+ uint16 frequency;
+ uint8 octave;
+};
+
+static const MelodicProgram melodicPrograms[128] = {
+ {{{ 0x1, 0x51, 0xf2, 0xb2, 0x0 }, { 0x11, 0x0, 0xf2, 0xa2, 0x0 }}, 0x0 },
+ {{{ 0xc2, 0x4b, 0xf1, 0x53, 0x0 }, { 0xd2, 0x0, 0xf2, 0x74, 0x0 }}, 0x4 },
+ {{{ 0x81, 0x9d, 0xf2, 0x74, 0x0 }, { 0x13, 0x0, 0xf2, 0xf1, 0x0 }}, 0x6 },
+ {{{ 0x3, 0x4f, 0xf1, 0x53, 0x0 }, { 0x17, 0x3, 0xf2, 0x74, 0x0 }}, 0x6 },
+ {{{ 0xd1, 0x81, 0x81, 0x73, 0x2 }, { 0xd4, 0x0, 0xe1, 0x34, 0x0 }}, 0x3 },
+ {{{ 0x1, 0x0, 0x94, 0xa6, 0x0 }, { 0x2, 0x0, 0x83, 0x26, 0x0 }}, 0x1 },
+ {{{ 0xf3, 0x84, 0x81, 0x2, 0x1 }, { 0x55, 0x80, 0xdd, 0x3, 0x0 }}, 0x4 },
+ {{{ 0x5, 0x8a, 0xf2, 0x26, 0x0 }, { 0x1, 0x80, 0xf3, 0x48, 0x0 }}, 0x0 },
+ {{{ 0x32, 0x0, 0xb1, 0x14, 0x0 }, { 0x12, 0x0, 0xfd, 0x36, 0x0 }}, 0x3 },
+ {{{ 0x1, 0x0, 0x82, 0xa, 0x2 }, { 0x2, 0x0, 0x85, 0x15, 0x0 }}, 0x3 },
+ {{{ 0xd1, 0x1, 0x97, 0xaa, 0x0 }, { 0x4, 0xd, 0xf3, 0xa5, 0x1 }}, 0x9 },
+ {{{ 0x17, 0x0, 0xf2, 0x62, 0x0 }, { 0x12, 0x0, 0xf2, 0x72, 0x0 }}, 0x8 },
+ {{{ 0x6, 0x0, 0xff, 0xf4, 0x0 }, { 0xc4, 0x0, 0xf8, 0xb5, 0x0 }}, 0xe },
+ {{{ 0xc0, 0x81, 0xf2, 0x13, 0x2 }, { 0xc0, 0xc1, 0xf3, 0x14, 0x2 }}, 0xb },
+ {{{ 0x44, 0x53, 0xf5, 0x31, 0x0 }, { 0x60, 0x80, 0xfd, 0x22, 0x0 }}, 0x6 },
+ {{{ 0xe0, 0x80, 0xf4, 0xf2, 0x0 }, { 0x61, 0x0, 0xf2, 0x6, 0x0 }}, 0x8 },
+ {{{ 0xc1, 0x6, 0x83, 0x23, 0x0 }, { 0xc1, 0x4, 0xf0, 0x26, 0x0 }}, 0x1 },
+ {{{ 0x26, 0x0, 0xf4, 0xb6, 0x0 }, { 0x21, 0x0, 0x81, 0x4b, 0x0 }}, 0x1 },
+ {{{ 0x24, 0x80, 0xff, 0xf, 0x0 }, { 0x21, 0x80, 0xff, 0xf, 0x0 }}, 0x1 },
+ {{{ 0x24, 0x4f, 0xf2, 0xb, 0x0 }, { 0x31, 0x0, 0x52, 0xb, 0x0 }}, 0xb },
+ {{{ 0x31, 0x8, 0x81, 0xb, 0x0 }, { 0xa1, 0x80, 0x92, 0x3b, 0x0 }}, 0x0 },
+ {{{ 0x70, 0xc5, 0x52, 0x11, 0x1 }, { 0x71, 0x80, 0x31, 0xfe, 0x1 }}, 0x0 },
+ {{{ 0x51, 0x88, 0x10, 0xf0, 0x0 }, { 0x42, 0x83, 0x40, 0xfc, 0x0 }}, 0x8 },
+ {{{ 0xf0, 0xd9, 0x81, 0x3, 0x0 }, { 0xb1, 0x80, 0xf1, 0x5, 0x0 }}, 0xa },
+ {{{ 0x21, 0x4f, 0xf1, 0x31, 0x0 }, { 0x2, 0x80, 0xc3, 0x45, 0x0 }}, 0x0 },
+ {{{ 0x7, 0x8f, 0x9c, 0x33, 0x1 }, { 0x1, 0x80, 0x8a, 0x13, 0x0 }}, 0x0 },
+ {{{ 0x21, 0x40, 0xf1, 0x31, 0x0 }, { 0x6, 0x80, 0xf4, 0x44, 0x0 }}, 0x0 },
+ {{{ 0x21, 0x40, 0xf1, 0x31, 0x3 }, { 0x81, 0x0, 0xf4, 0x44, 0x2 }}, 0x2 },
+ {{{ 0x11, 0x8d, 0xfd, 0x11, 0x0 }, { 0x11, 0x80, 0xfd, 0x11, 0x0 }}, 0x8 },
+ {{{ 0xf0, 0x1, 0x97, 0x17, 0x0 }, { 0x21, 0xd, 0xf1, 0x18, 0x0 }}, 0x8 },
+ {{{ 0xf1, 0x1, 0x97, 0x17, 0x0 }, { 0x21, 0xd, 0xf1, 0x18, 0x0 }}, 0x8 },
+ {{{ 0xcd, 0x9e, 0x55, 0xd1, 0x0 }, { 0xd1, 0x0, 0xf2, 0x71, 0x0 }}, 0xe },
+ {{{ 0x1, 0x0, 0xf2, 0x88, 0x0 }, { 0x1, 0x0, 0xf5, 0x88, 0x0 }}, 0x1 },
+ {{{ 0x30, 0xd, 0xf2, 0xef, 0x0 }, { 0x21, 0x0, 0xf5, 0x78, 0x0 }}, 0x6 },
+ {{{ 0x0, 0x10, 0xf4, 0xd9, 0x0 }, { 0x0, 0x0, 0xf5, 0xd7, 0x0 }}, 0x4 },
+ {{{ 0x1, 0x4c, 0xf2, 0x50, 0x0 }, { 0x1, 0x40, 0xd2, 0x59, 0x0 }}, 0x8 },
+ {{{ 0x20, 0x11, 0xe2, 0x8a, 0x0 }, { 0x20, 0x0, 0xe4, 0xa8, 0x0 }}, 0xa },
+ {{{ 0x21, 0x40, 0x7b, 0x4, 0x1 }, { 0x21, 0x0, 0x75, 0x72, 0x0 }}, 0x2 },
+ {{{ 0x31, 0xd, 0xf2, 0xef, 0x0 }, { 0x21, 0x0, 0xf5, 0x78, 0x0 }}, 0xa },
+ {{{ 0x1, 0xc, 0xf5, 0x2f, 0x1 }, { 0x0, 0x80, 0xf5, 0x5c, 0x0 }}, 0x0 },
+ {{{ 0xb0, 0x1c, 0x81, 0x3, 0x2 }, { 0x20, 0x0, 0x54, 0x67, 0x2 }}, 0xe },
+ {{{ 0x1, 0x0, 0xf1, 0x65, 0x0 }, { 0x1, 0x80, 0xa3, 0xa8, 0x2 }}, 0x1 },
+ {{{ 0xe1, 0x4f, 0xc1, 0xd3, 0x2 }, { 0x21, 0x0, 0x32, 0x74, 0x1 }}, 0x0 },
+ {{{ 0x2, 0x0, 0xf6, 0x16, 0x0 }, { 0x12, 0x0, 0xf2, 0xf8, 0x0 }}, 0x1 },
+ {{{ 0xe0, 0x63, 0xf8, 0xf3, 0x0 }, { 0x70, 0x80, 0xf7, 0xf3, 0x0 }}, 0x4 },
+ {{{ 0x1, 0x6, 0xf3, 0xff, 0x0 }, { 0x8, 0x0, 0xf7, 0xff, 0x0 }}, 0x4 },
+ {{{ 0x21, 0x16, 0xb0, 0x81, 0x1 }, { 0x22, 0x0, 0xb3, 0x13, 0x1 }}, 0xc },
+ {{{ 0x1, 0x4f, 0xf0, 0xff, 0x0 }, { 0x30, 0x0, 0x90, 0xf, 0x0 }}, 0x6 },
+ {{{ 0x0, 0x10, 0xf1, 0xf2, 0x2 }, { 0x1, 0x0, 0xf1, 0xf2, 0x3 }}, 0x0 },
+ {{{ 0x1, 0x4f, 0xf1, 0x50, 0x0 }, { 0x21, 0x80, 0xa3, 0x5, 0x3 }}, 0x6 },
+ {{{ 0xb1, 0x3, 0x55, 0x3, 0x0 }, { 0xb1, 0x3, 0x8, 0xa, 0x0 }}, 0x9 },
+ {{{ 0x22, 0x0, 0xa9, 0x34, 0x1 }, { 0x1, 0x0, 0xa2, 0x42, 0x2 }}, 0x2 },
+ {{{ 0xa0, 0xdc, 0x81, 0x31, 0x3 }, { 0xb1, 0x80, 0xf1, 0x1, 0x3 }}, 0x0 },
+ {{{ 0x1, 0x4f, 0xf1, 0x50, 0x0 }, { 0x21, 0x80, 0xa3, 0x5, 0x3 }}, 0x6 },
+ {{{ 0xf1, 0x80, 0xa0, 0x72, 0x0 }, { 0x74, 0x0, 0x90, 0x22, 0x0 }}, 0x9 },
+ {{{ 0xe1, 0x13, 0x71, 0xae, 0x0 }, { 0xe1, 0x0, 0xf0, 0xfc, 0x1 }}, 0xa },
+ {{{ 0x31, 0x1c, 0x41, 0xb, 0x0 }, { 0xa1, 0x80, 0x92, 0x3b, 0x0 }}, 0xe },
+ {{{ 0x71, 0x1c, 0x41, 0x1f, 0x0 }, { 0xa1, 0x80, 0x92, 0x3b, 0x0 }}, 0xe },
+ {{{ 0x21, 0x1c, 0x53, 0x1d, 0x0 }, { 0xa1, 0x80, 0x52, 0x3b, 0x0 }}, 0xc },
+ {{{ 0x21, 0x1d, 0xa4, 0xae, 0x1 }, { 0x21, 0x0, 0xb1, 0x9e, 0x0 }}, 0xc },
+ {{{ 0xe1, 0x16, 0x71, 0xae, 0x0 }, { 0xe1, 0x0, 0x81, 0x9e, 0x0 }}, 0xa },
+ {{{ 0xe1, 0x15, 0x71, 0xae, 0x0 }, { 0xe2, 0x0, 0x81, 0x9e, 0x0 }}, 0xe },
+ {{{ 0x21, 0x16, 0x71, 0xae, 0x0 }, { 0x21, 0x0, 0x81, 0x9e, 0x0 }}, 0xe },
+ {{{ 0x71, 0x1c, 0x41, 0x1f, 0x0 }, { 0xa1, 0x80, 0x92, 0x3b, 0x0 }}, 0xe },
+ {{{ 0x21, 0x4f, 0x81, 0x53, 0x0 }, { 0x32, 0x0, 0x22, 0x2c, 0x0 }}, 0xa },
+ {{{ 0x22, 0x4f, 0x81, 0x53, 0x0 }, { 0x32, 0x0, 0x22, 0x2c, 0x0 }}, 0xa },
+ {{{ 0x23, 0x4f, 0x81, 0x53, 0x0 }, { 0x34, 0x0, 0x22, 0x2c, 0x0 }}, 0xa },
+ {{{ 0xe1, 0x16, 0x71, 0xae, 0x0 }, { 0xe1, 0x0, 0x81, 0x9e, 0x0 }}, 0xa },
+ {{{ 0x71, 0xc5, 0x6e, 0x17, 0x0 }, { 0x22, 0x5, 0x8b, 0xe, 0x0 }}, 0x2 },
+ {{{ 0xe6, 0x27, 0x70, 0xf, 0x1 }, { 0xe3, 0x0, 0x60, 0x9f, 0x0 }}, 0xa },
+ {{{ 0x30, 0xc8, 0xd5, 0x19, 0x0 }, { 0xb1, 0x80, 0x61, 0x1b, 0x0 }}, 0xc },
+ {{{ 0x32, 0x9a, 0x51, 0x1b, 0x0 }, { 0xa1, 0x82, 0xa2, 0x3b, 0x0 }}, 0xc },
+ {{{ 0xad, 0x3, 0x74, 0x29, 0x0 }, { 0xa2, 0x82, 0x73, 0x29, 0x0 }}, 0x7 },
+ {{{ 0x21, 0x83, 0x74, 0x17, 0x0 }, { 0x62, 0x8d, 0x65, 0x17, 0x0 }}, 0x7 },
+ {{{ 0x94, 0xb, 0x85, 0xff, 0x1 }, { 0x13, 0x0, 0x74, 0xff, 0x0 }}, 0xc },
+ {{{ 0x74, 0x87, 0xa4, 0x2, 0x0 }, { 0xd6, 0x80, 0x45, 0x42, 0x0 }}, 0x2 },
+ {{{ 0xb3, 0x85, 0x76, 0x21, 0x1 }, { 0x20, 0x0, 0x3d, 0xc1, 0x0 }}, 0x6 },
+ {{{ 0x17, 0x4f, 0xf2, 0x61, 0x0 }, { 0x12, 0x8, 0xf1, 0xb4, 0x0 }}, 0x8 },
+ {{{ 0x4f, 0x86, 0x65, 0x1, 0x0 }, { 0x1f, 0x0, 0x32, 0x74, 0x0 }}, 0x4 },
+ {{{ 0xe1, 0x23, 0x71, 0xae, 0x0 }, { 0xe4, 0x0, 0x82, 0x9e, 0x0 }}, 0xa },
+ {{{ 0x11, 0x86, 0xf2, 0xbd, 0x0 }, { 0x4, 0x80, 0xa0, 0x9b, 0x1 }}, 0x8 },
+ {{{ 0x20, 0x90, 0xf5, 0x9e, 0x2 }, { 0x11, 0x0, 0xf4, 0x5b, 0x3 }}, 0xc },
+ {{{ 0xf0, 0x80, 0x34, 0xe4, 0x0 }, { 0x7e, 0x0, 0xa2, 0x6, 0x0 }}, 0x8 },
+ {{{ 0x90, 0xf, 0xff, 0x1, 0x3 }, { 0x0, 0x0, 0x1f, 0x1, 0x0 }}, 0xe },
+ {{{ 0x1, 0x4f, 0xf0, 0xff, 0x0 }, { 0x33, 0x0, 0x90, 0xf, 0x0 }}, 0x6 },
+ {{{ 0x1e, 0x0, 0x1f, 0xf, 0x0 }, { 0x10, 0x0, 0x1f, 0x7f, 0x0 }}, 0x0 },
+ {{{ 0xbe, 0x0, 0xf1, 0x1, 0x3 }, { 0x31, 0x0, 0xf1, 0x1, 0x0 }}, 0x4 },
+ {{{ 0xbe, 0x0, 0xf1, 0x1, 0x3 }, { 0x31, 0x0, 0xf1, 0x1, 0x0 }}, 0x4 },
+ {{{ 0x93, 0x6, 0xc1, 0x4, 0x1 }, { 0x82, 0x0, 0x51, 0x9, 0x0 }}, 0x6 },
+ {{{ 0xa0, 0x0, 0x96, 0x33, 0x0 }, { 0x20, 0x0, 0x55, 0x2b, 0x0 }}, 0x6 },
+ {{{ 0x0, 0xc0, 0xff, 0x5, 0x0 }, { 0x0, 0x0, 0xff, 0x5, 0x3 }}, 0x0 },
+ {{{ 0x4, 0x8, 0xf8, 0x7, 0x0 }, { 0x1, 0x0, 0x82, 0x74, 0x0 }}, 0x8 },
+ {{{ 0x0, 0x0, 0x2f, 0x5, 0x0 }, { 0x20, 0x0, 0xff, 0x5, 0x3 }}, 0xa },
+ {{{ 0x93, 0x0, 0xf7, 0x7, 0x2 }, { 0x0, 0x0, 0xf7, 0x7, 0x0 }}, 0xa },
+ {{{ 0x0, 0x40, 0x80, 0x7a, 0x0 }, { 0xc4, 0x0, 0xc0, 0x7e, 0x0 }}, 0x8 },
+ {{{ 0x90, 0x80, 0x55, 0xf5, 0x0 }, { 0x0, 0x0, 0x55, 0xf5, 0x0 }}, 0x8 },
+ {{{ 0xe1, 0x80, 0x34, 0xe4, 0x0 }, { 0x69, 0x0, 0xf2, 0x6, 0x0 }}, 0x8 },
+ {{{ 0x3, 0x2, 0xf0, 0xff, 0x3 }, { 0x11, 0x80, 0xf0, 0xff, 0x2 }}, 0x2 },
+ {{{ 0x1e, 0x0, 0x1f, 0xf, 0x0 }, { 0x10, 0x0, 0x1f, 0x7f, 0x0 }}, 0x0 },
+ {{{ 0x0, 0x0, 0x2f, 0x1, 0x0 }, { 0x0, 0x0, 0xff, 0x1, 0x0 }}, 0x4 },
+ {{{ 0xbe, 0x0, 0xf1, 0x1, 0x3 }, { 0x31, 0x0, 0xf1, 0x1, 0x0 }}, 0x4 },
+ {{{ 0x93, 0x85, 0x3f, 0x6, 0x1 }, { 0x0, 0x0, 0x5f, 0x7, 0x0 }}, 0x6 },
+ {{{ 0x6, 0x0, 0xa0, 0xf0, 0x0 }, { 0x44, 0x0, 0xc5, 0x75, 0x0 }}, 0xe },
+ {{{ 0x60, 0x0, 0x10, 0x81, 0x0 }, { 0x20, 0x8c, 0x12, 0x91, 0x0 }}, 0xe },
+ {{{ 0x1, 0x40, 0xf1, 0x53, 0x0 }, { 0x8, 0x40, 0xf1, 0x53, 0x0 }}, 0x0 },
+ {{{ 0x31, 0x0, 0x56, 0x31, 0x0 }, { 0x16, 0x0, 0x7d, 0x41, 0x0 }}, 0x0 },
+ {{{ 0x0, 0x10, 0xf2, 0x72, 0x0 }, { 0x13, 0x0, 0xf2, 0x72, 0x0 }}, 0xc },
+ {{{ 0x10, 0x0, 0x75, 0x93, 0x1 }, { 0x1, 0x0, 0xf5, 0x82, 0x1 }}, 0x0 },
+ {{{ 0x0, 0x0, 0xf6, 0xff, 0x2 }, { 0x0, 0x0, 0xf6, 0xff, 0x0 }}, 0x8 },
+ {{{ 0x30, 0x0, 0xff, 0xa0, 0x3 }, { 0x63, 0x0, 0x65, 0xb, 0x2 }}, 0x0 },
+ {{{ 0x2a, 0x0, 0xf6, 0x87, 0x0 }, { 0x2b, 0x0, 0x76, 0x25, 0x0 }}, 0x0 },
+ {{{ 0x85, 0x0, 0xb8, 0x84, 0x0 }, { 0x43, 0x0, 0xe5, 0x8f, 0x0 }}, 0x6 },
+ {{{ 0x7, 0x4f, 0xf2, 0x60, 0x0 }, { 0x12, 0x0, 0xf2, 0x72, 0x0 }}, 0x8 },
+ {{{ 0x5, 0x40, 0xb3, 0xd3, 0x0 }, { 0x86, 0x80, 0xf2, 0x24, 0x0 }}, 0x2 },
+ {{{ 0xd0, 0x0, 0x11, 0xcf, 0x0 }, { 0xd1, 0x0, 0xf4, 0xe8, 0x3 }}, 0x0 },
+ {{{ 0x5, 0x4e, 0xda, 0x25, 0x2 }, { 0x1, 0x0, 0xf9, 0x15, 0x0 }}, 0xa },
+ {{{ 0x3, 0x0, 0x8f, 0x7, 0x2 }, { 0x2, 0x0, 0xff, 0x6, 0x0 }}, 0x0 },
+ {{{ 0x13, 0x0, 0x8f, 0x7, 0x2 }, { 0x2, 0x0, 0xf9, 0x5, 0x0 }}, 0x0 },
+ {{{ 0xf0, 0x1, 0x97, 0x17, 0x0 }, { 0x21, 0xd, 0xf1, 0x18, 0x0 }}, 0x8 },
+ {{{ 0xf1, 0x41, 0x11, 0x11, 0x0 }, { 0xf1, 0x41, 0x11, 0x11, 0x0 }}, 0x2 },
+ {{{ 0x13, 0x0, 0x8f, 0x7, 0x2 }, { 0x2, 0x0, 0xff, 0x6, 0x0 }}, 0x0 },
+ {{{ 0x1, 0x0, 0x2f, 0x1, 0x0 }, { 0x1, 0x0, 0xaf, 0x1, 0x3 }}, 0xf },
+ {{{ 0x1, 0x6, 0xf3, 0xff, 0x0 }, { 0x8, 0x0, 0xf7, 0xff, 0x0 }}, 0x4 },
+ {{{ 0xc0, 0x4f, 0xf1, 0x3, 0x0 }, { 0xbe, 0xc, 0x10, 0x1, 0x0 }}, 0x2 },
+ {{{ 0x0, 0x2, 0xf0, 0xff, 0x0 }, { 0x11, 0x80, 0xf0, 0xff, 0x0 }}, 0x6 },
+ {{{ 0x81, 0x47, 0xf1, 0x83, 0x0 }, { 0xa2, 0x4, 0x91, 0x86, 0x0 }}, 0x6 },
+ {{{ 0xf0, 0xc0, 0xff, 0xff, 0x3 }, { 0xe5, 0x0, 0xfb, 0xf0, 0x0 }}, 0xe },
+ {{{ 0x0, 0x2, 0xf0, 0xff, 0x0 }, { 0x11, 0x80, 0xf0, 0xff, 0x0 }}, 0x6 }
+};
+
+static const PercussionNote percussionNotes[47] = {
+ {{{ 0x0, 0xb, 0xa8, 0x38, 0x0 }, { 0x0, 0x0, 0xd6, 0x49, 0x0 }}, 0x0, 0x4, 0x1, 0x97, 0x4 },
+ {{{ 0xc0, 0xc0, 0xf8, 0x3f, 0x2 }, { 0xc0, 0x0, 0xf6, 0x8e, 0x0 }}, 0x0, 0x4, 0x1, 0xf7, 0x4 },
+ {{{ 0xc0, 0x80, 0xc9, 0xab, 0x0 }, { 0xeb, 0x40, 0xb5, 0xf6, 0x0 }}, 0x1, 0x3, 0x1, 0x6a, 0x6 },
+ {{{ 0xc, 0x0, 0xd8, 0xa6, 0x0 }, { 0x0, 0x0, 0xd6, 0x4f, 0x0 }}, 0x1, 0x3, 0x1, 0x6c, 0x5 },
+ {{{ 0x1, 0x0, 0xe2, 0xd2, 0x0 }, { 0x3, 0x41, 0x8f, 0x48, 0x49 }}, 0xc, 0x4, 0x1, 0x2f, 0x5 },
+ {{{ 0x0, 0x0, 0xc8, 0x58, 0x3 }, { 0x0, 0x0, 0xf6, 0x4f, 0x0 }}, 0x9, 0x3, 0x1, 0x108, 0x4 },
+ {{{ 0x1, 0x0, 0xff, 0x5, 0x0 }, { 0xf2, 0xff, 0xe0, 0x50, 0x52 }}, 0x5d, 0x2, 0x1, 0x9f, 0x5 },
+ {{{ 0xe, 0x9, 0xb9, 0x47, 0x0 }, { 0xeb, 0x40, 0xf5, 0xe6, 0x0 }}, 0x0, 0x0, 0x1, 0x82, 0x6 },
+ {{{ 0x0, 0x0, 0xd6, 0x83, 0x0 }, { 0xd6, 0xd7, 0xe0, 0x41, 0x5e }}, 0x4a, 0x2, 0x1, 0xc7, 0x5 },
+ {{{ 0x1, 0x9, 0x89, 0x67, 0x0 }, { 0xd6, 0xd7, 0xe0, 0x41, 0x5e }}, 0x4a, 0x0, 0x1, 0x80, 0x6 },
+ {{{ 0x1, 0x0, 0xd6, 0x96, 0x0 }, { 0xd6, 0xd7, 0xe0, 0x41, 0x5e }}, 0x4a, 0x2, 0x1, 0xed, 0x5 },
+ {{{ 0x0, 0x9, 0xa9, 0x55, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x1, 0x82, 0x6 },
+ {{{ 0x2, 0x0, 0xc6, 0x96, 0x0 }, { 0xe0, 0x0, 0xe0, 0x40, 0x0 }}, 0x1, 0x2, 0x1, 0x123, 0x5 },
+ {{{ 0x5, 0x0, 0xf6, 0x56, 0x0 }, { 0xf7, 0xff, 0xb3, 0x90, 0x4f }}, 0x1, 0x2, 0x1, 0x15b, 0x5 },
+ {{{ 0x1, 0x0, 0xf7, 0x14, 0x0 }, { 0xf7, 0xff, 0x36, 0x90, 0x79 }}, 0xe7, 0x1, 0x1, 0x1ac, 0x5 },
+ {{{ 0x0, 0x0, 0xf6, 0x56, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x1, 0x2, 0x1, 0x18b, 0x5 },
+ {{{ 0x0, 0x83, 0xfb, 0x5, 0x0 }, { 0xf7, 0x41, 0x39, 0x90, 0x79 }}, 0x1, 0x1, 0x1, 0xc8, 0x5 },
+ {{{ 0x0, 0x0, 0xff, 0x5, 0x0 }, { 0xf7, 0xff, 0x36, 0x90, 0x79 }}, 0xe7, 0x1, 0x1, 0xf9, 0x5 },
+ {{{ 0x1, 0x0, 0xa0, 0x5, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x2, 0x1, 0x27a, 0x6 },
+ {{{ 0x0, 0x5, 0xf3, 0x6, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x2, 0x1, 0x108, 0x7 },
+ {{{ 0x1, 0x0, 0xf9, 0x34, 0x0 }, { 0xf7, 0xff, 0x36, 0x90, 0x79 }}, 0xe7, 0x1, 0x1, 0x147, 0x4 },
+ {{{ 0x0, 0x0, 0xf7, 0x16, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x2, 0x1, 0x120, 0x6 },
+ {{{ 0x1, 0x0, 0xff, 0x5, 0x0 }, { 0xf7, 0xff, 0x36, 0x90, 0x79 }}, 0xe7, 0x1, 0x1, 0x42, 0x6 },
+ {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
+ {{{ 0x1, 0x0, 0xff, 0x5, 0x0 }, { 0xf7, 0xff, 0x36, 0x90, 0x79 }}, 0xe7, 0x1, 0x1, 0x6d, 0x5 },
+ {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
+ {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
+ {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
+ {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
+ {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
+ {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
+ {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
+ {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
+ {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
+ {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
+ {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
+ {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
+ {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
+ {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
+ {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
+ {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
+ {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
+ {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
+ {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
+ {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
+ {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
+ {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 }
+};
+
+const uint16 melodicFrequencies[36] = {
+ 0x55, 0x5a, 0x60, 0x66, 0x6c, 0x72, 0x79, 0x80, 0x88,
+ 0x90, 0x99, 0xa1, 0xab, 0xb5, 0xc0, 0xcc, 0xd8, 0xe5,
+ 0xf2, 0x101, 0x110, 0x120, 0x132, 0x143, 0x156, 0x16b, 0x181,
+ 0x198, 0x1b0, 0x1ca, 0x1e5, 0x202, 0x220, 0x241, 0x263, 0x286
+};
+
+class AdLibDriver;
+
+class AdLibChannel : public MidiChannel_MPU401 {
+public:
+ void reset();
+
+ uint8 _program;
+ uint8 _volume;
+ uint8 _pedal;
+};
+
+struct MelodicVoice {
+ bool _used;
+ uint8 _channel;
+ uint8 _program;
+
+ uint8 _key;
+ uint32 _timestamp;
+ uint16 _frequency;
+ int8 _octave;
+};
+
+class AdLibDriver : public MidiDriver_Emulated {
+public:
+ AdLibDriver(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer) {
+ for (uint i = 0; i < 16; ++i)
+ _channels[i].init(this, i);
+ }
+
+ int open();
+ void close();
+ void send(uint32 b);
+ MidiChannel *allocateChannel();
+ MidiChannel *getPercussionChannel() { return &_channels[9]; }
+
+ bool isStereo() const { return false; }
+ int getRate() const { return _mixer->getOutputRate(); }
+
+ void generateSamples(int16 *buf, int len);
+
+protected:
+ OPL::OPL *_opl;
+ AdLibChannel _channels[16];
+ MelodicVoice _voices[kNumMelodic];
+ uint8 _notesPerPercussion[kNumPercussion];
+
+ uint _lastVoice;
+
+ uint8 _percussionMask;
+
+ void noteOff(uint8 channel, uint8 note);
+ void noteOn(uint8 channel, uint8 note, uint8 velocity);
+ void allNotesOff();
+ void setModulationWheel(uint8 channel, uint8 value);
+ void setFootController(uint8 channel, uint8 value);
+ void setVolume(uint8 channel, uint8 value);
+ void setPitchBend(uint8 channel, int16 value);
+
+ void playNote(uint8 voice, uint8 octave, uint16 frequency);
+
+ void programOperatorSimple(uint8 offset, const OPLOperator &op);
+ void programOperator(uint8 offset, const OPLOperator &op);
+ void setOperatorLevel(uint8 offset, const OPLOperator &op, uint8 velocity, uint8 channel, bool forceVolume);
+
+ void setupPercussion(const PercussionNote &note);
+ void playPercussion(uint8 channel, const PercussionNote &note, uint8 velocity);
+
+ void programMelodicVoice(uint8 voice, uint8 program);
+ void playMelodicNote(uint8 voice, uint8 channel, uint8 note, uint8 velocity);
+ void muteMelodicVoice(uint8 voice);
+
+ void initVoices();
+};
+
+MidiDriver *createAdLibDriver() {
+ return new AdLibDriver(g_system->getMixer());
+}
+
+void AdLibChannel::reset() {
+ _program = 0;
+ _volume = 127;
+ _pedal = 0;
+}
+
+/*
+ bit 7 - Clear: AM depth is 1 dB
+ bit 6 - Clear: Vibrato depth is 7 cent
+ bit 5 - Set: Rhythm enabled (6 melodic voices)
+ bit 4 - Bass drum off
+ bit 3 - Snare drum off
+ bit 2 - Tom tom off
+ bit 1 - Cymbal off
+ bit 0 - Hi Hat off
+*/
+const uint8 kDefaultPercussionMask = 0x20;
+
+int AdLibDriver::open() {
+ if (_isOpen)
+ return MERR_ALREADY_OPEN;
+
+ MidiDriver_Emulated::open();
+
+ _opl = OPL::Config::create();
+ _opl->init(getRate());
+ _opl->writeReg(0x1, 0x20); // set bit 5 (enable all waveforms)
+
+ // Reset the OPL registers.
+ for (uint i = 0; i < kNumVoices; ++i) {
+ _opl->writeReg(0xA0 + i, 0); // frequency
+ _opl->writeReg(0xB0 + i, 0); // key on
+ _opl->writeReg(0xC0 + i, 0); // feedback
+ }
+ _opl->writeReg(0xBD, kDefaultPercussionMask);
+
+ initVoices();
+
+ _mixer->playStream(Audio::Mixer::kMusicSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+ return 0;
+}
+
+void AdLibDriver::close() {
+ if (!_isOpen)
+ return;
+
+ _isOpen = false;
+ _mixer->stopHandle(_mixerSoundHandle);
+
+ delete _opl;
+}
+
+void AdLibDriver::send(uint32 b) {
+ uint channel = b & 0xf;
+ uint cmd = (b >> 4) & 0xf;
+ uint param1 = (b >> 8) & 0xff;
+ uint param2 = (b >> 16) & 0xff;
+
+ switch (cmd) {
+ case 8:
+ noteOff(channel, param1);
+ break;
+ case 9:
+ // TODO: map volume?
+ noteOn(channel, param1, param2);
+ break;
+ case 11:
+ // controller change
+ switch (param1) {
+ case 1:
+ setModulationWheel(channel, param2);
+ break;
+ case 4:
+ setFootController(channel, param2);
+ break;
+ case 7:
+ setVolume(channel, param2);
+ break;
+ case 123:
+ // all notes off
+ allNotesOff();
+ break;
+ }
+ break;
+ case 12:
+ // program change
+ _channels[channel]._program = param1;
+ break;
+ case 14:
+ setPitchBend(channel, (param1 | (param2 << 7)) - 0x2000);
+ break;
+ }
+}
+
+void AdLibDriver::noteOff(uint8 channel, uint8 note) {
+ if (channel == 9) {
+ if (note < 35 || note > 81)
+ return;
+
+ _percussionMask &= ~(1 << percussionNotes[note - 35].percussion);
+ _opl->writeReg(0xBD, _percussionMask);
+ return;
+ }
+
+ for (int i = kNumMelodic - 1; i >= 0; --i) {
+ if (_voices[i]._channel != channel)
+ continue;
+ if (_voices[i]._key != note)
+ continue;
+ muteMelodicVoice(i);
+ _voices[i]._used = false;
+ return;
+ }
+
+ //debug(1, "failed to find voice off for channel %d, note %d", channel, note);
+}
+
+void AdLibDriver::noteOn(uint8 channel, uint8 note, uint8 velocity) {
+ if (channel == 9) {
+ if (note < 35 || note > 81)
+ return;
+
+ const PercussionNote &info = percussionNotes[note - 35];
+ if (!info.valid)
+ return;
+
+ if (note != _notesPerPercussion[info.percussion]) {
+ setupPercussion(info);
+ _notesPerPercussion[info.percussion] = note;
+ }
+
+ playPercussion(channel, info, velocity);
+ return;
+ }
+
+ if (velocity == 0) {
+ noteOff(channel, note);
+ return;
+ }
+
+ // We want to play a note on a melodic (voice) channel.
+
+ // First, look for a voice playing the same note with the same program.
+ for (uint i = 0; i < kNumMelodic; ++i) {
+ if (_voices[i]._channel != channel || _voices[i]._key != note)
+ continue;
+ if (_voices[i]._program != _channels[channel]._program)
+ continue;
+ muteMelodicVoice(i);
+ playMelodicNote(i, channel, note, velocity);
+ return;
+ }
+
+ // The loops below try to start at _lastVoice and find a voice to use.
+ // They ignore _lastVoice itself, and update _lastVoice if they succeed.
+
+ // Then, try finding a melodic voice with the same program.
+ for (uint i = (_lastVoice + 1) % kNumMelodic; i != _lastVoice; i = (i + 1) % kNumMelodic) {
+ if (_voices[i]._used)
+ continue;
+ if (_voices[i]._program != _channels[channel]._program)
+ continue;
+ playMelodicNote(i, channel, note, velocity);
+ _lastVoice = i;
+ return;
+ }
+
+ // Then, try finding a free melodic voice of any kind.
+ for (uint i = (_lastVoice + 1) % kNumMelodic; i != _lastVoice; i = (i + 1) % kNumMelodic) {
+ if (_voices[i]._used)
+ continue;
+ programMelodicVoice(i, _channels[channel]._program);
+ playMelodicNote(i, channel, note, velocity);
+ _lastVoice = i;
+ return;
+ }
+
+ // Then just try finding a melodic voice with the same program,
+ // and steal it.
+ for (uint i = (_lastVoice + 1) % kNumMelodic; i != _lastVoice; i = (i + 1) % kNumMelodic) {
+ if (_voices[i]._program != _channels[channel]._program)
+ continue;
+ muteMelodicVoice(i);
+ playMelodicNote(i, channel, note, velocity);
+ _lastVoice = i;
+ return;
+ }
+
+ // Finally, just take control of the channel used least recently.
+ uint voiceId = 0;
+ uint32 bestTimestamp = 0xffffffff;
+ for (uint i = 0; i < kNumMelodic; ++i)
+ if (bestTimestamp > _voices[i]._timestamp) {
+ voiceId = i;
+ bestTimestamp = _voices[i]._timestamp;
+ }
+
+ //debug(1, "ran out of voices for channel %d, note %d, program %d: reused voice %d", channel, note, _channels[channel]._program, voiceId);
+ programMelodicVoice(voiceId, _channels[channel]._program);
+ playMelodicNote(voiceId, channel, note, velocity);
+ _lastVoice = voiceId;
+}
+
+// TODO: this doesn't match original
+void AdLibDriver::allNotesOff() {
+ for (uint i = 0; i < kNumMelodic; ++i) {
+ muteMelodicVoice(i);
+ _voices[i]._used = false;
+ }
+
+ _percussionMask = kDefaultPercussionMask;
+ _opl->writeReg(0xBD, kDefaultPercussionMask);
+}
+
+void AdLibDriver::setModulationWheel(uint8 channel, uint8 value) {
+ if (value >= 64)
+ _percussionMask |= 0x80;
+ else
+ _percussionMask &= 0x7f;
+
+ _opl->writeReg(0xBD, _percussionMask);
+}
+
+void AdLibDriver::setFootController(uint8 channel, uint8 value) {
+ _channels[channel]._pedal = (value >= 64);
+}
+
+void AdLibDriver::setVolume(uint8 channel, uint8 value) {
+ _channels[channel]._volume = value;
+}
+
+void AdLibDriver::setPitchBend(uint8 channel, int16 value) {
+ for (uint i = 0; i < kNumMelodic; ++i) {
+ if (_voices[i]._channel != channel || !_voices[i]._used)
+ continue;
+
+ // index into frequency table
+ uint f = 12 + (_voices[i]._key % 12);
+
+ int16 bendAmount = value;
+ if (bendAmount > 0) {
+ // bend up two semitones
+ bendAmount *= (melodicFrequencies[f + 2] - melodicFrequencies[f]);
+ } else {
+ // bend down two semitones
+ bendAmount *= (melodicFrequencies[f] - melodicFrequencies[f - 2]);
+ }
+ bendAmount /= 0x2000;
+ bendAmount += melodicFrequencies[f]; // add the base frequency
+ playNote(i, _voices[i]._octave, bendAmount);
+ _voices[i]._timestamp = g_system->getMillis();
+ }
+}
+
+void AdLibDriver::playNote(uint8 voice, uint8 octave, uint16 frequency) {
+ /* Percussions are always fed keyOn = 0 even to set the note, as they are activated using the
+ BD register instead. I wonder if they can just be fed the same value as melodic voice and
+ be done with it. */
+ uint8 keyOn = (voice < kNumMelodic) ? 0x20 : 0;
+
+ // key on, octave, high 2 bits of frequency
+ _opl->writeReg(0xB0 + voice, keyOn | ((octave & 7) << 2) | ((frequency >> 8) & 3));
+ // low 8 bits of frequency
+ _opl->writeReg(0xA0 + voice, frequency & 0xff);
+}
+
+void AdLibDriver::programOperatorSimple(uint8 offset, const OPLOperator &op) {
+ _opl->writeReg(0x40 + offset, op.levels & LEVEL_MASK);
+ _opl->writeReg(0x60 + offset, op.attackDecay);
+ _opl->writeReg(0x80 + offset, op.sustainRelease);
+}
+
+void AdLibDriver::programOperator(uint8 offset, const OPLOperator &op) {
+ _opl->writeReg(0x20 + offset, op.characteristic);
+ _opl->writeReg(0x60 + offset, op.attackDecay);
+ _opl->writeReg(0x80 + offset, op.sustainRelease);
+ _opl->writeReg(0xE0 + offset, op.waveform);
+ _opl->writeReg(0x40 + offset, op.levels);
+}
+
+const uint16 adlibLogVolume[] = {
+ 0, 37, 58, 73, 85, 95, 103, 110, 116, 121, 127, 131, 135, 139, 143, 146,
+ 149, 153, 155, 158, 161, 163, 165, 168, 170, 172, 174, 176, 178, 179, 181, 183,
+ 184, 186, 188, 189, 191, 192, 193, 195, 196, 197, 198, 200, 201, 202, 203, 204,
+ 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 219,
+ 220, 221, 222, 223, 223, 224, 225, 226, 226, 227, 228, 228, 229, 230, 231, 231,
+ 232, 233, 233, 234, 234, 235, 236, 236, 237, 237, 238, 239, 239, 240, 240, 241,
+ 241, 242, 242, 243, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249,
+ 249, 250, 250, 251, 251, 252, 252, 253, 253, 253, 254, 254, 255, 255, 256, 256,
+ 256
+};
+
+void AdLibDriver::setOperatorLevel(uint8 offset, const OPLOperator &op, uint8 velocity, uint8 channel, bool forceVolume) {
+ uint8 programLevel = LEVEL_MASK;
+ if (!forceVolume)
+ programLevel -= (op.levels & LEVEL_MASK);
+
+ uint32 noteLevel = adlibLogVolume[velocity];
+ uint32 channelLevel = adlibLogVolume[_channels[channel]._volume];
+ // programLevel comes from the static data and is probably already in the correct logarithmic scale
+ uint32 finalLevel = LEVEL_MASK - ((noteLevel * channelLevel * programLevel) >> 16);
+
+ // high 2 bits are scaling level, the rest is (inversed) volume
+ _opl->writeReg(0x40 + offset, (op.levels & 0xc0) | (finalLevel & 0x3f));
+}
+
+const uint8 operatorOffsetsForPercussion[] = {
+ 0x11, // hi-hat
+ 0x15, // cymbal
+ 0x12, // tom tom
+ 0x14 // snare drum
+};
+
+void AdLibDriver::setupPercussion(const PercussionNote &note) {
+ if (note.percussion < 4) {
+ // simple percussion (1 operator)
+
+ // turn off relevant percussion
+ _percussionMask &= ~(1 << note.percussion);
+ _opl->writeReg(0xBD, _percussionMask);
+
+ programOperatorSimple(operatorOffsetsForPercussion[note.percussion], note.op[0]);
+ return;
+ }
+
+ // bass drum (2 operators)
+
+ // turn off bass drum
+ _percussionMask &= ~(0x10);
+ _opl->writeReg(0xBD, _percussionMask);
+
+ programOperator(0x10, note.op[0]);
+ programOperator(0x13, note.op[1]);
+
+ _opl->writeReg(0xC0 + 6, note.feedbackAlgo);
+}
+
+void AdLibDriver::playPercussion(uint8 channel, const PercussionNote &note, uint8 velocity) {
+ if (note.percussion < 4) {
+ // simple percussion (1 operator)
+
+ // turn off relevant percussion
+ _percussionMask &= ~(1 << note.percussion);
+ _opl->writeReg(0xBD, _percussionMask);
+
+ setOperatorLevel(operatorOffsetsForPercussion[note.percussion], note.op[0], velocity, channel, true);
+
+ if (note.percussion == 2) {
+ // tom tom
+ playNote(8, note.octave, note.frequency);
+ } else if (note.percussion == 3) {
+ // snare drum
+ playNote(7, note.octave, note.frequency);
+ }
+
+ // turn on relevant percussion
+ _percussionMask |= (1 << note.percussion);
+ _opl->writeReg(0xBD, _percussionMask);
+ return;
+ }
+
+ // turn off bass drum
+ _percussionMask &= ~(0x10);
+ _opl->writeReg(0xBD, _percussionMask);
+
+ if (note.feedbackAlgo & 1) {
+ // operators 1 and 2 in additive synthesis
+ setOperatorLevel(0x10, note.op[0], velocity, channel, true);
+ setOperatorLevel(0x13, note.op[1], velocity, channel, true);
+ } else {
+ // operator 2 is modulating operator 1
+ setOperatorLevel(0x13, note.op[1], velocity, channel, true);
+ }
+
+ playNote(6, note.octave, note.frequency);
+
+ // turn on bass drum
+ _percussionMask |= 0x10;
+ _opl->writeReg(0xBD, _percussionMask);
+}
+
+const uint8 offset1ForMelodic[kNumVoices] = { 0x0, 0x1, 0x2, 0x8, 0x9, 0xa, 0x10, 0x11, 0x12 };
+const uint8 offset2ForMelodic[kNumVoices] = { 0x3, 0x4, 0x5, 0xb, 0xc, 0xd, 0x13, 0x14, 0x15 };
+
+void AdLibDriver::programMelodicVoice(uint8 voice, uint8 program) {
+ assert(program < 128);
+ assert(voice < kNumMelodic);
+
+ const MelodicProgram &info = melodicPrograms[program];
+ uint8 offset1 = offset1ForMelodic[voice];
+ uint8 offset2 = offset2ForMelodic[voice];
+
+ // Start at lowest volume.
+ _opl->writeReg(0x40 + offset1, LEVEL_MASK);
+ _opl->writeReg(0x40 + offset2, LEVEL_MASK);
+
+ muteMelodicVoice(voice);
+
+ programOperator(offset1, info.op[0]);
+ programOperator(offset2, info.op[1]);
+
+ _opl->writeReg(0xC0 + voice, info.feedbackAlgo);
+}
+
+void AdLibDriver::playMelodicNote(uint8 voice, uint8 channel, uint8 note, uint8 velocity) {
+ assert(voice < kNumMelodic);
+
+ uint8 octave = note / 12;
+ uint8 f = 12 + (note % 12);
+
+ if (octave > 7)
+ octave = 7;
+
+ const MelodicProgram &info = melodicPrograms[_channels[channel]._program];
+ uint8 offset1 = offset1ForMelodic[voice];
+ uint8 offset2 = offset2ForMelodic[voice];
+
+ if (info.feedbackAlgo & 1) {
+ setOperatorLevel(offset1, info.op[0], velocity, channel, false);
+ setOperatorLevel(offset2, info.op[1], velocity, channel, false);
+ } else {
+ setOperatorLevel(offset2, info.op[1], velocity, channel, true);
+ }
+
+ playNote(voice, octave, melodicFrequencies[f]);
+
+ _voices[voice]._program = _channels[channel]._program;
+ _voices[voice]._key = note;
+ _voices[voice]._channel = channel;
+ _voices[voice]._timestamp = g_system->getMillis();
+ _voices[voice]._frequency = melodicFrequencies[f];
+ _voices[voice]._octave = octave;
+ _voices[voice]._used = true;
+}
+
+void AdLibDriver::muteMelodicVoice(uint8 voice) {
+ _opl->writeReg(0xB0 + voice, 0 | ((_voices[voice]._octave & 7) << 2) | ((_voices[voice]._frequency >> 8) & 3));
+}
+
+MidiChannel *AdLibDriver::allocateChannel() {
+ for (uint i = 0; i < 16; ++i) {
+ if (i == 9)
+ continue;
+
+ if (_channels[i].allocate())
+ return &_channels[i];
+ }
+
+ return NULL;
+}
+
+void AdLibDriver::generateSamples(int16 *buf, int len) {
+ memset(buf, 0, sizeof(int16) * len);
+ _opl->readBuffer(buf, len);
+}
+
+void AdLibDriver::initVoices() {
+ _percussionMask = kDefaultPercussionMask;
+ _opl->writeReg(0xBD, _percussionMask);
+
+ for (uint i = 0; i < 16; ++i)
+ _channels[i].reset();
+
+ for (uint i = 0; i < kNumMelodic; ++i) {
+ _voices[i]._key = 0xff;
+ _voices[i]._program = 0xff;
+ _voices[i]._channel = 0xff;
+ _voices[i]._timestamp = 0;
+ _voices[i]._frequency = 0;
+ _voices[i]._octave = 0;
+ _voices[i]._used = false;
+ }
+
+ for (uint i = 0; i < kNumPercussion; ++i)
+ _notesPerPercussion[i] = 0xff;
+
+ _lastVoice = 0;
+}
+
+} // namespace Parallaction
diff --git a/engines/parallaction/callables_ns.cpp b/engines/parallaction/callables_ns.cpp
index 64885c7ff3..c1720a1a8e 100644
--- a/engines/parallaction/callables_ns.cpp
+++ b/engines/parallaction/callables_ns.cpp
@@ -275,7 +275,7 @@ void Parallaction_ns::_c_contaFoglie(void *parm) {
if (num_foglie != 6)
return;
- _globalFlags |= 0x1000;
+ g_globalFlags |= 0x1000;
return;
}
@@ -286,7 +286,7 @@ void Parallaction_ns::_c_zeroFoglie(void *parm) {
}
void Parallaction_ns::_c_trasformata(void *parm) {
- _engineFlags ^= kEngineTransformedDonna;
+ g_engineFlags ^= kEngineTransformedDonna;
// No need to invoke changeCharacter here, as
// transformation happens on a location switch
// and character change is automatically triggered.
@@ -295,11 +295,11 @@ void Parallaction_ns::_c_trasformata(void *parm) {
void Parallaction_ns::_c_offMouse(void *parm) {
_input->setMouseState(MOUSE_DISABLED);
- _engineFlags |= kEngineBlockInput;
+ g_engineFlags |= kEngineBlockInput;
}
void Parallaction_ns::_c_onMouse(void *parm) {
- _engineFlags &= ~kEngineBlockInput;
+ g_engineFlags &= ~kEngineBlockInput;
_input->setMouseState(MOUSE_ENABLED_SHOW);
}
@@ -389,7 +389,7 @@ void Parallaction_ns::_c_finito(void *parm) {
}
void Parallaction_ns::_c_ridux(void *parm) {
- changeCharacter(_minidinoName);
+ changeCharacter(g_minidinoName);
return;
}
@@ -444,7 +444,7 @@ void Parallaction_ns::_c_startIntro(void *parm) {
_soundManI->playMusic();
}
- _engineFlags |= kEngineBlockInput;
+ g_engineFlags |= kEngineBlockInput;
_input->setMouseState(MOUSE_DISABLED);
_intro = true;
}
diff --git a/engines/parallaction/debug.cpp b/engines/parallaction/debug.cpp
index 0cb329e0f0..25acac9b06 100644
--- a/engines/parallaction/debug.cpp
+++ b/engines/parallaction/debug.cpp
@@ -103,7 +103,7 @@ bool Debugger::Cmd_Locations(int argc, const char **argv) {
bool Debugger::Cmd_GlobalFlags(int argc, const char **argv) {
- uint32 flags = _globalFlags;
+ uint32 flags = g_globalFlags;
DebugPrintf("+------------------------------+---------+\n"
"| flag name | value |\n"
@@ -128,10 +128,10 @@ bool Debugger::Cmd_ToggleGlobalFlag(int argc, const char **argv) {
DebugPrintf("invalid flag '%s'\n", argv[1]);
} else {
i--;
- if ((_globalFlags & (1 << i)) == 0)
- _globalFlags |= (1 << i);
+ if ((g_globalFlags & (1 << i)) == 0)
+ g_globalFlags |= (1 << i);
else
- _globalFlags &= ~(1 << i);
+ g_globalFlags &= ~(1 << i);
}
break;
diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp
index e0bd6a6677..78cc23311f 100644
--- a/engines/parallaction/dialogue.cpp
+++ b/engines/parallaction/dialogue.cpp
@@ -192,7 +192,7 @@ void DialogueManager::transitionToState(DialogueState newState) {
bool DialogueManager::testAnswerFlags(Answer *a) {
uint32 flags = _vm->getLocationFlags();
if (a->_yesFlags & kFlagsGlobal)
- flags = _globalFlags | kFlagsGlobal;
+ flags = g_globalFlags | kFlagsGlobal;
return ((a->_yesFlags & flags) == a->_yesFlags) && ((a->_noFlags & ~flags) == a->_noFlags);
}
@@ -370,9 +370,9 @@ protected:
bool _askPassword;
bool checkPassword() {
- return ((!scumm_stricmp(_vm->_char.getBaseName(), _doughName) && _vm->_password.hasPrefix("1732461")) ||
- (!scumm_stricmp(_vm->_char.getBaseName(), _donnaName) && _vm->_password.hasPrefix("1622")) ||
- (!scumm_stricmp(_vm->_char.getBaseName(), _dinoName) && _vm->_password.hasPrefix("179")));
+ return ((!scumm_stricmp(_vm->_char.getBaseName(), g_doughName) && _vm->_password.hasPrefix("1732461")) ||
+ (!scumm_stricmp(_vm->_char.getBaseName(), g_donnaName) && _vm->_password.hasPrefix("1622")) ||
+ (!scumm_stricmp(_vm->_char.getBaseName(), g_dinoName) && _vm->_password.hasPrefix("179")));
}
void resetPassword() {
diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp
index ee981a2c7d..8988897456 100644
--- a/engines/parallaction/disk_br.cpp
+++ b/engines/parallaction/disk_br.cpp
@@ -31,7 +31,7 @@
namespace Parallaction {
-extern byte _braAmigaFramesDefaultPalette[];
+extern byte braAmigaFramesDefaultPalette[];
struct Sprite {
uint16 size;
@@ -475,7 +475,7 @@ void AmigaDisk_br::loadBackground(BackgroundInfo& info, const char *filename) {
}
delete stream;
} else {
- p = _braAmigaFramesDefaultPalette;
+ p = braAmigaFramesDefaultPalette;
for (i = 0; i < 16; i++) {
r = *p >> 2;
p++;
diff --git a/engines/parallaction/disk_ns.cpp b/engines/parallaction/disk_ns.cpp
index 8d4afd6847..bad854525d 100644
--- a/engines/parallaction/disk_ns.cpp
+++ b/engines/parallaction/disk_ns.cpp
@@ -262,8 +262,15 @@ Common::SeekableReadStream *DosDisk_ns::tryOpenFile(const char* name) {
Script* Disk_ns::loadLocation(const char *name) {
char path[PATH_LEN];
+ const char *charName = _vm->_char.getBaseName();
- sprintf(path, "%s%s/%s.loc", _vm->_char.getBaseName(), _language.c_str(), name);
+ // WORKAROUND: Special case for the Multilingual DOS version: during the ending
+ // sequence, it tries to load a non-existing file using "Dinor" as a character
+ // name. In this case, the character name should be just "dino".
+ if (!strcmp(charName, "Dinor"))
+ charName = "dino";
+
+ sprintf(path, "%s%s/%s.loc", charName, _language.c_str(), name);
debugC(3, kDebugDisk, "Disk_ns::loadLocation(%s): trying '%s'", name, path);
Common::SeekableReadStream *stream = tryOpenFile(path);
@@ -328,7 +335,7 @@ GfxObj* DosDisk_ns::loadTalk(const char *name) {
}
char v20[30];
- if (_engineFlags & kEngineTransformedDonna) {
+ if (g_engineFlags & kEngineTransformedDonna) {
sprintf(v20, "%stta.cnv", name);
} else {
sprintf(v20, "%stal.cnv", name);
diff --git a/engines/parallaction/exec.cpp b/engines/parallaction/exec.cpp
index 8594d02641..122abf9e0e 100644
--- a/engines/parallaction/exec.cpp
+++ b/engines/parallaction/exec.cpp
@@ -56,7 +56,7 @@ void ProgramExec::runScript(ProgramPtr script, AnimationPtr a) {
}
void ProgramExec::runScripts(ProgramList::iterator first, ProgramList::iterator last) {
- if (_engineFlags & kEnginePauseJobs) {
+ if (g_engineFlags & kEnginePauseJobs) {
return;
}
@@ -110,7 +110,7 @@ void CommandExec::runList(CommandList::iterator first, CommandList::iterator las
}
if (cmd->_flagsOn & kFlagsGlobal) {
- useFlags = _globalFlags | kFlagsGlobal;
+ useFlags = g_globalFlags | kFlagsGlobal;
useLocalFlags = false;
} else {
useFlags = _vm->getLocationFlags();
@@ -182,7 +182,7 @@ void CommandExec::suspend() {
}
void CommandExec::runSuspended() {
- if (_engineFlags & kEngineWalking) {
+ if (g_engineFlags & kEngineWalking) {
return;
}
diff --git a/engines/parallaction/exec_br.cpp b/engines/parallaction/exec_br.cpp
index 658ef5af82..985ea29311 100644
--- a/engines/parallaction/exec_br.cpp
+++ b/engines/parallaction/exec_br.cpp
@@ -307,7 +307,7 @@ DECLARE_COMMAND_OPCODE(testsfx) {
DECLARE_COMMAND_OPCODE(ret) {
- _engineFlags |= kEngineReturn;
+ g_engineFlags |= kEngineReturn;
}
@@ -327,7 +327,7 @@ DECLARE_INSTRUCTION_OPCODE(invalid) {
DECLARE_COMMAND_OPCODE(clear) {
if (ctxt._cmd->_flags & kFlagsGlobal) {
ctxt._cmd->_flags &= ~kFlagsGlobal;
- _globalFlags &= ~ctxt._cmd->_flags;
+ g_globalFlags &= ~ctxt._cmd->_flags;
} else {
_vm->clearLocationFlags(ctxt._cmd->_flags);
}
@@ -356,7 +356,7 @@ DECLARE_COMMAND_OPCODE(get) {
DECLARE_COMMAND_OPCODE(toggle) {
if (ctxt._cmd->_flags & kFlagsGlobal) {
ctxt._cmd->_flags &= ~kFlagsGlobal;
- _globalFlags ^= ctxt._cmd->_flags;
+ g_globalFlags ^= ctxt._cmd->_flags;
} else {
_vm->toggleLocationFlags(ctxt._cmd->_flags);
}
@@ -373,7 +373,7 @@ DECLARE_COMMAND_OPCODE(invalid) {
DECLARE_COMMAND_OPCODE(set) {
if (ctxt._cmd->_flags & kFlagsGlobal) {
ctxt._cmd->_flags &= ~kFlagsGlobal;
- _globalFlags |= ctxt._cmd->_flags;
+ g_globalFlags |= ctxt._cmd->_flags;
} else {
_vm->setLocationFlags(ctxt._cmd->_flags);
}
diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp
index d8fbdea971..3ea4332e50 100644
--- a/engines/parallaction/exec_ns.cpp
+++ b/engines/parallaction/exec_ns.cpp
@@ -151,7 +151,7 @@ DECLARE_INSTRUCTION_OPCODE(call) {
DECLARE_INSTRUCTION_OPCODE(wait) {
- if (_engineFlags & kEngineWalking) {
+ if (g_engineFlags & kEngineWalking) {
ctxt._ip--;
ctxt._suspend = true;
}
@@ -198,7 +198,7 @@ DECLARE_COMMAND_OPCODE(invalid) {
DECLARE_COMMAND_OPCODE(set) {
if (ctxt._cmd->_flags & kFlagsGlobal) {
ctxt._cmd->_flags &= ~kFlagsGlobal;
- _globalFlags |= ctxt._cmd->_flags;
+ g_globalFlags |= ctxt._cmd->_flags;
} else {
_vm->setLocationFlags(ctxt._cmd->_flags);
}
@@ -208,7 +208,7 @@ DECLARE_COMMAND_OPCODE(set) {
DECLARE_COMMAND_OPCODE(clear) {
if (ctxt._cmd->_flags & kFlagsGlobal) {
ctxt._cmd->_flags &= ~kFlagsGlobal;
- _globalFlags &= ~ctxt._cmd->_flags;
+ g_globalFlags &= ~ctxt._cmd->_flags;
} else {
_vm->clearLocationFlags(ctxt._cmd->_flags);
}
@@ -267,7 +267,7 @@ DECLARE_COMMAND_OPCODE(call) {
DECLARE_COMMAND_OPCODE(toggle) {
if (ctxt._cmd->_flags & kFlagsGlobal) {
ctxt._cmd->_flags &= ~kFlagsGlobal;
- _globalFlags ^= ctxt._cmd->_flags;
+ g_globalFlags ^= ctxt._cmd->_flags;
} else {
_vm->toggleLocationFlags(ctxt._cmd->_flags);
}
diff --git a/engines/parallaction/font.cpp b/engines/parallaction/font.cpp
index d4c9aefd32..3b40960381 100644
--- a/engines/parallaction/font.cpp
+++ b/engines/parallaction/font.cpp
@@ -29,7 +29,7 @@
namespace Parallaction {
-extern byte _amigaTopazFont[];
+extern byte amigaTopazFont[];
class BraFont : public Font {
@@ -675,7 +675,7 @@ void Parallaction_ns::initFonts() {
_introFont = _disk->loadFont("slide");
} else {
_dialogueFont = _disk->loadFont("comic");
- Common::MemoryReadStream stream(_amigaTopazFont, 2600, DisposeAfterUse::NO);
+ Common::MemoryReadStream stream(amigaTopazFont, 2600, DisposeAfterUse::NO);
_labelFont = new AmigaFont(stream);
_menuFont = _disk->loadFont("slide");
_introFont = _disk->loadFont("intro");
diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp
index 852235ce34..a9889cc7af 100644
--- a/engines/parallaction/gfxbase.cpp
+++ b/engines/parallaction/gfxbase.cpp
@@ -152,22 +152,22 @@ void Gfx::freeCharacterObjects() {
freeDialogueObjects();
}
-void BackgroundInfo::loadGfxObjMask(const char *name, GfxObj *obj) {
+void BackgroundInfo::loadGfxObjMask(Parallaction *vm, const char *name, GfxObj *obj) {
debugC(1, kDebugGraphics, "BackgroundInfo::loadGfxObjMask(\"%s\")", name);
Common::Rect rect;
obj->getRect(0, rect);
- MaskBuffer *buf = _vm->_disk->loadMask(name, rect.width(), rect.height());
+ MaskBuffer *buf = vm->_disk->loadMask(name, rect.width(), rect.height());
obj->_maskId = addMaskPatch(buf);
obj->_hasMask = true;
}
-void BackgroundInfo::loadGfxObjPath(const char *name, GfxObj *obj) {
+void BackgroundInfo::loadGfxObjPath(Parallaction *vm, const char *name, GfxObj *obj) {
Common::Rect rect;
obj->getRect(0, rect);
- PathBuffer *buf = _vm->_disk->loadPath(name, rect.width(), rect.height());
+ PathBuffer *buf = vm->_disk->loadPath(name, rect.width(), rect.height());
obj->_pathId = addPathPatch(buf);
obj->_hasPath = true;
@@ -226,6 +226,11 @@ void Gfx::drawGfxObject(GfxObj *obj, Graphics::Surface &surf) {
rect.translate(x, y);
data = obj->getData(obj->frame);
+ // WORKAROUND: During the end credits, game scripts try to show a
+ // non-existing frame. We change it to an existing one here.
+ if (obj->frame == 14 && obj->getNum() == 9 && !strcmp(obj->getName(), "Dinor"))
+ obj->frame = 8;
+
if (obj->getSize(obj->frame) == obj->getRawSize(obj->frame)) {
blt(rect, data, &surf, obj->layer, obj->scale, obj->transparentKey);
} else {
diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp
index 9855830478..59cd02e6ef 100644
--- a/engines/parallaction/graphics.cpp
+++ b/engines/parallaction/graphics.cpp
@@ -80,11 +80,11 @@ void drawCircle(int xCenter, int yCenter, int radius, int color, void (*plotProc
Palette::Palette() {
- int gameType = _vm->getGameType();
+ int gameType = g_vm->getGameType();
if (gameType == GType_Nippon) {
_colors = 32;
- _hb = (_vm->getPlatform() == Common::kPlatformAmiga);
+ _hb = (g_vm->getPlatform() == Common::kPlatformAmiga);
} else
if (gameType == GType_BRA) {
_colors = 256;
diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h
index f8cb4b3647..e9daabb194 100644
--- a/engines/parallaction/graphics.h
+++ b/engines/parallaction/graphics.h
@@ -377,14 +377,14 @@ public:
void toggleMaskPatch(uint id, int x, int y, bool apply);
uint16 getMaskLayer(uint16 z) const;
void finalizeMask();
- void loadGfxObjMask(const char *name, GfxObj *obj);
+ void loadGfxObjMask(Parallaction *vm, const char *name, GfxObj *obj);
// path management
bool hasPath();
uint addPathPatch(PathBuffer *patch);
void togglePathPatch(uint id, int x, int y, bool apply);
void finalizePath();
- void loadGfxObjPath(const char *name, GfxObj *obj);
+ void loadGfxObjPath(Parallaction *vm, const char *name, GfxObj *obj);
};
diff --git a/engines/parallaction/gui_ns.cpp b/engines/parallaction/gui_ns.cpp
index 3794aeae29..082c37f666 100644
--- a/engines/parallaction/gui_ns.cpp
+++ b/engines/parallaction/gui_ns.cpp
@@ -787,7 +787,7 @@ public:
}
destroyLabels();
- _engineFlags &= ~kEngineBlockInput;
+ g_engineFlags &= ~kEngineBlockInput;
return _helper->getState("selectcharacter");
}
diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp
index 453bf9849d..4fbd9b99cc 100644
--- a/engines/parallaction/input.cpp
+++ b/engines/parallaction/input.cpp
@@ -188,15 +188,15 @@ int Input::updateGameInput() {
int event = kEvNone;
if (!isMouseEnabled() ||
- (_engineFlags & kEngineBlockInput) ||
- (_engineFlags & kEngineWalking) ||
- (_engineFlags & kEngineChangeLocation)) {
+ (g_engineFlags & kEngineBlockInput) ||
+ (g_engineFlags & kEngineWalking) ||
+ (g_engineFlags & kEngineChangeLocation)) {
debugC(3, kDebugInput, "updateGameInput: input flags (mouse: %i, block: %i, walking: %i, changeloc: %i)",
isMouseEnabled(),
- (_engineFlags & kEngineBlockInput) == 0,
- (_engineFlags & kEngineWalking) == 0,
- (_engineFlags & kEngineChangeLocation) == 0
+ (g_engineFlags & kEngineBlockInput) == 0,
+ (g_engineFlags & kEngineWalking) == 0,
+ (g_engineFlags & kEngineChangeLocation) == 0
);
return event;
@@ -289,7 +289,7 @@ void Input::walkTo(const Common::Point &dest) {
bool Input::translateGameInput() {
- if (_engineFlags & kEnginePauseJobs) {
+ if (g_engineFlags & kEnginePauseJobs) {
return false;
}
@@ -312,7 +312,7 @@ bool Input::translateGameInput() {
// test if mouse is hovering on an interactive zone for the currently selected inventory item
ZonePtr z = _vm->hitZone(_activeItem._id, mousePos.x, mousePos.y);
- if (((_mouseButtons == kMouseLeftUp) && (_activeItem._id == 0) && ((_engineFlags & kEngineWalking) == 0)) && ((!z) || (ACTIONTYPE(z) != kZoneCommand))) {
+ if (((_mouseButtons == kMouseLeftUp) && (_activeItem._id == 0) && ((g_engineFlags & kEngineWalking) == 0)) && ((!z) || (ACTIONTYPE(z) != kZoneCommand))) {
walkTo(mousePos);
return true;
}
@@ -361,7 +361,7 @@ void Input::enterInventoryMode() {
if (hitCharacter) {
if (_activeItem._id != 0) {
_activeItem._index = (_activeItem._id >> 16) & 0xFFFF;
- _engineFlags |= kEngineDragging;
+ g_engineFlags |= kEngineDragging;
} else {
setArrowCursor();
}
@@ -384,9 +384,9 @@ void Input::exitInventoryMode() {
int pos = _vm->getHoverInventoryItem(mousePos.x, mousePos.y);
_vm->highlightInventoryItem(-1); // disable
- if ((_engineFlags & kEngineDragging)) {
+ if ((g_engineFlags & kEngineDragging)) {
- _engineFlags &= ~kEngineDragging;
+ g_engineFlags &= ~kEngineDragging;
ZonePtr z = _vm->hitZone(kZoneMerge, _activeItem._index, _vm->getInventoryItemIndex(pos));
if (z) {
diff --git a/engines/parallaction/module.mk b/engines/parallaction/module.mk
index d65653cd92..36572a51df 100644
--- a/engines/parallaction/module.mk
+++ b/engines/parallaction/module.mk
@@ -1,6 +1,7 @@
MODULE := engines/parallaction
MODULE_OBJS := \
+ adlib.o \
balloons.o \
callables_br.o \
callables_ns.o \
diff --git a/engines/parallaction/objects.cpp b/engines/parallaction/objects.cpp
index d3529c5dd9..50556c3ec4 100644
--- a/engines/parallaction/objects.cpp
+++ b/engines/parallaction/objects.cpp
@@ -203,7 +203,7 @@ Zone::Zone() {
}
Zone::~Zone() {
- _vm->_gfx->unregisterLabel(_label);
+ g_vm->_gfx->unregisterLabel(_label);
delete _label;
}
@@ -325,7 +325,7 @@ int16 ScriptVar::getValue() {
}
if (_flags & kParaRandom) {
- return (_vm->_rnd.getRandomNumber(65536) * _value) >> 16;
+ return (g_vm->_rnd.getRandomNumber(65536) * _value) >> 16;
}
error("Parameter is not an r-value");
diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp
index 3b1b7d54a0..e6ef53aa78 100644
--- a/engines/parallaction/parallaction.cpp
+++ b/engines/parallaction/parallaction.cpp
@@ -33,12 +33,12 @@
#include "parallaction/walk.h"
namespace Parallaction {
-Parallaction *_vm = NULL;
+Parallaction *g_vm = NULL;
// public stuff
-char _saveData1[30] = { '\0' };
-uint32 _engineFlags = 0;
-uint32 _globalFlags = 0;
+char g_saveData1[30] = { '\0' };
+uint32 g_engineFlags = 0;
+uint32 g_globalFlags = 0;
// private stuff
@@ -48,7 +48,7 @@ Parallaction::Parallaction(OSystem *syst, const PARALLACTIONGameDescription *gam
// Setup mixer
syncSoundSettings();
- _vm = this;
+ g_vm = this;
DebugMan.addDebugChannel(kDebugDialogue, "dialogue", "Dialogues debug level");
DebugMan.addDebugChannel(kDebugParser, "parser", "Parser debug level");
DebugMan.addDebugChannel(kDebugDisk, "disk", "Disk debug level");
@@ -87,7 +87,7 @@ Parallaction::~Parallaction() {
Common::Error Parallaction::init() {
_gameType = getGameType();
- _engineFlags = 0;
+ g_engineFlags = 0;
_objectsNames = NULL;
_globalFlagsNames = NULL;
_location._hasSound = false;
@@ -129,13 +129,9 @@ GUI::Debugger *Parallaction::getDebugger() {
return _debugger;
}
-bool canScroll() {
- return (_vm->_gfx->_backgroundInfo->width > _vm->_screenWidth);
-}
-
void Parallaction::updateView() {
- if ((_engineFlags & kEnginePauseJobs) && (_input->_inputMode != Input::kInputModeInventory)) {
+ if ((g_engineFlags & kEnginePauseJobs) && (_input->_inputMode != Input::kInputModeInventory)) {
return;
}
@@ -147,14 +143,14 @@ void Parallaction::updateView() {
void Parallaction::pauseJobs() {
debugC(9, kDebugExec, "pausing jobs execution");
- _engineFlags |= kEnginePauseJobs;
+ g_engineFlags |= kEnginePauseJobs;
return;
}
void Parallaction::resumeJobs() {
debugC(9, kDebugExec, "resuming jobs execution");
- _engineFlags &= ~kEnginePauseJobs;
+ g_engineFlags &= ~kEnginePauseJobs;
return;
}
@@ -265,7 +261,7 @@ void Parallaction::runGameFrame(int event) {
if (shouldQuit())
return;
- if (_engineFlags & kEngineChangeLocation) {
+ if (g_engineFlags & kEngineChangeLocation) {
changeLocation();
}
@@ -900,14 +896,14 @@ void CharacterName::bind(const char *name) {
if (!_dummy) {
if (!strcmp(name, "donna")) {
- _engineFlags &= ~kEngineTransformedDonna;
+ g_engineFlags &= ~kEngineTransformedDonna;
} else {
- if (_engineFlags & kEngineTransformedDonna) {
+ if (g_engineFlags & kEngineTransformedDonna) {
_suffix = _suffixTras;
} else {
const char *s = strstr(name, "tras");
if (s) {
- _engineFlags |= kEngineTransformedDonna;
+ g_engineFlags |= kEngineTransformedDonna;
_suffix = _suffixTras;
end = s;
}
@@ -953,7 +949,7 @@ void Parallaction::beep() {
void Parallaction::scheduleLocationSwitch(const char *location) {
debugC(9, kDebugExec, "scheduleLocationSwitch(%s)\n", location);
_newLocationName = location;
- _engineFlags |= kEngineChangeLocation;
+ g_engineFlags |= kEngineChangeLocation;
}
} // End of namespace Parallaction
diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h
index 0d56b62e2f..2dbb0227d6 100644
--- a/engines/parallaction/parallaction.h
+++ b/engines/parallaction/parallaction.h
@@ -104,17 +104,17 @@ struct PARALLACTIONGameDescription;
-extern uint32 _engineFlags;
-extern char _saveData1[];
-extern uint32 _globalFlags;
-extern const char *_dinoName;
-extern const char *_donnaName;
-extern const char *_doughName;
-extern const char *_drkiName;
-extern const char *_minidinoName;
-extern const char *_minidonnaName;
-extern const char *_minidoughName;
-extern const char *_minidrkiName;
+extern uint32 g_engineFlags;
+extern char g_saveData1[];
+extern uint32 g_globalFlags;
+extern const char *g_dinoName;
+extern const char *g_donnaName;
+extern const char *g_doughName;
+extern const char *g_drkiName;
+extern const char *g_minidinoName;
+extern const char *g_minidonnaName;
+extern const char *g_minidoughName;
+extern const char *g_minidrkiName;
@@ -601,7 +601,7 @@ private:
void _c_password(void *);
};
-extern Parallaction *_vm;
+extern Parallaction *g_vm;
} // End of namespace Parallaction
diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp
index 658a8e8795..07755fac5f 100644
--- a/engines/parallaction/parallaction_br.cpp
+++ b/engines/parallaction/parallaction_br.cpp
@@ -79,7 +79,7 @@ Common::Error Parallaction_br::init() {
_cmdExec = new CommandExec_br(this);
_programExec = new ProgramExec_br(this);
- _walker = new PathWalker_BR;
+ _walker = new PathWalker_BR(this);
_part = -1;
_nextPart = -1;
@@ -161,10 +161,10 @@ Common::Error Parallaction_br::go() {
// initCharacter();
- while (((_engineFlags & kEngineReturn) == 0) && (!shouldQuit())) {
+ while (((g_engineFlags & kEngineReturn) == 0) && (!shouldQuit())) {
runGame();
}
- _engineFlags &= ~kEngineReturn;
+ g_engineFlags &= ~kEngineReturn;
cleanupGame();
}
@@ -259,7 +259,7 @@ void Parallaction_br::cleanupGame() {
_countersNames = 0;
_numLocations = 0;
- _globalFlags = 0;
+ g_globalFlags = 0;
memset(_localFlags, 0, sizeof(_localFlags));
memset(_locationNames, 0, sizeof(_locationNames));
memset(_zoneFlags, 0, sizeof(_zoneFlags));
@@ -275,7 +275,7 @@ void Parallaction_br::changeLocation() {
cleanupGame();
// more cleanup needed for part changes (see also saveload)
- _globalFlags = 0;
+ g_globalFlags = 0;
cleanInventory(true);
strcpy(_characterName1, "null");
@@ -358,7 +358,7 @@ void Parallaction_br::changeLocation() {
// TODO: implement the music commands which control music execution
_soundMan->execute(SC_PLAYMUSIC);
- _engineFlags &= ~kEngineChangeLocation;
+ g_engineFlags &= ~kEngineChangeLocation;
_newLocationName.clear();
_nextPart = -1;
}
@@ -548,7 +548,7 @@ void Parallaction_br::scheduleWalk(int16 x, int16 y, bool fromUser) {
}
}
- _engineFlags |= kEngineWalking;
+ g_engineFlags |= kEngineWalking;
}
void Parallaction_br::setFollower(const Common::String &name) {
diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp
index 0b92db1f0a..d33be0aa47 100644
--- a/engines/parallaction/parallaction_ns.cpp
+++ b/engines/parallaction/parallaction_ns.cpp
@@ -182,7 +182,7 @@ Common::Error Parallaction_ns::init() {
_cmdExec = new CommandExec_ns(this);
_programExec = new ProgramExec_ns(this);
- _walker = new PathWalker_NS;
+ _walker = new PathWalker_NS(this);
_sarcophagusDeltaX = 0;
_movingSarcophagus = false;
@@ -310,6 +310,7 @@ void Parallaction_ns::changeBackground(const char* background, const char* mask,
_system->delayMillis(20);
_gfx->setPalette(pal);
_gfx->updateScreen();
+ return;
}
if (path == 0) {
@@ -382,8 +383,8 @@ void Parallaction_ns::changeLocation() {
changeCharacter(locname.character());
}
- strcpy(_saveData1, locname.location());
- parseLocation(_saveData1);
+ strcpy(g_saveData1, locname.location());
+ parseLocation(g_saveData1);
if (_location._startPosition.x != -1000) {
_char._ani->setX(_location._startPosition.x);
@@ -399,7 +400,7 @@ void Parallaction_ns::changeLocation() {
// BUG #1837503: kEngineChangeLocation flag must be cleared *before* commands
// and acommands are executed, so that it can be set again if needed.
- _engineFlags &= ~kEngineChangeLocation;
+ g_engineFlags &= ~kEngineChangeLocation;
_cmdExec->run(_location._commands);
@@ -412,6 +413,11 @@ void Parallaction_ns::changeLocation() {
if (!_intro) {
_input->setMouseState(oldMouseState);
+ // WORKAROUND: Fix a script bug in the Multilingual DOS version of
+ // Nippon Safes: the mouse cursor is incorrectly hidden outside the
+ // cave at the end of the game. Fix it here.
+ if (!strcmp(_location._name, "ingressocav"))
+ _input->setMouseState(MOUSE_ENABLED_SHOW);
}
debugC(1, kDebugExec, "changeLocation() done");
@@ -526,10 +532,10 @@ void Parallaction_ns::cleanupGame() {
_soundManI->stopMusic();
_inTestResult = false;
- _engineFlags &= ~kEngineTransformedDonna;
+ g_engineFlags &= ~kEngineTransformedDonna;
_numLocations = 0;
- _globalFlags = 0;
+ g_globalFlags = 0;
memset(_localFlags, 0, sizeof(_localFlags));
memset(_locationNames, 0, sizeof(_locationNames));
@@ -553,7 +559,7 @@ void Parallaction_ns::scheduleWalk(int16 x, int16 y, bool fromUser) {
}
_walker->buildPath(a, x, y);
- _engineFlags |= kEngineWalking;
+ g_engineFlags |= kEngineWalking;
}
}// namespace Parallaction
diff --git a/engines/parallaction/parser_br.cpp b/engines/parallaction/parser_br.cpp
index 0904dbf655..e7f1b1b1ed 100644
--- a/engines/parallaction/parser_br.cpp
+++ b/engines/parallaction/parser_br.cpp
@@ -767,10 +767,10 @@ void LocationParser_br::parseGetData(ZonePtr z) {
data->_gfxobj = obj;
} else
if (!scumm_stricmp(_tokens[0], "mask")) {
- _out->_info->loadGfxObjMask(_tokens[1], data->_gfxobj);
+ _out->_info->loadGfxObjMask(_vm, _tokens[1], data->_gfxobj);
} else
if (!scumm_stricmp(_tokens[0], "path")) {
- _out->_info->loadGfxObjPath(_tokens[1], data->_gfxobj);
+ _out->_info->loadGfxObjPath(_vm, _tokens[1], data->_gfxobj);
} else
if (!scumm_stricmp(_tokens[0], "icon")) {
data->_getIcon = 4 + _vm->_objectsNames->lookup(_tokens[1]);
diff --git a/engines/parallaction/parser_ns.cpp b/engines/parallaction/parser_ns.cpp
index f1d1db53e9..41ff74f0b4 100644
--- a/engines/parallaction/parser_ns.cpp
+++ b/engines/parallaction/parser_ns.cpp
@@ -246,7 +246,7 @@ DECLARE_ANIM_PARSER(file) {
char vC8[200];
strcpy(vC8, _tokens[1]);
- if (_engineFlags & kEngineTransformedDonna) {
+ if (g_engineFlags & kEngineTransformedDonna) {
if (!scumm_stricmp(_tokens[1], "donnap") || !scumm_stricmp(_tokens[1], "donnapa")) {
strcat(vC8, "tras");
}
diff --git a/engines/parallaction/saveload.cpp b/engines/parallaction/saveload.cpp
index 8de2d89b18..2ecc5377a4 100644
--- a/engines/parallaction/saveload.cpp
+++ b/engines/parallaction/saveload.cpp
@@ -88,7 +88,7 @@ void SaveLoad_ns::doLoadGame(uint16 slot) {
_vm->_score = atoi(s.c_str());
s = f->readLine();
- _globalFlags = atoi(s.c_str());
+ g_globalFlags = atoi(s.c_str());
s = f->readLine();
_vm->_numLocations = atoi(s.c_str());
@@ -151,7 +151,7 @@ void SaveLoad_ns::doSaveGame(uint16 slot, const char* name) {
sprintf(s, "%s\n", _vm->_char.getFullName());
f->writeString(s);
- sprintf(s, "%s\n", _saveData1);
+ sprintf(s, "%s\n", g_saveData1);
f->writeString(s);
sprintf(s, "%d\n", _vm->_char._ani->getX());
f->writeString(s);
@@ -159,7 +159,7 @@ void SaveLoad_ns::doSaveGame(uint16 slot, const char* name) {
f->writeString(s);
sprintf(s, "%d\n", _vm->_score);
f->writeString(s);
- sprintf(s, "%u\n", _globalFlags);
+ sprintf(s, "%u\n", g_globalFlags);
f->writeString(s);
sprintf(s, "%d\n", _vm->_numLocations);
diff --git a/engines/parallaction/sound.h b/engines/parallaction/sound.h
index e875e69334..e12e50e278 100644
--- a/engines/parallaction/sound.h
+++ b/engines/parallaction/sound.h
@@ -33,6 +33,7 @@
#define PATH_LEN 200
class MidiParser;
+class MidiDriver;
namespace Parallaction {
@@ -41,6 +42,7 @@ class MidiPlayer;
class Parallaction_br;
class MidiPlayer_MSC;
+MidiDriver *createAdLibDriver();
class SoundManImpl {
public:
diff --git a/engines/parallaction/sound_br.cpp b/engines/parallaction/sound_br.cpp
index 0925e55309..ad510eb1f1 100644
--- a/engines/parallaction/sound_br.cpp
+++ b/engines/parallaction/sound_br.cpp
@@ -91,20 +91,20 @@ public:
};
void MidiParser_MSC::parseMetaEvent(EventInfo &info) {
- uint8 type = read1(_position._play_pos);
- uint8 len = read1(_position._play_pos);
+ uint8 type = read1(_position._playPos);
+ uint8 len = read1(_position._playPos);
info.ext.type = type;
info.length = len;
info.ext.data = 0;
if (type == 0x51) {
- info.ext.data = _position._play_pos;
+ info.ext.data = _position._playPos;
} else {
warning("unknown meta event 0x%02X", type);
info.ext.type = 0;
}
- _position._play_pos += len;
+ _position._playPos += len;
}
void MidiParser_MSC::parseMidiEvent(EventInfo &info) {
@@ -116,13 +116,13 @@ void MidiParser_MSC::parseMidiEvent(EventInfo &info) {
case 0xA:
case 0xB:
case 0xE:
- info.basic.param1 = read1(_position._play_pos);
- info.basic.param2 = read1(_position._play_pos);
+ info.basic.param1 = read1(_position._playPos);
+ info.basic.param2 = read1(_position._playPos);
break;
case 0xC:
case 0xD:
- info.basic.param1 = read1(_position._play_pos);
+ info.basic.param1 = read1(_position._playPos);
info.basic.param2 = 0;
break;
@@ -135,9 +135,9 @@ void MidiParser_MSC::parseMidiEvent(EventInfo &info) {
}
void MidiParser_MSC::parseNextEvent(EventInfo &info) {
- info.start = _position._play_pos;
+ info.start = _position._playPos;
- if (_position._play_pos >= _trackEnd) {
+ if (_position._playPos >= _trackEnd) {
// fake an end-of-track meta event
info.delta = 0;
info.event = 0xFF;
@@ -146,8 +146,9 @@ void MidiParser_MSC::parseNextEvent(EventInfo &info) {
return;
}
- info.delta = readVLQ(_position._play_pos);
- info.event = read1(_position._play_pos);
+ info.length = 0;
+ info.delta = readVLQ(_position._playPos);
+ info.event = read1(_position._playPos);
if (info.event == 0xFF) {
parseMetaEvent(info);
@@ -155,7 +156,7 @@ void MidiParser_MSC::parseNextEvent(EventInfo &info) {
}
if (info.event < 0x80) {
- _position._play_pos--;
+ _position._playPos--;
info.event = _lastEvent;
}
@@ -185,7 +186,7 @@ bool MidiParser_MSC::loadMusic(byte *data, uint32 size) {
_lastEvent = 0;
_trackEnd = data + size;
- _num_tracks = 1;
+ _numTracks = 1;
_tracks[0] = pos;
setTempo(500000);
@@ -224,7 +225,12 @@ MidiPlayer_MSC::MidiPlayer_MSC()
: _paused(false) {
MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
- _driver = MidiDriver::createMidi(dev);
+ const MusicType musicType = MidiDriver::getMusicType(dev);
+ if (musicType == MT_ADLIB) {
+ _driver = createAdLibDriver();
+ } else {
+ _driver = MidiDriver::createMidi(dev);
+ }
assert(_driver);
int ret = _driver->open();
diff --git a/engines/parallaction/sound_ns.cpp b/engines/parallaction/sound_ns.cpp
index dcc71e4f2f..0ee3d73556 100644
--- a/engines/parallaction/sound_ns.cpp
+++ b/engines/parallaction/sound_ns.cpp
@@ -168,13 +168,13 @@ void DosSoundMan_ns::playCharacterMusic(const char *character) {
char *name = const_cast<char *>(character);
const char *newMusicFile = 0;
- if (!scumm_stricmp(name, _dinoName)) {
+ if (!scumm_stricmp(name, g_dinoName)) {
newMusicFile = "dino";
} else
- if (!scumm_stricmp(name, _donnaName)) {
+ if (!scumm_stricmp(name, g_donnaName)) {
newMusicFile = "donna";
} else
- if (!scumm_stricmp(name, _doughName)) {
+ if (!scumm_stricmp(name, g_doughName)) {
newMusicFile = "nuts";
} else {
warning("unknown character '%s' in DosSoundMan_ns_ns::playCharacterMusic", character);
diff --git a/engines/parallaction/staticres.cpp b/engines/parallaction/staticres.cpp
index 73e78cae3c..f09b1241bc 100644
--- a/engines/parallaction/staticres.cpp
+++ b/engines/parallaction/staticres.cpp
@@ -89,14 +89,14 @@ byte Input::_resMouseArrow_BR_Amiga[512] = {
/*
This palette snippet is used for animations in Big Red Adventure.
*/
-byte _braAmigaFramesDefaultPalette[48] = {
+byte braAmigaFramesDefaultPalette[48] = {
0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0xFF, 0xE0, 0xCF, 0x7F, 0x7F, 0x7F, 0xD9, 0x9C, 0x84, 0x00,
0x9E, 0xF0, 0x91, 0xCC, 0x36, 0xFF, 0x6A, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xDC, 0x11, 0xB0, 0xEE,
0xF0, 0xFF, 0x17, 0x3D, 0x18, 0xAC, 0x3A, 0xB0, 0x00, 0x00, 0x7D, 0x00, 0x00, 0xFF, 0xA8, 0xFF,
};
-byte _amigaTopazFont[2600] = {
+byte amigaTopazFont[2600] = {
0x00, 0x00, 0x03, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x79, 0x00, 0x00, 0x03, 0xe9, 0x00, 0x00, 0x02, 0x79,
0x70, 0xff, 0x4e, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
@@ -263,7 +263,7 @@ byte _amigaTopazFont[2600] = {
};
-const char *_callableNamesRes_ns[] = {
+const char *callableNamesRes_ns[] = {
"Projector",
"HBOff",
"StartIntro",
@@ -292,7 +292,7 @@ const char *_callableNamesRes_ns[] = {
};
-const char *_callableNamesRes_br[] = {
+const char *callableNamesRes_br[] = {
"blufade",
"resetpalette",
"ferrcycle",
@@ -301,15 +301,15 @@ const char *_callableNamesRes_br[] = {
"password"
};
-const char *_dinoName = "dino";
-const char *_donnaName = "donna";
-const char *_doughName = "dough";
-const char *_drkiName = "drki";
+const char *g_dinoName = "dino";
+const char *g_donnaName = "donna";
+const char *g_doughName = "dough";
+const char *g_drkiName = "drki";
-const char *_minidinoName = "minidino";
-const char *_minidonnaName = "minidonna";
-const char *_minidoughName = "minidough";
-const char *_minidrkiName = "minidrki";
+const char *g_minidinoName = "minidino";
+const char *g_minidonnaName = "minidonna";
+const char *g_minidoughName = "minidough";
+const char *g_minidrkiName = "minidrki";
#define CALLABLE_NS(x) &Parallaction_ns::x
@@ -391,7 +391,7 @@ const Parallaction_br::Callable Parallaction_br::_amigaCallables[] = {
void Parallaction_ns::initResources() {
- _callableNames = new Table(ARRAYSIZE(_callableNamesRes_ns), _callableNamesRes_ns);
+ _callableNames = new Table(ARRAYSIZE(callableNamesRes_ns), callableNamesRes_ns);
_localFlagNames = new FixedTable(NUM_LOCATIONS, 1);
_localFlagNames->addData("visited");
@@ -406,7 +406,7 @@ void Parallaction_ns::initResources() {
void Parallaction_br::initResources() {
- _callableNames = new Table(ARRAYSIZE(_callableNamesRes_br), _callableNamesRes_br);
+ _callableNames = new Table(ARRAYSIZE(callableNamesRes_br), callableNamesRes_br);
_localFlagNames = new FixedTable(NUM_LOCATIONS, 2);
_localFlagNames->addData("visited");
diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp
index 53237db4ef..19162cd7db 100644
--- a/engines/parallaction/walk.cpp
+++ b/engines/parallaction/walk.cpp
@@ -55,27 +55,27 @@ WalkFrames _char24WalkFrames_NS = {
};
static int getPathWidth() {
- if (!_vm->_gfx->_backgroundInfo->_path) {
+ if (!g_vm->_gfx->_backgroundInfo->_path) {
warning("getPathWidth() _path is NULL!");
return 0;
} else
- return _vm->_gfx->_backgroundInfo->_path->w;
+ return g_vm->_gfx->_backgroundInfo->_path->w;
}
static int getPathHeight() {
- if (!_vm->_gfx->_backgroundInfo->_path) {
+ if (!g_vm->_gfx->_backgroundInfo->_path) {
warning("getPathHeight() _path is NULL!");
return 0;
} else
- return _vm->_gfx->_backgroundInfo->_path->h;
+ return g_vm->_gfx->_backgroundInfo->_path->h;
}
static bool isPathClear(uint16 x, uint16 y) {
- if (!_vm->_gfx->_backgroundInfo->_path) {
+ if (!g_vm->_gfx->_backgroundInfo->_path) {
warning("isPathClear() _path is NULL!");
return false;
} else
- return (_vm->_gfx->_backgroundInfo->_path->getValue(x, y) ? true : false);
+ return (g_vm->_gfx->_backgroundInfo->_path->getValue(x, y) ? true : false);
}
// adjusts position towards nearest walkable point
@@ -306,7 +306,7 @@ void PathWalker_NS::checkDoor(const Common::Point &foot) {
}
void PathWalker_NS::finalizeWalk() {
- _engineFlags &= ~kEngineWalking;
+ g_engineFlags &= ~kEngineWalking;
Common::Point foot;
_a->getFoot(foot);
@@ -316,7 +316,7 @@ void PathWalker_NS::finalizeWalk() {
}
void PathWalker_NS::walk() {
- if ((_engineFlags & kEngineWalking) == 0) {
+ if ((g_engineFlags & kEngineWalking) == 0) {
return;
}
@@ -382,7 +382,7 @@ void PathWalker_NS::updateDirection(const Common::Point& pos, const Common::Poin
_a->setF(frames->firstWalkFrame[_direction] + (_step / frames->frameRepeat[_direction]) % frames->numWalkFrames[_direction]);
}
-PathWalker_NS::PathWalker_NS() : _direction(WALK_DOWN), _step(0) {
+PathWalker_NS::PathWalker_NS(Parallaction *vm) : _direction(WALK_DOWN), _step(0), _vm(vm) {
}
bool PathWalker_BR::directPathExists(const Common::Point &from, const Common::Point &to) {
@@ -481,7 +481,7 @@ void PathWalker_BR::buildPath(State &s, uint16 x, uint16 y) {
}
void PathWalker_BR::finalizeWalk(State &s) {
- _engineFlags &= ~kEngineWalking;
+ g_engineFlags &= ~kEngineWalking;
Common::Point foot;
_character._a->getFoot(foot);
@@ -508,8 +508,8 @@ void PathWalker_BR::finalizeWalk(State &s) {
#if 0
// TODO: Input::walkTo must be extended to support destination frame in addition to coordinates
- if (_engineFlags & FINAL_WALK_FRAME) { // this flag is set in readInput()
- _engineFlags &= ~FINAL_WALK_FRAME;
+ if (g_engineFlags & FINAL_WALK_FRAME) { // this flag is set in readInput()
+ g_engineFlags &= ~FINAL_WALK_FRAME;
_ch._a->_frame = _moveToF; // from readInput()...
} else {
_ch._a->_frame = _dirFrame; // from walk()
@@ -523,7 +523,7 @@ void PathWalker_BR::finalizeWalk(State &s) {
}
void PathWalker_BR::walk() {
- if ((_engineFlags & kEngineWalking) == 0) {
+ if ((g_engineFlags & kEngineWalking) == 0) {
return;
}
@@ -714,7 +714,7 @@ void PathWalker_BR::doWalk(State &s) {
}
}
-PathWalker_BR::PathWalker_BR() {
+PathWalker_BR::PathWalker_BR(Parallaction *vm) : _vm(vm) {
_character._active = false;
_character._step = 0;
_follower._active = false;
diff --git a/engines/parallaction/walk.h b/engines/parallaction/walk.h
index 6796991f9d..ae6db6eaf1 100644
--- a/engines/parallaction/walk.h
+++ b/engines/parallaction/walk.h
@@ -49,8 +49,10 @@ class PathWalker_NS {
void checkDoor(const Common::Point &foot);
void updateDirection(const Common::Point& pos, const Common::Point& to);
+ Parallaction *_vm;
+
public:
- PathWalker_NS();
+ PathWalker_NS(Parallaction *vm);
void buildPath(AnimationPtr a, uint16 x, uint16 y);
void walk();
@@ -79,8 +81,10 @@ class PathWalker_BR {
void doWalk(State &s);
void checkTrap(const Common::Point &p);
+ Parallaction *_vm;
+
public:
- PathWalker_BR();
+ PathWalker_BR(Parallaction *vm);
~PathWalker_BR() { }
void setCharacterPath(AnimationPtr a, uint16 x, uint16 y);
diff --git a/engines/pegasus/ai/ai_action.cpp b/engines/pegasus/ai/ai_action.cpp
new file mode 100644
index 0000000000..38d639038f
--- /dev/null
+++ b/engines/pegasus/ai/ai_action.cpp
@@ -0,0 +1,78 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/ai/ai_action.h"
+#include "pegasus/ai/ai_area.h"
+
+namespace Pegasus {
+
+AICompoundAction::~AICompoundAction() {
+ for (AIActionList::iterator it = _compoundActions.begin(); it != _compoundActions.end(); it++)
+ delete *it;
+}
+
+void AICompoundAction::performAIAction(AIRule *rule) {
+ for (AIActionList::iterator it = _compoundActions.begin(); it != _compoundActions.end(); it++)
+ (*it)->performAIAction(rule);
+}
+
+AIPlayMessageAction::AIPlayMessageAction(const Common::String &movieName, bool keepLastFrame, const InputBits interruptionFilter) {
+ _movieName = movieName;
+ _keepLastFrame = keepLastFrame;
+ _interruptionFilter = interruptionFilter;
+}
+
+void AIPlayMessageAction::performAIAction(AIRule *) {
+ if (g_AIArea) {
+ g_AIArea->checkMiddleArea();
+ g_AIArea->playAIMovie(kRightAreaSignature, _movieName, _keepLastFrame, _interruptionFilter);
+ }
+}
+
+AIStartTimerAction::AIStartTimerAction(AITimerCondition *timerCondition) {
+ _timerCondition = timerCondition;
+}
+
+void AIStartTimerAction::performAIAction(AIRule *) {
+ _timerCondition->startTimer();
+}
+
+AIActivateRuleAction::AIActivateRuleAction(AIRule *rule) {
+ _rule = rule;
+}
+
+void AIActivateRuleAction::performAIAction(AIRule *) {
+ _rule->activateRule();
+}
+
+AIDeactivateRuleAction::AIDeactivateRuleAction(AIRule *rule) {
+ _rule = rule;
+}
+
+void AIDeactivateRuleAction::performAIAction(AIRule *) {
+ _rule->deactivateRule();
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/ai/ai_action.h b/engines/pegasus/ai/ai_action.h
new file mode 100644
index 0000000000..6eac976f9c
--- /dev/null
+++ b/engines/pegasus/ai/ai_action.h
@@ -0,0 +1,136 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_AI_AIACTION_H
+#define PEGASUS_AI_AIACTION_H
+
+#include "common/list.h"
+
+#include "pegasus/input.h"
+#include "pegasus/types.h"
+
+namespace Pegasus {
+
+class AIRule;
+class AITimerCondition;
+
+/////////////////////////////////////////////
+//
+// AIAction
+
+class AIAction {
+friend class AIRule;
+public:
+ AIAction() { _actionCount = 1; }
+ virtual ~AIAction() {}
+
+ virtual void performAIAction(AIRule *) = 0;
+
+ void setActionCount(const uint32 count) { _actionCount = count; }
+
+protected:
+ uint32 _actionCount;
+};
+
+typedef Common::List<AIAction *> AIActionList;
+
+/////////////////////////////////////////////
+//
+// AICompoundAction
+
+class AICompoundAction : public AIAction {
+public:
+ AICompoundAction() {}
+ virtual ~AICompoundAction();
+
+ void addAction(AIAction *action) { _compoundActions.push_back(action); }
+
+ virtual void performAIAction(AIRule *);
+
+protected:
+ AIActionList _compoundActions;
+};
+
+/////////////////////////////////////////////
+//
+// AIPlayMessageAction
+
+class AIPlayMessageAction : public AIAction {
+public:
+ AIPlayMessageAction(const Common::String &movieName, bool keepLastFrame, const InputBits = kWarningInterruption);
+
+ virtual void performAIAction(AIRule *);
+
+protected:
+ Common::String _movieName;
+ InputBits _interruptionFilter;
+ bool _keepLastFrame;
+};
+
+/////////////////////////////////////////////
+//
+// AIStartTimerAction
+
+class AIStartTimerAction : public AIAction {
+public:
+ AIStartTimerAction(AITimerCondition *);
+
+ virtual void performAIAction(AIRule *);
+
+protected:
+ AITimerCondition *_timerCondition;
+};
+
+/////////////////////////////////////////////
+//
+// AIActivateRuleAction
+
+class AIActivateRuleAction : public AIAction {
+public:
+ AIActivateRuleAction(AIRule *);
+
+ virtual void performAIAction(AIRule *);
+
+protected:
+ AIRule *_rule;
+};
+
+/////////////////////////////////////////////
+//
+// AIDeactivateRuleAction
+
+class AIDeactivateRuleAction : public AIAction {
+public:
+ AIDeactivateRuleAction(AIRule *rule);
+
+ virtual void performAIAction(AIRule *);
+
+protected:
+ AIRule *_rule;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/ai/ai_area.cpp b/engines/pegasus/ai/ai_area.cpp
new file mode 100644
index 0000000000..5ac8af8812
--- /dev/null
+++ b/engines/pegasus/ai/ai_area.cpp
@@ -0,0 +1,613 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/memstream.h"
+
+#include "pegasus/cursor.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/biochips/aichip.h"
+#include "pegasus/items/biochips/biochipitem.h"
+#include "pegasus/items/biochips/opticalchip.h"
+#include "pegasus/items/biochips/pegasuschip.h"
+#include "pegasus/items/inventory/airmask.h"
+#include "pegasus/items/inventory/inventoryitem.h"
+
+namespace Pegasus {
+
+AIArea *g_AIArea = 0;
+
+AIArea::AIArea(InputHandler *nextHandler) : InputHandler(nextHandler), _leftAreaMovie(kAILeftAreaID),
+ _middleAreaMovie(kAIMiddleAreaID), _rightAreaMovie(kAIRightAreaID), _AIMovie(kAIMovieID) {
+ g_AIArea = this;
+ _leftAreaOwner = kNoClientSignature;
+ _middleAreaOwner = kNoClientSignature;
+ _rightAreaOwner = kNoClientSignature;
+ _leftInventoryTime = 0xffffffff;
+ _middleInventoryTime = 0xffffffff;
+ _middleBiochipTime = 0xffffffff;
+ _rightBiochipTime = 0xffffffff;
+ _lockCount = 0;
+ startIdling();
+}
+
+AIArea::~AIArea() {
+ if (_middleAreaOwner == kBiochipSignature) {
+ BiochipItem *currentBiochip = ((PegasusEngine *)g_engine)->getCurrentBiochip();
+ if (currentBiochip && currentBiochip->isSelected())
+ currentBiochip->giveUpSharedArea();
+ } else if (_middleAreaOwner == kInventorySignature) {
+ InventoryItem *currentItem = ((PegasusEngine *)g_engine)->getCurrentInventoryItem();
+ if (currentItem && currentItem->isSelected())
+ currentItem->giveUpSharedArea();
+ }
+
+ stopIdling();
+
+ for (AIRuleList::iterator it = _AIRules.begin(); it != _AIRules.end(); it++)
+ delete *it;
+
+ g_AIArea = 0;
+}
+
+// Save last state of AI rules...
+void AIArea::saveAIState() {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ delete vm->_aiSaveStream;
+
+ Common::MemoryWriteStreamDynamic out;
+ writeAIRules(&out);
+
+ vm->_aiSaveStream = new Common::MemoryReadStream(out.getData(), out.size(), DisposeAfterUse::YES);
+}
+
+void AIArea::restoreAIState() {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ if (vm->_aiSaveStream)
+ readAIRules(vm->_aiSaveStream);
+}
+
+void AIArea::writeAIRules(Common::WriteStream *stream) {
+ _AIRules.writeAIRules(stream);
+}
+
+void AIArea::readAIRules(Common::ReadStream *stream) {
+ _AIRules.readAIRules(stream);
+}
+
+void AIArea::initAIArea() {
+ allocateSurface(Common::Rect(0, 0, 384, 96));
+
+ _leftAreaMovie.shareSurface(this);
+ _leftAreaMovie.initFromMovieFile("Images/Items/Left Area Movie");
+ _leftAreaMovie.moveElementTo(kAILeftAreaLeft, kAILeftAreaTop);
+ _leftAreaMovie.setDisplayOrder(kAILeftAreaOrder);
+ _leftAreaMovie.startDisplaying();
+ _leftAreaMovie.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
+
+ _middleAreaMovie.shareSurface(this);
+ _middleAreaMovie.initFromMovieFile("Images/Items/Middle Area Movie");
+ _middleAreaMovie.moveElementTo(kAIMiddleAreaLeft, kAIMiddleAreaTop);
+ _middleAreaMovie.moveMovieBoxTo(kAIMiddleAreaLeft - kAILeftAreaLeft, 0);
+ _middleAreaMovie.setDisplayOrder(kAIMiddleAreaOrder);
+ _middleAreaMovie.startDisplaying();
+ _middleAreaMovie.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
+
+ _rightAreaMovie.shareSurface(this);
+ _rightAreaMovie.initFromMovieFile("Images/Items/Right Area Movie");
+ _rightAreaMovie.moveElementTo(kAIRightAreaLeft, kAIRightAreaTop);
+ _rightAreaMovie.moveMovieBoxTo(kAIRightAreaLeft - kAILeftAreaLeft, 0);
+ _rightAreaMovie.setDisplayOrder(kAIRightAreaOrder);
+ _rightAreaMovie.startDisplaying();
+ _rightAreaMovie.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
+
+ _AIMovie.setDisplayOrder(kAIMovieOrder);
+}
+
+void AIArea::setAIVolume(const uint16 volume) {
+ _leftAreaMovie.setVolume(volume);
+ _middleAreaMovie.setVolume(volume);
+ _rightAreaMovie.setVolume(volume);
+}
+
+// There are only so many legal combinations of client/area.
+// Here is the list of supported pairs:
+// kInventorySignature kLeftAreaSignature
+// kInventorySignature kMiddleAreaSignature
+// kBiochipSignature kMiddleAreaSignature
+// kBiochipSignature kRightAreaSignature
+// kAISignature kLeftAreaSignature
+// Further, the kAISignature never sets a static frame time in the left area,
+// but only plays a sequence.
+
+// If this function is called while a sequence is playing, it will just "remember"
+// the time value, so that when the sequence finishes, the new time is asserted.
+
+void AIArea::setAIAreaToTime(const LowerClientSignature client, const LowerAreaSignature area, const TimeValue time) {
+ switch (area) {
+ case kLeftAreaSignature:
+ // Only support kInventorySignature client, since AI never calls SetAIAreaToTime.
+ _leftAreaMovie.setSegment(0, _leftAreaMovie.getDuration());
+
+ if (time == 0xffffffff) {
+ _leftAreaMovie.hide();
+ _leftAreaOwner = kNoClientSignature;
+ } else {
+ setLeftMovieTime(time);
+ }
+ break;
+ case kMiddleAreaSignature:
+ // Only support kInventorySignature and kBiochipSignature clients.
+ _middleAreaMovie.stop();
+ _middleAreaMovie.setFlags(0);
+ _middleAreaMovie.setSegment(0, _middleAreaMovie.getDuration());
+
+ if (time == 0xffffffff) {
+ if (client == kInventorySignature) {
+ if (_middleBiochipTime != 0xffffffff) {
+ setMiddleMovieTime(kBiochipSignature, _middleBiochipTime);
+ } else {
+ _middleAreaMovie.hide();
+ _middleAreaOwner = kNoClientSignature;
+ }
+ } else { // client == kBiochipSignature
+ if (_middleInventoryTime != 0xffffffff) {
+ setMiddleMovieTime(kInventorySignature, _middleInventoryTime);
+ } else {
+ _middleAreaMovie.hide();
+ _middleAreaOwner = kNoClientSignature;
+ }
+ }
+ } else {
+ setMiddleMovieTime(client, time);
+ }
+ break;
+ case kRightAreaSignature:
+ // Only support kBiochipSignature client.
+ _rightAreaMovie.setSegment(0, _rightAreaMovie.getDuration());
+
+ if (time == 0xffffffff) {
+ _rightAreaMovie.hide();
+ _rightAreaOwner = kNoClientSignature;
+ } else {
+ setRightMovieTime(time);
+ }
+ break;
+ }
+}
+
+// Plays a sequence on an area. When the sequence ends, the previous image
+// is restored.
+// Also, is input disabled or not?
+// Easy answer: yes.
+
+// There are only so many legal combinations of client/area.
+// Here is the list of supported pairs:
+// kBiochipSignature kMiddleAreaSignature
+// kBiochipSignature kRightAreaSignature
+// kInventorySignature kMiddleAreaSignature
+
+void AIArea::playAIAreaSequence(const LowerClientSignature, const LowerAreaSignature area, const TimeValue start, const TimeValue stop) {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ lockAIOut();
+
+ switch (area) {
+ case kLeftAreaSignature:
+ break;
+ case kMiddleAreaSignature:
+ if (_middleAreaOwner == kInventorySignature)
+ _middleInventoryTime = _middleAreaMovie.getTime();
+ else if (_middleAreaOwner == kBiochipSignature)
+ _middleBiochipTime = _middleAreaMovie.getTime();
+
+ _middleAreaMovie.stop();
+ _middleAreaMovie.setFlags(0);
+ _middleAreaMovie.setSegment(start, stop);
+ _middleAreaMovie.setTime(start);
+ _middleAreaMovie.show();
+ _middleAreaMovie.start();
+ vm->_cursor->hide();
+
+ while (_middleAreaMovie.isRunning()) {
+ vm->checkCallBacks();
+ vm->refreshDisplay();
+ g_system->delayMillis(10);
+ }
+
+ _middleAreaMovie.stop();
+ vm->_cursor->hideUntilMoved();
+
+ if (_middleAreaOwner == kInventorySignature)
+ setAIAreaToTime(_middleAreaOwner, kMiddleAreaSignature, _middleInventoryTime);
+ else if (_middleAreaOwner == kBiochipSignature)
+ setAIAreaToTime(_middleAreaOwner, kMiddleAreaSignature, _middleBiochipTime);
+ else
+ setAIAreaToTime(_middleAreaOwner, kMiddleAreaSignature, 0xffffffff);
+ break;
+ case kRightAreaSignature:
+ _rightBiochipTime = _rightAreaMovie.getTime();
+ _rightAreaMovie.setSegment(start, stop);
+ _rightAreaMovie.setTime(start);
+ _rightAreaMovie.show();
+ _rightAreaMovie.start();
+ vm->_cursor->hide();
+
+ while (_rightAreaMovie.isRunning()) {
+ vm->checkCallBacks();
+ vm->refreshDisplay();
+ g_system->delayMillis(10);
+ }
+
+ _rightAreaMovie.stop();
+ vm->_cursor->hideUntilMoved();
+ setAIAreaToTime(_rightAreaOwner, kRightAreaSignature, _rightBiochipTime);
+ break;
+ }
+
+ unlockAI();
+}
+
+bool AIArea::playAIMovie(const LowerAreaSignature area, const Common::String &movieName, bool keepLastFrame, const InputBits interruptFilter) {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ lockAIOut();
+
+ InputDevice.waitInput(interruptFilter);
+ if (_AIMovie.isMovieValid())
+ _AIMovie.releaseMovie();
+
+ _AIMovie.shareSurface(this);
+ _AIMovie.initFromMovieFile(movieName);
+
+ if (area == kLeftAreaSignature) {
+ _AIMovie.moveElementTo(kAILeftAreaLeft, kAILeftAreaTop);
+ _leftAreaMovie.hide();
+ } else {
+ _AIMovie.moveElementTo(kAIRightAreaLeft, kAIRightAreaTop);
+ _AIMovie.moveMovieBoxTo(kAIRightAreaLeft - kAILeftAreaLeft, 0);
+ _rightAreaMovie.hide();
+ }
+
+ _AIMovie.setTime(0);
+ _AIMovie.startDisplaying();
+ _AIMovie.show();
+ _AIMovie.redrawMovieWorld();
+ _AIMovie.setVolume(vm->getSoundFXLevel());
+ _AIMovie.start();
+ vm->_cursor->hide();
+
+ bool result = true;
+ bool saveAllowed = vm->swapSaveAllowed(false);
+ bool openAllowed = vm->swapLoadAllowed(false);
+
+ while (_AIMovie.isRunning()) {
+ Input input;
+ InputDevice.getInput(input, interruptFilter);
+
+ if (input.anyInput() || vm->shouldQuit() || vm->saveRequested() || vm->loadRequested()) {
+ result = false;
+ break;
+ }
+
+ vm->checkCallBacks();
+ vm->refreshDisplay();
+ g_system->delayMillis(10);
+ }
+
+ _AIMovie.stop();
+
+ vm->swapSaveAllowed(saveAllowed);
+ vm->swapLoadAllowed(openAllowed);
+
+ // This used to keep the last frame up even if the movie was interrupted.
+ // However, this only occurs in the recalibration, where interruption means skip the
+ // whole thing, so skipping causes the AI to go away even when keepLastFrame is true.
+
+ if (!(result && keepLastFrame)) {
+ _AIMovie.stopDisplaying();
+ _AIMovie.releaseMovie();
+
+ if (area == kLeftAreaSignature) {
+ _leftAreaMovie.setTime(_leftInventoryTime);
+ _leftAreaMovie.show();
+ _leftAreaMovie.redrawMovieWorld();
+ } else {
+ _rightAreaMovie.setTime(_rightBiochipTime);
+ _rightAreaMovie.show();
+ _rightAreaMovie.redrawMovieWorld();
+ }
+ }
+
+ vm->_cursor->hideUntilMoved();
+ unlockAI();
+ return result;
+}
+
+// Only implemented for kMiddleAreaSignature, kInventorySignature
+void AIArea::loopAIAreaSequence(const LowerClientSignature owner, const LowerAreaSignature area, const TimeValue start, const TimeValue stop) {
+ if (area == kMiddleAreaSignature && owner == kInventorySignature && owner == _middleAreaOwner) {
+ _middleAreaMovie.stop();
+ _middleAreaMovie.setFlags(0);
+ _middleAreaMovie.setSegment(start, stop);
+ _middleAreaMovie.setFlags(kLoopTimeBase);
+ _middleAreaMovie.setTime(start);
+ _middleAreaMovie.show();
+ _middleAreaMovie.start();
+ }
+}
+
+// Only called by kInventorySignature.
+void AIArea::setLeftMovieTime(const TimeValue time) {
+ if (!_AIMovie.isSurfaceValid()) {
+ _leftAreaMovie.setTime(time);
+ _leftAreaMovie.show();
+ _leftAreaMovie.redrawMovieWorld();
+ }
+
+ _leftAreaOwner = kInventorySignature;
+ _leftInventoryTime = time;
+}
+
+void AIArea::setMiddleMovieTime(const LowerClientSignature client, const TimeValue time) {
+ if (client == kInventorySignature) {
+ _middleInventoryTime = time;
+ if (_middleAreaOwner == kBiochipSignature) {
+ BiochipItem *currentBiochip = ((PegasusEngine *)g_engine)->getCurrentBiochip();
+ if (currentBiochip && currentBiochip->isSelected())
+ currentBiochip->giveUpSharedArea();
+ }
+ } else {
+ _middleBiochipTime = time;
+ if (_middleAreaOwner == kInventorySignature) {
+ InventoryItem *currentItem = ((PegasusEngine *)g_engine)->getCurrentInventoryItem();
+ if (currentItem && currentItem->isSelected())
+ currentItem->giveUpSharedArea();
+ }
+ }
+
+ _middleAreaMovie.setSegment(0, _middleAreaMovie.getDuration());
+ _middleAreaMovie.stop();
+ _middleAreaMovie.setFlags(0);
+ _middleAreaMovie.setTime(time);
+ _middleAreaMovie.show();
+ _middleAreaMovie.redrawMovieWorld();
+ _middleAreaOwner = client;
+}
+
+// Only called by kBiochipSignature.
+void AIArea::setRightMovieTime(const TimeValue time) {
+ if (!_AIMovie.isSurfaceValid()) {
+ // Can't do it when the AI movie is up...
+ _rightAreaMovie.setTime(time);
+ _rightAreaMovie.show();
+ _rightAreaMovie.redrawMovieWorld();
+ }
+
+ _rightAreaOwner = kBiochipSignature;
+ _rightBiochipTime = time;
+}
+
+void AIArea::handleInput(const Input &input, const Hotspot *cursorSpot) {
+ if (JMPPPInput::isToggleAIMiddleInput(input))
+ toggleMiddleAreaOwner();
+ else
+ InputHandler::handleInput(input, cursorSpot);
+}
+
+void AIArea::toggleMiddleAreaOwner() {
+ if (_middleAreaOwner == kInventorySignature) {
+ BiochipItem *currentBiochip = ((PegasusEngine *)g_engine)->getCurrentBiochip();
+ if (currentBiochip) {
+ setMiddleMovieTime(kBiochipSignature, currentBiochip->getSharedAreaTime());
+ currentBiochip->takeSharedArea();
+ }
+ } else if (_middleAreaOwner == kBiochipSignature) {
+ InventoryItem *currentItem = ((PegasusEngine *)g_engine)->getCurrentInventoryItem();
+ if (currentItem) {
+ setMiddleMovieTime(kInventorySignature, currentItem->getSharedAreaTime());
+ currentItem->takeSharedArea();
+ }
+ }
+}
+
+void AIArea::activateHotspots() {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ if (_middleAreaOwner == kBiochipSignature) {
+ BiochipItem *currentBiochip = ((PegasusEngine *)g_engine)->getCurrentBiochip();
+ if (currentBiochip)
+ switch (currentBiochip->getObjectID()) {
+ case kAIBiochip:
+ ((AIChip *)currentBiochip)->activateAIHotspots();
+ break;
+ case kPegasusBiochip:
+ if (!vm->isDemo())
+ ((PegasusChip *)currentBiochip)->activatePegasusHotspots();
+ break;
+ case kOpticalBiochip:
+ ((OpticalChip *)currentBiochip)->activateOpticalHotspots();
+ break;
+ }
+ } else if (_middleAreaOwner == kInventorySignature) {
+ InventoryItem *currentItem = ((PegasusEngine *)g_engine)->getCurrentInventoryItem();
+ if (currentItem && currentItem->getObjectID() == kAirMask)
+ ((AirMask *)currentItem)->activateAirMaskHotspots();
+ }
+
+ InputHandler::activateHotspots();
+}
+
+void AIArea::clickInHotspot(const Input &input, const Hotspot *hotspot) {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ bool handled = false;
+
+ if (_middleAreaOwner == kBiochipSignature) {
+ BiochipItem *currentBiochip = ((PegasusEngine *)g_engine)->getCurrentBiochip();
+
+ if (currentBiochip) {
+ switch (currentBiochip->getObjectID()) {
+ case kAIBiochip:
+ if ((hotspot->getHotspotFlags() & kAIBiochipSpotFlag) != 0) {
+ ((AIChip *)currentBiochip)->clickInAIHotspot(hotspot->getObjectID());
+ handled = true;
+ }
+ break;
+ case kPegasusBiochip:
+ if (!vm->isDemo() && ((hotspot->getHotspotFlags() & kPegasusBiochipSpotFlag) != 0)) {
+ ((PegasusChip *)currentBiochip)->clickInPegasusHotspot();
+ handled = true;
+ }
+ break;
+ case kOpticalBiochip:
+ if ((hotspot->getHotspotFlags() & kOpticalBiochipSpotFlag) != 0) {
+ ((OpticalChip *)currentBiochip)->clickInOpticalHotspot(hotspot->getObjectID());
+ handled = true;
+ }
+ break;
+ }
+ }
+ } else if (_middleAreaOwner == kInventorySignature) {
+ InventoryItem *currentItem = ((PegasusEngine *)g_engine)->getCurrentInventoryItem();
+
+ if (currentItem) {
+ switch (currentItem->getObjectID()) {
+ case kAirMask:
+ if ((hotspot->getHotspotFlags() & kAirMaskSpotFlag) != 0) {
+ ((AirMask *)currentItem)->clickInAirMaskHotspot();
+ handled = true;
+ }
+ break;
+ }
+ }
+ }
+
+ if (!handled)
+ InputHandler::clickInHotspot(input, hotspot);
+}
+
+void AIArea::lockAIOut() {
+ if (_lockCount == 0)
+ stopIdling();
+
+ _lockCount++;
+}
+
+void AIArea::unlockAI() {
+ if (_lockCount > 0) {
+ _lockCount--;
+ if (_lockCount == 0)
+ startIdling();
+ }
+}
+
+void AIArea::forceAIUnlocked() {
+ if (_lockCount > 0) {
+ _lockCount = 1;
+ unlockAI();
+ }
+}
+
+void AIArea::checkRules() {
+ if (_lockCount == 0 && ((PegasusEngine *)g_engine)->playerAlive())
+ for (AIRuleList::iterator it = _AIRules.begin(); it != _AIRules.end(); it++)
+ if ((*it)->fireRule())
+ break;
+}
+
+void AIArea::useIdleTime() {
+ checkRules();
+}
+
+void AIArea::addAIRule(AIRule *rule) {
+ _AIRules.push_back(rule);
+}
+
+void AIArea::removeAllRules() {
+ for (AIRuleList::iterator it = _AIRules.begin(); it != _AIRules.end(); it++)
+ delete *it;
+
+ _AIRules.clear();
+}
+
+void AIArea::checkMiddleArea() {
+ BiochipItem *currentBiochip = ((PegasusEngine *)g_engine)->getCurrentBiochip();
+
+ if (currentBiochip) {
+ if (_middleAreaOwner == kBiochipSignature) {
+ switch (currentBiochip->getObjectID()) {
+ case kAIBiochip:
+ ((AIChip *)currentBiochip)->setUpAIChip();
+ break;
+ case kPegasusBiochip:
+ ((PegasusChip *)currentBiochip)->setUpPegasusChip();
+ break;
+ }
+ } else {
+ switch (currentBiochip->getObjectID()) {
+ case kAIBiochip:
+ ((AIChip *)currentBiochip)->setUpAIChipRude();
+ break;
+ case kPegasusBiochip:
+ ((PegasusChip *)currentBiochip)->setUpPegasusChipRude();
+ break;
+ }
+ }
+ }
+}
+
+TimeValue AIArea::getBigInfoTime() {
+ if (_middleAreaOwner == kInventorySignature) {
+ InventoryItem *currentItem = ((PegasusEngine *)g_engine)->getCurrentInventoryItem();
+ return currentItem->getInfoLeftTime();
+ } else if (_middleAreaOwner == kBiochipSignature) {
+ BiochipItem *currentBiochip = ((PegasusEngine *)g_engine)->getCurrentBiochip();
+ return currentBiochip->getInfoLeftTime();
+ }
+
+ return 0xffffffff;
+}
+
+void AIArea::getSmallInfoSegment(TimeValue &start, TimeValue &stop) {
+ if (_middleAreaOwner == kInventorySignature) {
+ InventoryItem *currentItem = ((PegasusEngine *)g_engine)->getCurrentInventoryItem();
+ currentItem->getInfoRightTimes(start, stop);
+ } else if (_middleAreaOwner == kBiochipSignature) {
+ BiochipItem *currentBiochip = ((PegasusEngine *)g_engine)->getCurrentBiochip();
+ currentBiochip->getInfoRightTimes(start, stop);
+ } else {
+ start = 0xffffffff;
+ stop = 0xffffffff;
+ }
+}
+
+LowerClientSignature AIArea::getMiddleAreaOwner() {
+ return _middleAreaOwner;
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/ai/ai_area.h b/engines/pegasus/ai/ai_area.h
new file mode 100644
index 0000000000..806e6ef6bb
--- /dev/null
+++ b/engines/pegasus/ai/ai_area.h
@@ -0,0 +1,172 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_AI_AIAREA_H
+#define PEGASUS_AI_AIAREA_H
+
+#include "pegasus/input.h"
+#include "pegasus/movie.h"
+#include "pegasus/timers.h"
+#include "pegasus/ai/ai_rule.h"
+
+namespace Common {
+ class ReadStream;
+ class WriteStream;
+}
+
+/*
+
+ The AI area is the area at the bottom of the screen. There are three areas within
+ the AI area:
+ 1) the inventory/AI help area
+ 2) the middle area
+ 3) the biochip display area
+
+ Area 1 is used for displaying the current inventory item. When the player changes the
+ current item, either by selecting a new one in the inventory list or by picking
+ up a new item, area 1 updates to show the new item.
+
+ If the AI decides to give a message, the AI's head temporarily takes over area 1
+ for the duration of the message, then goes away, returning the area to the current
+ inventory item.
+
+ Area 2 is used to display the current inventory item's state, the current biochip's
+ state, and any extra information from the AI. The contention for this area is
+ resolved as follows:
+ -- If the AI needs to use the area while giving a message in area 1, it takes over
+ area 2 for the duration of its message.
+*** This is not true.
+ -- If the player selects a new inventory item, the inventory item's state gets
+ displayed immediately.
+ -- If the player selects a new biochip, the biochip's state info gets displayed
+ immediately.
+ -- If any auto drawing is to occur, it seizes the area as soon as the drawing is
+ to occur. For example, the mapping biochip does auto drawing every time the
+ player takes a step. The only exception to this rule is if the AI is presenting
+ a warning. When the AI seizes areas 1 and 2, it preempts all other uses.
+ Some inventory items and biochips can cause arbitrary drawing to occur in this area
+ at arbitrary times. The map biochip is one example which causes drawing when the
+ player takes a step. Another example is the poison gas canister, which flashes in
+ this area to indicate a dangerous compound.
+
+ Area 3 is used to display the current biochip. When the player changes the current
+ biochip, either by selecting a new one from the biochip list or by picking up a
+ new one, area 3 updates to show the new item. In addition, some biochips can play
+ animation in this area.
+
+*/
+
+namespace Pegasus {
+
+class AIArea : public Surface, public Idler, public InputHandler {
+public:
+ AIArea(InputHandler *);
+ virtual ~AIArea();
+
+ void writeAIRules(Common::WriteStream *stream);
+ void readAIRules(Common::ReadStream *stream);
+
+ void initAIArea();
+
+ void saveAIState();
+ void restoreAIState();
+
+ void handleInput(const Input &, const Hotspot *);
+ void activateHotspots();
+ void clickInHotspot(const Input &, const Hotspot *);
+
+ void setAIVolume(const uint16);
+
+ // There are only so many legal combinations of client/area.
+ // Here is the list of supported pairs:
+ // kInventorySignature kLeftAreaSignature
+ // kInventorySignature kMiddleAreaSignature
+ // kBiochipSignature kMiddleAreaSignature
+ // kBiochipSignature kRightAreaSignature
+ // kAISignature kLeftAreaSignature
+ // Further, the kAISignature never sets a static frame time in the left area,
+ // but only plays a sequence from the AI movie.
+ void setAIAreaToTime(const LowerClientSignature, const LowerAreaSignature, const TimeValue);
+
+ // The "Play" functions play the requested sequence synchronously.
+ void playAIAreaSequence(const LowerClientSignature, const LowerAreaSignature, const TimeValue, const TimeValue);
+
+ // For PlayAIMovie, it is assumed that the client is the AI itself.
+ // This is used to play AI messages as well as Optical Memory video.
+ // Returns true if the movie played all the way through, false if it was interrupted.
+ bool playAIMovie(const LowerAreaSignature, const Common::String &movieName, bool keepLastFrame, const InputBits);
+
+ // Loop the requested sequence indefinitely.
+ void loopAIAreaSequence(const LowerClientSignature, const LowerAreaSignature, const TimeValue, const TimeValue);
+
+ void addAIRule(AIRule *);
+
+ // Remove and delete all rules.
+ void removeAllRules();
+
+ void lockAIOut();
+ void unlockAI();
+ void forceAIUnlocked();
+
+ void checkMiddleArea();
+ void checkRules();
+
+ LowerClientSignature getMiddleAreaOwner();
+ void toggleMiddleAreaOwner();
+
+ TimeValue getBigInfoTime();
+ void getSmallInfoSegment(TimeValue &, TimeValue &);
+
+protected:
+ void useIdleTime();
+
+ void setLeftMovieTime(const TimeValue);
+ void setMiddleMovieTime(const LowerClientSignature, const TimeValue);
+ void setRightMovieTime(const TimeValue);
+
+ Movie _leftAreaMovie;
+ Movie _middleAreaMovie;
+ Movie _rightAreaMovie;
+ Movie _AIMovie;
+
+ LowerClientSignature _leftAreaOwner;
+ LowerClientSignature _middleAreaOwner;
+ LowerClientSignature _rightAreaOwner;
+
+ TimeValue _leftInventoryTime;
+ TimeValue _middleInventoryTime;
+ TimeValue _middleBiochipTime;
+ TimeValue _rightBiochipTime;
+
+ AIRuleList _AIRules;
+
+ uint _lockCount;
+};
+
+extern AIArea *g_AIArea;
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/ai/ai_condition.cpp b/engines/pegasus/ai/ai_condition.cpp
new file mode 100644
index 0000000000..9fc9272566
--- /dev/null
+++ b/engines/pegasus/ai/ai_condition.cpp
@@ -0,0 +1,290 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/stream.h"
+
+#include "pegasus/energymonitor.h"
+#include "pegasus/gamestate.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/ai/ai_condition.h"
+#include "pegasus/items/itemlist.h"
+#include "pegasus/items/biochips/biochipitem.h"
+#include "pegasus/items/inventory/inventoryitem.h"
+
+namespace Pegasus {
+
+AIOneChildCondition::AIOneChildCondition(AICondition *child) {
+ _child = child;
+}
+
+AIOneChildCondition::~AIOneChildCondition() {
+ delete _child;
+}
+
+void AIOneChildCondition::writeAICondition(Common::WriteStream *stream) {
+ if (_child)
+ _child->writeAICondition(stream);
+}
+
+void AIOneChildCondition::readAICondition(Common::ReadStream *stream) {
+ if (_child)
+ _child->readAICondition(stream);
+}
+
+AITwoChildrenCondition::AITwoChildrenCondition(AICondition *leftChild, AICondition *rightChild) {
+ _leftChild = leftChild;
+ _rightChild = rightChild;
+}
+
+AITwoChildrenCondition::~AITwoChildrenCondition() {
+ delete _leftChild;
+ delete _rightChild;
+}
+
+void AITwoChildrenCondition::writeAICondition(Common::WriteStream *stream) {
+ if (_leftChild)
+ _leftChild->writeAICondition(stream);
+
+ if (_rightChild)
+ _rightChild->writeAICondition(stream);
+}
+
+void AITwoChildrenCondition::readAICondition(Common::ReadStream *stream) {
+ if (_leftChild)
+ _leftChild->readAICondition(stream);
+
+ if (_rightChild)
+ _rightChild->readAICondition(stream);
+}
+
+AINotCondition::AINotCondition(AICondition* child) : AIOneChildCondition(child) {
+}
+
+bool AINotCondition::fireCondition() {
+ return _child && !_child->fireCondition();
+}
+
+AIAndCondition::AIAndCondition(AICondition *leftChild, AICondition *rightChild) : AITwoChildrenCondition(leftChild, rightChild) {
+}
+
+bool AIAndCondition::fireCondition() {
+ return _leftChild && _leftChild->fireCondition() && _rightChild && _rightChild->fireCondition();
+}
+
+AIOrCondition::AIOrCondition(AICondition *leftChild, AICondition *rightChild) : AITwoChildrenCondition(leftChild, rightChild) {
+}
+
+bool AIOrCondition::fireCondition() {
+ return (_leftChild && _leftChild->fireCondition()) || (_rightChild && _rightChild->fireCondition());
+}
+
+AITimerCondition::AITimerCondition(const TimeValue time, const TimeScale scale, const bool shouldStartTimer) {
+ _timerFuse.primeFuse(time, scale);
+ _timerFuse.setFunctor(new Common::Functor0Mem<void, AITimerCondition>(this, &AITimerCondition::fire));
+ _fired = false;
+
+ if (shouldStartTimer)
+ startTimer();
+}
+
+void AITimerCondition::startTimer() {
+ _fired = false;
+ _timerFuse.lightFuse();
+}
+
+void AITimerCondition::stopTimer() {
+ _timerFuse.stopFuse();
+}
+
+void AITimerCondition::writeAICondition(Common::WriteStream *stream) {
+ stream->writeByte(_timerFuse.isFuseLit());
+ stream->writeByte(_fired);
+ stream->writeUint32BE(_timerFuse.getTimeRemaining());
+ stream->writeUint32BE(_timerFuse.getFuseScale());
+}
+
+void AITimerCondition::readAICondition(Common::ReadStream *stream) {
+ bool running = stream->readByte();
+ _fired = stream->readByte();
+ TimeValue time = stream->readUint32BE();
+ TimeScale scale = stream->readUint32BE();
+
+ _timerFuse.stopFuse();
+ _timerFuse.primeFuse(time, scale);
+
+ if (running)
+ _timerFuse.lightFuse();
+}
+
+bool AITimerCondition::fireCondition() {
+ return _fired;
+}
+
+void AITimerCondition::fire() {
+ _fired = true;
+}
+
+AILocationCondition::AILocationCondition(uint32 maxLocations) {
+ _numLocations = 0;
+ _maxLocations = maxLocations;
+ _locations = new RoomViewID[maxLocations];
+}
+
+AILocationCondition::~AILocationCondition() {
+ delete[] _locations;
+}
+
+void AILocationCondition::addLocation(const RoomViewID location) {
+ if (_numLocations < _maxLocations)
+ _locations[_numLocations++] = location;
+}
+
+bool AILocationCondition::fireCondition() {
+ RoomViewID test = GameState.getCurrentRoomAndView(), *p;
+ uint32 i;
+
+ for (i = 0, p = _locations; i < _numLocations; i++, p++) {
+ if (test == *p) {
+ *p = MakeRoomView(kNoRoomID, kNoDirection);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void AILocationCondition::writeAICondition(Common::WriteStream *stream) {
+ stream->writeUint32BE(_maxLocations);
+ stream->writeUint32BE(_numLocations);
+
+ uint32 i;
+ RoomViewID *p;
+ for (i = 0, p = _locations; i < _numLocations; i++, p++)
+ stream->writeUint32BE(*p);
+}
+
+void AILocationCondition::readAICondition(Common::ReadStream *stream) {
+ uint32 maxLocations = stream->readUint32BE();
+
+ if (_maxLocations != maxLocations) {
+ delete[] _locations;
+ _locations = new RoomViewID[maxLocations];
+ _maxLocations = maxLocations;
+ }
+
+ _numLocations = stream->readUint32BE();
+
+ uint32 i;
+ RoomViewID *p;
+ for (i = 0, p = _locations; i < _numLocations; i++, p++)
+ *p = stream->readUint32BE();
+}
+
+AIDoorOpenedCondition::AIDoorOpenedCondition(RoomViewID doorLocation) {
+ _doorLocation = doorLocation;
+}
+
+bool AIDoorOpenedCondition::fireCondition() {
+ return GameState.getCurrentRoomAndView() == _doorLocation && GameState.isCurrentDoorOpen();
+}
+
+AIHasItemCondition::AIHasItemCondition(const ItemID item) {
+ _item = item;
+}
+
+bool AIHasItemCondition::fireCondition() {
+ return _item == kNoItemID || GameState.isTakenItemID(_item);
+}
+
+AIDoesntHaveItemCondition::AIDoesntHaveItemCondition(const ItemID item) {
+ _item = item;
+}
+
+bool AIDoesntHaveItemCondition::fireCondition() {
+ return _item == kNoItemID || !GameState.isTakenItemID(_item);
+}
+
+AICurrentItemCondition::AICurrentItemCondition(const ItemID item) {
+ _item = item;
+}
+
+bool AICurrentItemCondition::fireCondition() {
+ InventoryItem *item = ((PegasusEngine *)g_engine)->getCurrentInventoryItem();
+
+ if (_item == kNoItemID)
+ return item == 0;
+
+ return item != 0 && item->getObjectID() == _item;
+}
+
+AICurrentBiochipCondition::AICurrentBiochipCondition(const ItemID biochip) {
+ _biochip = biochip;
+}
+
+bool AICurrentBiochipCondition::fireCondition() {
+ BiochipItem *biochip = ((PegasusEngine *)g_engine)->getCurrentBiochip();
+
+ if (_biochip == kNoItemID)
+ return biochip == 0;
+
+ return biochip != 0 && biochip->getObjectID() == _biochip;
+}
+
+AIItemStateCondition::AIItemStateCondition(const ItemID item, const ItemState state) {
+ _item = item;
+ _state = state;
+}
+
+bool AIItemStateCondition::fireCondition() {
+ Item *item = g_allItems.findItemByID(_item);
+ return item != 0 && item->getItemState() == _state;
+}
+
+AIEnergyMonitorCondition::AIEnergyMonitorCondition(const int32 energyThreshold) {
+ _energyThreshold = energyThreshold;
+}
+
+bool AIEnergyMonitorCondition::fireCondition() {
+ return g_energyMonitor != 0 && g_energyMonitor->getCurrentEnergy() < _energyThreshold;
+}
+
+AILastExtraCondition::AILastExtraCondition(const ExtraID lastExtra) {
+ _lastExtra = lastExtra;
+}
+
+bool AILastExtraCondition::fireCondition() {
+ return g_neighborhood && (ExtraID)g_neighborhood->getLastExtra() == _lastExtra;
+}
+
+AICondition *makeLocationAndDoesntHaveItemCondition(const RoomID room, const DirectionConstant direction, const ItemID item) {
+ AILocationCondition *location = new AILocationCondition(1);
+ location->addLocation(MakeRoomView(room, direction));
+
+ AIDoesntHaveItemCondition *doesntHaveItem = new AIDoesntHaveItemCondition(item);
+
+ return new AIAndCondition(location, doesntHaveItem);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/ai/ai_condition.h b/engines/pegasus/ai/ai_condition.h
new file mode 100644
index 0000000000..ae85168a36
--- /dev/null
+++ b/engines/pegasus/ai/ai_condition.h
@@ -0,0 +1,287 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_AI_AICONDITION_H
+#define PEGASUS_AI_AICONDITION_H
+
+#include "pegasus/timers.h"
+
+namespace Common {
+ class ReadStream;
+ class WriteStream;
+}
+
+namespace Pegasus {
+
+/////////////////////////////////////////////
+//
+// AICondition
+
+class AICondition {
+public:
+ AICondition() {}
+ virtual ~AICondition() {}
+
+ virtual bool fireCondition() = 0;
+
+ // Only need these for conditions that are dynamic, like timer conditions...
+ // other conditions, like item related conditions, which don't change during
+ // the run of an environment, are completely initted when the environment
+ // is created.
+ virtual void writeAICondition(Common::WriteStream *) {}
+ virtual void readAICondition(Common::ReadStream *) {}
+};
+
+/////////////////////////////////////////////
+//
+// AIOneChildCondition
+
+class AIOneChildCondition : public AICondition {
+public:
+ AIOneChildCondition(AICondition *);
+ virtual ~AIOneChildCondition();
+
+ virtual void writeAICondition(Common::WriteStream *);
+ virtual void readAICondition(Common::ReadStream *);
+
+protected:
+ AICondition *_child;
+};
+
+/////////////////////////////////////////////
+//
+// AITwoChildrenCondition
+
+class AITwoChildrenCondition : public AICondition {
+public:
+ AITwoChildrenCondition(AICondition *, AICondition *);
+ virtual ~AITwoChildrenCondition();
+
+ virtual void writeAICondition(Common::WriteStream *);
+ virtual void readAICondition(Common::ReadStream *);
+
+protected:
+ AICondition *_leftChild, *_rightChild;
+};
+
+/////////////////////////////////////////////
+//
+// AINotCondition
+
+class AINotCondition : public AIOneChildCondition {
+public:
+ AINotCondition(AICondition *);
+
+ virtual bool fireCondition();
+};
+
+/////////////////////////////////////////////
+//
+// AIAndCondition
+
+class AIAndCondition : public AITwoChildrenCondition {
+public:
+ AIAndCondition(AICondition *, AICondition *);
+
+ virtual bool fireCondition();
+};
+
+/////////////////////////////////////////////
+//
+// AIOrCondition
+
+class AIOrCondition : public AITwoChildrenCondition {
+public:
+ AIOrCondition(AICondition *, AICondition *);
+
+ virtual bool fireCondition();
+};
+
+/////////////////////////////////////////////
+//
+// AITimerCondition
+
+class AITimerCondition : public AICondition {
+public:
+ AITimerCondition(const TimeValue, const TimeScale, const bool);
+
+ void startTimer();
+ void stopTimer();
+
+ virtual bool fireCondition();
+
+ virtual void writeAICondition(Common::WriteStream *);
+ virtual void readAICondition(Common::ReadStream *);
+
+protected:
+ void fire();
+
+ FuseFunction _timerFuse;
+ bool _fired;
+};
+
+/////////////////////////////////////////////
+//
+// AILocationCondition
+
+class AILocationCondition : public AICondition {
+public:
+ AILocationCondition(uint32);
+ virtual ~AILocationCondition();
+
+ void addLocation(RoomViewID);
+ virtual bool fireCondition();
+
+ virtual void writeAICondition(Common::WriteStream *);
+ virtual void readAICondition(Common::ReadStream *);
+
+protected:
+ uint32 _numLocations, _maxLocations;
+ RoomViewID *_locations;
+};
+
+/////////////////////////////////////////////
+//
+// AIDoorOpenedCondition
+
+class AIDoorOpenedCondition : public AICondition {
+public:
+ AIDoorOpenedCondition(RoomViewID);
+ virtual ~AIDoorOpenedCondition() {}
+
+ virtual bool fireCondition();
+
+protected:
+ RoomViewID _doorLocation;
+};
+
+/////////////////////////////////////////////
+//
+// AIHasItemCondition
+
+class AIHasItemCondition : public AICondition {
+public:
+ AIHasItemCondition(const ItemID);
+
+ virtual bool fireCondition();
+
+protected:
+ ItemID _item;
+};
+
+/////////////////////////////////////////////
+//
+// AIDoesntHaveItemCondition
+
+class AIDoesntHaveItemCondition : public AICondition {
+public:
+ AIDoesntHaveItemCondition(const ItemID);
+
+ virtual bool fireCondition();
+
+protected:
+ ItemID _item;
+};
+
+/////////////////////////////////////////////
+//
+// AICurrentItemCondition
+
+class AICurrentItemCondition : public AICondition {
+public:
+ AICurrentItemCondition(const ItemID);
+
+ virtual bool fireCondition();
+
+protected:
+ ItemID _item;
+};
+
+/////////////////////////////////////////////
+//
+// AICurrentBiochipCondition
+
+class AICurrentBiochipCondition : public AICondition {
+public:
+ AICurrentBiochipCondition(const ItemID);
+
+ virtual bool fireCondition();
+
+protected:
+ ItemID _biochip;
+};
+
+/////////////////////////////////////////////
+//
+// AIItemStateCondition
+
+class AIItemStateCondition : public AICondition {
+public:
+ AIItemStateCondition(const ItemID, const ItemState);
+
+ virtual bool fireCondition();
+
+protected:
+ ItemID _item;
+ ItemState _state;
+};
+
+/////////////////////////////////////////////
+//
+// AIEnergyMonitorCondition
+
+class AIEnergyMonitorCondition : public AICondition {
+public:
+ AIEnergyMonitorCondition(const int32);
+
+ virtual bool fireCondition();
+
+protected:
+ int32 _energyThreshold;
+};
+
+/////////////////////////////////////////////
+//
+// AILastExtraCondition
+
+class AILastExtraCondition : public AICondition {
+public:
+ AILastExtraCondition(const ExtraID);
+
+ virtual bool fireCondition();
+
+protected:
+ ExtraID _lastExtra;
+};
+
+/////////////////////////////////////////////
+//
+// Helper functions
+
+AICondition *makeLocationAndDoesntHaveItemCondition(const RoomID room, const DirectionConstant direction, const ItemID item);
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/ai/ai_rule.cpp b/engines/pegasus/ai/ai_rule.cpp
new file mode 100644
index 0000000000..3aaa530a4a
--- /dev/null
+++ b/engines/pegasus/ai/ai_rule.cpp
@@ -0,0 +1,78 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/stream.h"
+
+#include "pegasus/ai/ai_action.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/ai/ai_condition.h"
+#include "pegasus/ai/ai_rule.h"
+
+namespace Pegasus {
+
+bool AIRule::fireRule() {
+ if (_ruleActive && _ruleCondition && _ruleAction && _ruleCondition->fireCondition()) {
+ if (g_AIArea)
+ g_AIArea->lockAIOut();
+
+ _ruleAction->performAIAction(this);
+
+ if (--_ruleAction->_actionCount <= 0)
+ deactivateRule();
+
+ if (g_AIArea)
+ g_AIArea->unlockAI();
+
+ return true;
+ }
+
+ return false;
+}
+
+void AIRule::writeAIRule(Common::WriteStream *stream) {
+ stream->writeByte(_ruleActive);
+
+ if (_ruleCondition)
+ _ruleCondition->writeAICondition(stream);
+}
+
+void AIRule::readAIRule(Common::ReadStream *stream) {
+ _ruleActive = stream->readByte();
+
+ if (_ruleCondition)
+ _ruleCondition->readAICondition(stream);
+}
+
+void AIRuleList::writeAIRules(Common::WriteStream *stream) {
+ for (AIRuleList::iterator it = begin(); it != end(); it++)
+ (*it)->writeAIRule(stream);
+}
+
+void AIRuleList::readAIRules(Common::ReadStream *stream) {
+ for (AIRuleList::iterator it = begin(); it != end(); it++)
+ (*it)->readAIRule(stream);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/ai/ai_rule.h b/engines/pegasus/ai/ai_rule.h
new file mode 100644
index 0000000000..aa2ca07332
--- /dev/null
+++ b/engines/pegasus/ai/ai_rule.h
@@ -0,0 +1,86 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_AI_AIRULE_H
+#define PEGASUS_AI_AIRULE_H
+
+#include "common/list.h"
+
+#include "pegasus/ai/ai_action.h"
+#include "pegasus/ai/ai_condition.h"
+
+namespace Common {
+ class ReadStream;
+ class WriteStream;
+}
+
+namespace Pegasus {
+
+class AICondition;
+class AIAction;
+
+class AIRule {
+public:
+ AIRule(AICondition *condition, AIAction *rule) {
+ _ruleCondition = condition;
+ _ruleAction = rule;
+ _ruleActive = true;
+ }
+
+ ~AIRule() {
+ if (_ruleCondition)
+ delete _ruleCondition;
+
+ if (_ruleAction)
+ delete _ruleAction;
+ }
+
+ bool fireRule();
+
+ void activateRule() { _ruleActive = true; }
+ void deactivateRule() { _ruleActive = false; }
+ bool isRuleActive() { return _ruleActive; }
+
+ void writeAIRule(Common::WriteStream *);
+ void readAIRule(Common::ReadStream *);
+
+protected:
+ AICondition *_ruleCondition;
+ AIAction *_ruleAction;
+ bool _ruleActive;
+};
+
+class AIRuleList : public Common::List<AIRule *> {
+public:
+ AIRuleList() {}
+ ~AIRuleList() {}
+
+ void writeAIRules(Common::WriteStream *);
+ void readAIRules(Common::ReadStream *);
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/compass.cpp b/engines/pegasus/compass.cpp
new file mode 100644
index 0000000000..5de8b91b11
--- /dev/null
+++ b/engines/pegasus/compass.cpp
@@ -0,0 +1,82 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/compass.h"
+
+namespace Pegasus {
+
+Compass *g_compass = 0;
+
+Compass::Compass() : FaderAnimation(kCompassID) {
+ // Initialize it to east...
+ setFaderValue(90);
+ g_compass = this;
+}
+
+Compass::~Compass() {
+ g_compass = 0;
+}
+
+void Compass::initCompass() {
+ if (!isCompassValid()) {
+ Common::Rect r;
+ _compassImage.initFromPICTFile("Images/Compass/Compass");
+ _compassImage.getSurfaceBounds(r);
+ r.right = kCompassWidth;
+ setBounds(r);
+ }
+}
+
+void Compass::deallocateCompass() {
+ _compassImage.deallocateSurface();
+}
+
+void Compass::setFaderValue(const int32 angle) {
+ int16 a = angle % 360;
+
+ if (a < 0)
+ a += 360;
+
+ FaderAnimation::setFaderValue(a);
+}
+
+void Compass::draw(const Common::Rect &r1) {
+ if (_compassImage.isSurfaceValid()) {
+ Common::Rect bounds;
+ getBounds(bounds);
+
+ Common::Rect r2;
+ _compassImage.getSurfaceBounds(r2);
+
+ CoordType width = r2.width();
+ CoordType offsetH = width / 10 - bounds.width() / 2 + (getFaderValue() * width) / 450 - bounds.left;
+ CoordType offsetV = -bounds.top;
+ r2 = r1;
+ r2.translate(offsetH, offsetV);
+ _compassImage.drawImage(r2, r1);
+ }
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/compass.h b/engines/pegasus/compass.h
new file mode 100644
index 0000000000..67a8e06294
--- /dev/null
+++ b/engines/pegasus/compass.h
@@ -0,0 +1,58 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_COMPASS_H
+#define PEGASUS_COMPASS_H
+
+#include "pegasus/fader.h"
+#include "pegasus/surface.h"
+
+namespace Pegasus {
+
+// Compass is defined with 0 as north, 90 east, 180 south, 270 west.
+// Clockwise rotation increases the angle, counterclockwise rotation decreases the angle.
+
+class Compass : public FaderAnimation {
+public:
+ Compass();
+ virtual ~Compass();
+
+ void initCompass();
+ void deallocateCompass();
+ bool isCompassValid() const { return _compassImage.isSurfaceValid(); }
+
+ void setFaderValue(const int32);
+
+protected:
+ void draw(const Common::Rect &);
+
+ Frame _compassImage;
+};
+
+extern Compass *g_compass;
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/console.cpp b/engines/pegasus/console.cpp
new file mode 100644
index 0000000000..64bd0ba5f2
--- /dev/null
+++ b/engines/pegasus/console.cpp
@@ -0,0 +1,102 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/console.h"
+#include "pegasus/interface.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/neighborhood/neighborhood.h"
+
+namespace Pegasus {
+
+PegasusConsole::PegasusConsole(PegasusEngine *vm) : GUI::Debugger(), _vm(vm) {
+ DCmd_Register("die", WRAP_METHOD(PegasusConsole, Cmd_Die));
+
+ // These functions are non-demo specific
+ if (!_vm->isDemo())
+ DCmd_Register("jump", WRAP_METHOD(PegasusConsole, Cmd_Jump));
+}
+
+PegasusConsole::~PegasusConsole() {
+}
+
+bool PegasusConsole::Cmd_Die(int argc, const char **argv) {
+ if (argc == 1) {
+ DebugPrintf("Usage: die <death reason>\n");
+ return true;
+ }
+
+ int reason = atoi(argv[1]);
+
+ bool invalidReason = (reason == 0 || reason > kPlayerWonGame);
+
+ if (!invalidReason && _vm->isDemo())
+ invalidReason = (reason != kDeathFallOffCliff) && (reason != kDeathEatenByDinosaur) &&
+ (reason != kDeathStranded) && (reason != kPlayerWonGame);
+
+
+ if (invalidReason) {
+ DebugPrintf("Invalid death reason %d\n", reason);
+ return true;
+ }
+
+ _vm->die(atoi(argv[1]));
+ return false;
+}
+
+bool PegasusConsole::Cmd_Jump(int argc, const char **argv) {
+ if (!g_interface) {
+ // TODO
+ DebugPrintf("Cannot jump without interface set up\n");
+ return true;
+ }
+
+ // TODO: Default room/direction for each neighborhood
+
+ if (argc < 4) {
+ DebugPrintf("Usage: jump <neighborhood> <room> <direction>\n");
+ return true;
+ }
+
+ NeighborhoodID neighborhood = (NeighborhoodID)atoi(argv[1]);
+ RoomID room = (RoomID)atoi(argv[2]);
+ DirectionConstant direction = (DirectionConstant)atoi(argv[3]);
+
+ if ((neighborhood < kCaldoriaID || neighborhood > kNoradDeltaID || neighborhood == kFinalTSAID) &&
+ neighborhood != kNoradSubChaseID) {
+ DebugPrintf("Invalid neighborhood %d", neighborhood);
+ return true;
+ }
+
+ // No real way to check room validity at this point
+
+ if (direction > kWest) {
+ DebugPrintf("Invalid direction %d", direction);
+ return true;
+ }
+
+ // Here we go!
+ // TODO: Can't clear menu since the engine is paused
+ _vm->jumpToNewEnvironment(neighborhood, room, direction);
+ return false;
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/console.h b/engines/pegasus/console.h
new file mode 100644
index 0000000000..f00ee25294
--- /dev/null
+++ b/engines/pegasus/console.h
@@ -0,0 +1,46 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_CONSOLE_H
+#define PEGASUS_CONSOLE_H
+
+#include "gui/debugger.h"
+
+namespace Pegasus {
+
+class PegasusEngine;
+
+class PegasusConsole : public GUI::Debugger {
+public:
+ PegasusConsole(PegasusEngine *vm);
+ virtual ~PegasusConsole();
+
+private:
+ bool Cmd_Die(int argc, const char **argv);
+ bool Cmd_Jump(int argc, const char **argv);
+
+ PegasusEngine *_vm;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/constants.h b/engines/pegasus/constants.h
new file mode 100644
index 0000000000..f81d2197ac
--- /dev/null
+++ b/engines/pegasus/constants.h
@@ -0,0 +1,729 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_CONSTANTS_H
+#define PEGASUS_CONSTANTS_H
+
+#include "common/endian.h"
+#include "common/rect.h"
+
+#include "pegasus/types.h"
+
+namespace Pegasus {
+
+// TODO: Organize these
+
+static const GameID kGameIDNothing = -1;
+
+static const ActorID kNoActorID = kGameIDNothing;
+static const ActorID kPlayerID = 0;
+static const ItemID kNoItemID = kGameIDNothing;
+static const RoomID kNoRoomID = kGameIDNothing;
+static const ExtraID kNoExtraID = 0xFFFFFFFF;
+static const NeighborhoodID kNoNeighborhoodID = kGameIDNothing;
+static const AlternateID kNoAlternateID = 0;
+static const GameMenuCommand kMenuCmdNoCommand = 0;
+
+static const HotSpotActivationID kActivateHotSpotAlways = 0;
+static const HotSpotActivationID kActivateHotSpotNever = -1;
+
+static const ItemState kNoItemState = -1;
+
+static const DirectionConstant kNoDirection = 0xFF;
+static const DirectionConstant kNorth = 0;
+static const DirectionConstant kSouth = 1;
+static const DirectionConstant kEast = 2;
+static const DirectionConstant kWest = 3;
+
+static const TurnDirection kNoTurn = 0xFF;
+static const TurnDirection kTurnLeft = 0;
+static const TurnDirection kTurnRight = 1;
+static const TurnDirection kTurnUp = 2;
+static const TurnDirection kTurnDown = 3;
+static const TurnDirection kMaxTurns = 4;
+
+static const GameMode kNoMode = -1;
+static const GameMode kModeNavigation = 0;
+static const GameMode kLastGameShellMode = kModeNavigation;
+
+static const CanMoveForwardReason kCanMoveForward = 0;
+static const CanMoveForwardReason kCantMoveBlocked = kCanMoveForward + 1;
+static const CanMoveForwardReason kCantMoveDoorClosed = kCantMoveBlocked + 1;
+static const CanMoveForwardReason kCantMoveDoorLocked = kCantMoveDoorClosed + 1;
+static const CanMoveForwardReason kCantMoveLastReason = kCantMoveDoorLocked;
+
+static const CanTurnReason kCanTurn = 0;
+static const CanTurnReason kCantTurnNoTurn = kCanTurn + 1;
+static const CanTurnReason kCantTurnLastReason = kCantTurnNoTurn;
+
+static const CanOpenDoorReason kCanOpenDoor = 0;
+static const CanOpenDoorReason kCantOpenNoDoor = kCanOpenDoor + 1;
+static const CanOpenDoorReason kCantOpenLocked = kCantOpenNoDoor + 1;
+static const CanOpenDoorReason kCantOpenAlreadyOpen = kCantOpenLocked + 1;
+static const CanOpenDoorReason kCantOpenLastReason = kCantOpenAlreadyOpen;
+
+static const DisplayElementID kNoDisplayElement = -1;
+static const DisplayElementID kHighestReservedElementID = -2;
+
+static const DisplayElementID kCursorID = kHighestReservedElementID;
+static const DisplayElementID kLoadScreenID = kCursorID - 1;
+
+static const DisplayOrder kMinAvailableOrder = 0;
+static const DisplayOrder kMaxAvailableOrder = 999998;
+static const DisplayOrder kLoadScreenOrder = 900000;
+static const DisplayOrder kCursorOrder = 1000000;
+
+static const HotSpotID kNoHotSpotID = -1;
+static const HotSpotFlags kNoHotSpotFlags = 0;
+static const HotSpotFlags kAllHotSpotFlags = ~kNoHotSpotFlags;
+
+static const NotificationFlags kNoNotificationFlags = 0;
+
+static const DisplayElementID kCurrentDragSpriteID = 1000;
+
+static const TimeScale kDefaultTimeScale = 600;
+
+// Ticks per second.
+
+static const TimeScale kOneTickPerSecond = 1;
+static const TimeScale kTwoTicksPerSecond = 2;
+static const TimeScale kFifteenTicksPerSecond = 15;
+static const TimeScale kThirtyTicksPerSecond = 30;
+static const TimeScale kSixtyTicksPerSecond = 60;
+static const TimeScale kMovieTicksPerSecond = 600;
+
+// These times are in seconds.
+
+static const TimeValue kOneSecond = 1;
+static const TimeValue kTwoSeconds = 2;
+static const TimeValue kThreeSeconds = 3;
+static const TimeValue kFourSeconds = 4;
+static const TimeValue kFiveSeconds = 5;
+static const TimeValue kSixSeconds = 6;
+static const TimeValue kSevenSeconds = 7;
+static const TimeValue kEightSeconds = 8;
+static const TimeValue kNineSeconds = 9;
+static const TimeValue kTenSeconds = 10;
+static const TimeValue kElevenSeconds = 11;
+static const TimeValue kTwelveSeconds = 12;
+static const TimeValue kThirteenSeconds = 13;
+static const TimeValue kFourteenSeconds = 14;
+static const TimeValue kFifteenSeconds = 15;
+static const TimeValue kSixteenSeconds = 16;
+static const TimeValue kSeventeenSeconds = 17;
+static const TimeValue kEighteenSeconds = 18;
+static const TimeValue kNineteenSeconds = 19;
+static const TimeValue kTwentySeconds = 20;
+static const TimeValue kThirtySeconds = 30;
+static const TimeValue kFortySeconds = 40;
+static const TimeValue kFiftySeconds = 50;
+static const TimeValue kSixtySeconds = 60;
+static const TimeValue kOneMinute = 60;
+static const TimeValue kTwoMinutes = kOneMinute * 2;
+static const TimeValue kThreeMinutes = kOneMinute * 3;
+static const TimeValue kFourMinutes = kOneMinute * 4;
+static const TimeValue kFiveMinutes = kOneMinute * 5;
+static const TimeValue kSixMinutes = kOneMinute * 6;
+static const TimeValue kSevenMinutes = kOneMinute * 7;
+static const TimeValue kEightMinutes = kOneMinute * 8;
+static const TimeValue kNineMinutes = kOneMinute * 9;
+static const TimeValue kTenMinutes = kOneMinute * 10;
+static const TimeValue kElevenMinutes = kOneMinute * 11;
+static const TimeValue kTwelveMinutes = kOneMinute * 12;
+static const TimeValue kThirteenMinutes = kOneMinute * 13;
+static const TimeValue kFourteenMinutes = kOneMinute * 14;
+static const TimeValue kFifteenMinutes = kOneMinute * 15;
+static const TimeValue kSixteenMinutes = kOneMinute * 16;
+static const TimeValue kSeventeenMinutes = kOneMinute * 17;
+static const TimeValue kEighteenMinutes = kOneMinute * 18;
+static const TimeValue kNineteenMinutes = kOneMinute * 19;
+static const TimeValue kTwentyMinutes = kOneMinute * 20;
+static const TimeValue kThirtyMinutes = kOneMinute * 30;
+static const TimeValue kFortyMinutes = kOneMinute * 40;
+static const TimeValue kFiftyMinutes = kOneMinute * 50;
+static const TimeValue kOneHour = kOneMinute * 60;
+static const TimeValue kTwoHours = kOneHour * 2;
+
+// Common times.
+
+static const TimeValue kHalfSecondPerTwoTicks = kTwoTicksPerSecond / 2;
+static const TimeValue kHalfSecondPerThirtyTicks = kThirtyTicksPerSecond / 2;
+static const TimeValue kHalfSecondPerSixtyTicks = kSixtyTicksPerSecond / 2;
+
+static const TimeValue kOneSecondPerTwoTicks = kTwoTicksPerSecond;
+static const TimeValue kOneSecondPerThirtyTicks = kThirtyTicksPerSecond;
+static const TimeValue kOneSecondPerSixtyTicks = kSixtyTicksPerSecond;
+
+static const TimeValue kOneMinutePerFifteenTicks = kOneMinute * kFifteenTicksPerSecond;
+static const TimeValue kFiveMinutesPerFifteenTicks = kFiveMinutes * kFifteenTicksPerSecond;
+static const TimeValue kTenMinutesPerFifteenTicks = kTenMinutes * kFifteenTicksPerSecond;
+
+static const TimeValue kOneMinutePerThirtyTicks = kOneMinute * kThirtyTicksPerSecond;
+static const TimeValue kFiveMinutesPerThirtyTicks = kFiveMinutes * kThirtyTicksPerSecond;
+static const TimeValue kTenMinutesPerThirtyTicks = kTenMinutes * kThirtyTicksPerSecond;
+
+static const TimeValue kOneMinutePerSixtyTicks = kOneMinute * kSixtyTicksPerSecond;
+static const TimeValue kFiveMinutesPerSixtyTicks = kFiveMinutes * kSixtyTicksPerSecond;
+static const TimeValue kTenMinutesPerSixtyTicks = kTenMinutes * kSixtyTicksPerSecond;
+
+// Time in seconds you can hang around Caldoria without going to work...
+static const TimeValue kLateWarning2TimeLimit = kFiveMinutes;
+static const TimeValue kLateWarning3TimeLimit = kTenMinutes;
+
+static const TimeValue kSinclairShootsTimeLimit = kThreeMinutes;
+static const TimeValue kCardBombCountDownTime = kTwelveSeconds;
+
+static const TimeValue kOxyMaskFullTime = kThirtyMinutes;
+
+static const TimeValue kTSAUncreatedTimeLimit = kFiveMinutes;
+static const TimeValue kRipTimeLimit = kTenMinutesPerFifteenTicks;
+static const TimeScale kRipTimeScale = kFifteenTicksPerSecond;
+
+static const TimeValue kIntroTimeOut = kThirtySeconds;
+
+static const TimeValue kMarsRobotPatienceLimit = kFifteenSeconds;
+static const TimeValue kLockFreezeTimeLmit = kFifteenSeconds;
+static const TimeValue kSpaceChaseTimeLimit = kTenMinutes;
+static const TimeValue kVacuumSurvivalTimeLimit = kThirtySeconds;
+static const TimeValue kColorMatchingTimeLimit = kFourMinutes;
+static const TimeScale kJunkTimeScale = kFifteenTicksPerSecond;
+static const TimeValue kJunkDropBaseTime = kFiveSeconds;
+static const TimeValue kJunkDropSlopTime = kThreeSeconds;
+static const TimeValue kJunkTravelTime = kTenSeconds * kJunkTimeScale;
+static const TimeValue kCollisionReboundTime = kOneSecond * kJunkTimeScale;
+static const TimeValue kWeaponReboundTime = kTwoSeconds * kJunkTimeScale;
+
+static const TimeValue kGawkAtRobotTime = kTenSeconds;
+static const TimeValue kGawkAtRobotTime2 = kThirteenSeconds;
+static const TimeValue kPlasmaImpactTime = kTwoSeconds;
+
+static const TimeValue kNoradAirMaskTimeLimit = kOneMinute + kFifteenSeconds;
+
+static const NotificationID kNeighborhoodNotificationID = 1;
+static const NotificationID kLastNeighborhoodNotificationID = kNeighborhoodNotificationID;
+
+static const NotificationFlags kNeighborhoodMovieCompletedFlag = 1;
+static const NotificationFlags kMoveForwardCompletedFlag = kNeighborhoodMovieCompletedFlag << 1;
+static const NotificationFlags kStrideCompletedFlag = kMoveForwardCompletedFlag << 1;
+static const NotificationFlags kTurnCompletedFlag = kStrideCompletedFlag << 1;
+static const NotificationFlags kSpotCompletedFlag = kTurnCompletedFlag << 1;
+static const NotificationFlags kDoorOpenCompletedFlag = kSpotCompletedFlag << 1;
+static const NotificationFlags kExtraCompletedFlag = kDoorOpenCompletedFlag << 1;
+static const NotificationFlags kSpotSoundCompletedFlag = kExtraCompletedFlag << 1;
+static const NotificationFlags kDelayCompletedFlag = kSpotSoundCompletedFlag << 1;
+static const NotificationFlags kActionRequestCompletedFlag = kDelayCompletedFlag << 1;
+static const NotificationFlags kDeathExtraCompletedFlag = kActionRequestCompletedFlag << 1;
+static const NotificationFlags kLastNeighborhoodNotificationFlag = kDeathExtraCompletedFlag;
+
+static const NotificationFlags kNeighborhoodFlags = kNeighborhoodMovieCompletedFlag |
+ kMoveForwardCompletedFlag |
+ kStrideCompletedFlag |
+ kTurnCompletedFlag |
+ kSpotCompletedFlag |
+ kDoorOpenCompletedFlag |
+ kExtraCompletedFlag |
+ kSpotSoundCompletedFlag |
+ kDelayCompletedFlag |
+ kActionRequestCompletedFlag |
+ kDeathExtraCompletedFlag;
+
+static const uint32 kPegasusPrimeCreator = MKTAG('J', 'P', 'P', 'P');
+static const uint32 kPegasusPrimeContinueType = MKTAG('P', 'P', 'C', 'T');
+
+static const uint32 kPegasusPrimeDisk1GameType = MKTAG('P', 'P', 'G', '1');
+static const uint32 kPegasusPrimeDisk2GameType = MKTAG('P', 'P', 'G', '2');
+static const uint32 kPegasusPrimeDisk3GameType = MKTAG('P', 'P', 'G', '3');
+static const uint32 kPegasusPrimeDisk4GameType = MKTAG('P', 'P', 'G', '4');
+
+// We only support one of the save versions; the rest are from betas
+// and we are not supporting them.
+static const uint32 kPegasusPrimeVersion = 0x00009019;
+
+static const char kNormalSave = 0;
+static const char kContinueSave = 1;
+
+// Display IDs.
+
+static const DisplayElementID kNavMovieID = 1;
+static const DisplayElementID kTurnPushID = 2;
+
+static const DisplayElementID kMaxGameShellDisplayID = kTurnPushID;
+
+// Display ordering.
+
+static const DisplayOrder kNavLayer = 10000;
+static const DisplayOrder kNavMovieOrder = kNavLayer;
+static const DisplayOrder kTurnPushOrder = kNavMovieOrder + 1;
+
+/////////////////////////////////////////////
+//
+// Display IDs.
+
+static const DisplayElementID kScreenDimmerID = kMaxGameShellDisplayID + 1;
+static const DisplayElementID kInterface1ID = kScreenDimmerID + 1;
+static const DisplayElementID kInterface2ID = kInterface1ID + 1;
+static const DisplayElementID kInterface3ID = kInterface2ID + 1;
+static const DisplayElementID kInterface4ID = kInterface3ID + 1;
+static const DisplayElementID kDateID = kInterface4ID + 1;
+static const DisplayElementID kCompassID = kDateID + 1;
+static const DisplayElementID kInventoryPushID = kCompassID + 1;
+static const DisplayElementID kInventoryLidID = kInventoryPushID + 1;
+static const DisplayElementID kBiochipPushID = kInventoryLidID + 1;
+static const DisplayElementID kBiochipLidID = kBiochipPushID + 1;
+static const DisplayElementID kEnergyBarID = kBiochipLidID + 1;
+static const DisplayElementID kWarningLightID = kEnergyBarID + 1;
+static const DisplayElementID kAILeftAreaID = kWarningLightID + 1;
+static const DisplayElementID kAIMiddleAreaID = kAILeftAreaID + 1;
+static const DisplayElementID kAIRightAreaID = kAIMiddleAreaID + 1;
+static const DisplayElementID kAIMovieID = kAIRightAreaID + 1;
+static const DisplayElementID kInventoryDropHighlightID = kAIMovieID + 1;
+static const DisplayElementID kBiochipDropHighlightID = kInventoryDropHighlightID + 1;
+
+static const DisplayElementID kDraggingSpriteID = 1000;
+
+static const DisplayElementID kCroppedMovieID = 2000;
+
+static const DisplayElementID kNeighborhoodDisplayID = 3000;
+
+static const DisplayElementID kItemPictureBaseID = 5000;
+
+static const CoordType kNavAreaLeft = 64;
+static const CoordType kNavAreaTop = 64;
+
+static const CoordType kBackground1Left = 0;
+static const CoordType kBackground1Top = 64;
+
+static const CoordType kBackground2Left = 0;
+static const CoordType kBackground2Top = 0;
+
+static const CoordType kBackground3Left = 576;
+static const CoordType kBackground3Top = 64;
+
+static const CoordType kBackground4Left = 0;
+static const CoordType kBackground4Top = 320;
+
+static const CoordType kOverviewControllerLeft = 540;
+static const CoordType kOverviewControllerTop = 348;
+
+static const CoordType kSwapLeft = 194;
+static const CoordType kSwapTop = 116;
+
+static const CoordType kSwapHiliteLeft = 200;
+static const CoordType kSwapHiliteTop = 206;
+
+static const CoordType kDateLeft = 136;
+static const CoordType kDateTop = 44;
+
+static const CoordType kCompassLeft = 222;
+static const CoordType kCompassTop = 42;
+static const CoordType kCompassWidth = 92;
+
+static const CoordType kInventoryPushLeft = 74;
+static const CoordType kInventoryPushTop = 92;
+
+static const CoordType kInventoryLidLeft = 74;
+static const CoordType kInventoryLidTop = 316;
+
+static const CoordType kBiochipPushLeft = 362;
+static const CoordType kBiochipPushTop = 192;
+
+static const CoordType kBiochipLidLeft = 362;
+static const CoordType kBiochipLidTop = 316;
+
+static const CoordType kInventoryDropLeft = 0;
+static const CoordType kInventoryDropTop = 320;
+static const CoordType kInventoryDropRight = 232;
+static const CoordType kInventoryDropBottom = 480;
+
+static const CoordType kBiochipDropLeft = 302;
+static const CoordType kBiochipDropTop = 320;
+static const CoordType kBiochipDropRight = 640;
+static const CoordType kBiochipDropBottom = 480;
+
+static const CoordType kFinalMessageLeft = kInventoryPushLeft + 1;
+static const CoordType kFinalMessageTop = kInventoryPushTop + 24;
+
+/////////////////////////////////////////////
+//
+// Notifications.
+
+static const NotificationID kJMPDCShellNotificationID = kLastNeighborhoodNotificationID + 1;
+static const NotificationID kInterfaceNotificationID = kJMPDCShellNotificationID + 1;
+static const NotificationID kAINotificationID = kInterfaceNotificationID + 1;
+static const NotificationID kNoradNotificationID = kAINotificationID + 1;
+static const NotificationID kNoradECRNotificationID = kNoradNotificationID + 1;
+static const NotificationID kNoradFillingStationNotificationID = kNoradECRNotificationID + 1;
+static const NotificationID kNoradPressureNotificationID = kNoradFillingStationNotificationID + 1;
+static const NotificationID kNoradUtilityNotificationID = kNoradPressureNotificationID + 1;
+static const NotificationID kNoradElevatorNotificationID = kNoradUtilityNotificationID + 1;
+static const NotificationID kNoradSubPlatformNotificationID = kNoradElevatorNotificationID + 1;
+static const NotificationID kSubControlNotificationID = kNoradSubPlatformNotificationID + 1;
+static const NotificationID kNoradGreenBallNotificationID = kSubControlNotificationID + 1;
+static const NotificationID kNoradGlobeNotificationID = kNoradGreenBallNotificationID + 1;
+static const NotificationID kCaldoriaVidPhoneNotificationID = kNoradGlobeNotificationID + 1;
+static const NotificationID kCaldoriaMessagesNotificationID = kCaldoriaVidPhoneNotificationID + 1;
+static const NotificationID kCaldoriaBombTimerNotificationID = kCaldoriaMessagesNotificationID + 1;
+
+// Sent to the shell by fShellNotification.
+static const NotificationFlags kGameStartingFlag = 1;
+static const NotificationFlags kNeedNewJumpFlag = kGameStartingFlag << 1;
+static const NotificationFlags kPlayerDiedFlag = kNeedNewJumpFlag << 1;
+
+static const NotificationFlags kJMPShellNotificationFlags = kGameStartingFlag |
+ kNeedNewJumpFlag |
+ kPlayerDiedFlag;
+
+// Sent to the interface.
+static const NotificationFlags kInventoryLidOpenFlag = 1;
+static const NotificationFlags kInventoryLidClosedFlag = kInventoryLidOpenFlag << 1;
+static const NotificationFlags kInventoryDrawerUpFlag = kInventoryLidClosedFlag << 1;
+static const NotificationFlags kInventoryDrawerDownFlag = kInventoryDrawerUpFlag << 1;
+static const NotificationFlags kBiochipLidOpenFlag = kInventoryDrawerDownFlag << 1;
+static const NotificationFlags kBiochipLidClosedFlag = kBiochipLidOpenFlag << 1;
+static const NotificationFlags kBiochipDrawerUpFlag = kBiochipLidClosedFlag << 1;
+static const NotificationFlags kBiochipDrawerDownFlag = kBiochipDrawerUpFlag << 1;
+
+static const NotificationFlags kInterfaceNotificationFlags = kInventoryLidOpenFlag |
+ kInventoryLidClosedFlag |
+ kInventoryDrawerUpFlag |
+ kInventoryDrawerDownFlag |
+ kBiochipLidOpenFlag |
+ kBiochipLidClosedFlag |
+ kBiochipDrawerUpFlag |
+ kBiochipDrawerDownFlag;
+
+// Hot spots.
+
+// Neighborhood hot spots.
+
+static const HotSpotID kFirstNeighborhoodSpotID = 5000;
+
+// kShellSpotFlag is a flag which marks all hot spots which belong to the shell, like
+// the current item and current biochip spots.
+static const HotSpotFlags kShellSpotFlag = 1;
+// kNeighborhoodSpotFlag is a flag which marks all hot spots which belong to a
+// neighborhood, like buttons on walls and so on.
+static const HotSpotFlags kNeighborhoodSpotFlag = kShellSpotFlag << 1;
+// kZoomInSpotFlag is a flag which marks all hot spots which indicate a zoom.
+static const HotSpotFlags kZoomInSpotFlag = kNeighborhoodSpotFlag << 1;
+// kZoomOutSpotFlag is a flag which marks all hot spots which indicate a zoom.
+static const HotSpotFlags kZoomOutSpotFlag = kZoomInSpotFlag << 1;
+
+static const HotSpotFlags kClickSpotFlag = kZoomOutSpotFlag << 1;
+static const HotSpotFlags kPlayExtraSpotFlag = kClickSpotFlag << 1;
+static const HotSpotFlags kPickUpItemSpotFlag = kPlayExtraSpotFlag << 1;
+static const HotSpotFlags kDropItemSpotFlag = kPickUpItemSpotFlag << 1;
+static const HotSpotFlags kOpenDoorSpotFlag = kDropItemSpotFlag << 1;
+
+static const HotSpotFlags kZoomSpotFlags = kZoomInSpotFlag | kZoomOutSpotFlag;
+
+static const HotSpotFlags kHighestGameShellSpotFlag = kOpenDoorSpotFlag;
+
+/////////////////////////////////////////////
+//
+// Hot spots.
+
+// Shell hot spots.
+// The shell reserves all hot spot IDs from 0 to 999
+
+static const HotSpotID kCurrentItemSpotID = 0;
+static const HotSpotID kCurrentBiochipSpotID = kCurrentItemSpotID + 1;
+
+static const HotSpotID kInventoryDropSpotID = kCurrentBiochipSpotID + 1;
+static const HotSpotID kBiochipDropSpotID = kInventoryDropSpotID + 1;
+
+static const HotSpotID kInfoReturnSpotID = kBiochipDropSpotID + 1;
+
+static const HotSpotID kAIHint1SpotID = kInfoReturnSpotID + 1;
+static const HotSpotID kAIHint2SpotID = kAIHint1SpotID + 1;
+static const HotSpotID kAIHint3SpotID = kAIHint2SpotID + 1;
+static const HotSpotID kAISolveSpotID = kAIHint3SpotID + 1;
+static const HotSpotID kAIBriefingSpotID = kAISolveSpotID + 1;
+static const HotSpotID kAIScanSpotID = kAIBriefingSpotID + 1;
+
+static const HotSpotID kPegasusRecallSpotID = kAIScanSpotID + 1;
+
+static const HotSpotID kAriesSpotID = kPegasusRecallSpotID + 1;
+static const HotSpotID kMercurySpotID = kAriesSpotID + 1;
+static const HotSpotID kPoseidonSpotID = kMercurySpotID + 1;
+
+static const HotSpotID kAirMaskToggleSpotID = kPoseidonSpotID + 1;
+
+static const HotSpotID kShuttleEnergySpotID = kAirMaskToggleSpotID + 1;
+static const HotSpotID kShuttleGravitonSpotID = kShuttleEnergySpotID + 1;
+static const HotSpotID kShuttleTractorSpotID = kShuttleGravitonSpotID + 1;
+static const HotSpotID kShuttleViewSpotID = kShuttleTractorSpotID + 1;
+static const HotSpotID kShuttleTransportSpotID = kShuttleViewSpotID + 1;
+
+// Most of these are obsolete:
+
+// kInventoryDropSpotFlag is a flag which marks hot spots which are valid drop spots
+// for inventory items.
+// static const HotSpotFlags kInventoryDropSpotFlag = kHighestGameShellSpotFlag << 1;
+
+// kBiochipDropSpotFlag is a flag which marks hot spots which are valid drop spots
+// for biochips.
+// static const HotSpotFlags kBiochipDropSpotFlag = kInventoryDropSpotFlag << 1;
+
+// kInventorySpotFlag is a flag which marks hot spots which indicate inventory items
+// in the environment.
+// static const HotSpotFlags kInventorySpotFlag = kBiochipDropSpotFlag << 1;
+
+// kBiochipSpotFlag is a flag which marks hot spots which indicate biochips
+// in the environment.
+static const HotSpotFlags kPickUpBiochipSpotFlag = kHighestGameShellSpotFlag << 1;
+static const HotSpotFlags kDropBiochipSpotFlag = kPickUpBiochipSpotFlag << 1;
+
+static const HotSpotFlags kInfoReturnSpotFlag = kDropBiochipSpotFlag << 1;
+
+// Biochip and inventory hot spot flags...
+
+static const HotSpotFlags kAIBiochipSpotFlag = kInfoReturnSpotFlag << 1;
+static const HotSpotFlags kPegasusBiochipSpotFlag = kAIBiochipSpotFlag << 1;
+static const HotSpotFlags kOpticalBiochipSpotFlag = kPegasusBiochipSpotFlag << 1;
+static const HotSpotFlags kAirMaskSpotFlag = kOpticalBiochipSpotFlag << 1;
+
+static const HotSpotFlags kJMPClickingSpotFlags = kClickSpotFlag |
+ kPlayExtraSpotFlag |
+ kOpenDoorSpotFlag |
+ kInfoReturnSpotFlag |
+ kAIBiochipSpotFlag |
+ kPegasusBiochipSpotFlag |
+ kOpticalBiochipSpotFlag |
+ kAirMaskSpotFlag;
+
+static const int32 kMainMenuID = 1;
+static const int32 kPauseMenuID = 2;
+static const int32 kCreditsMenuID = 3;
+static const int32 kDeathMenuID = 4;
+
+/////////////////////////////////////////////
+//
+// Menu commands.
+
+static const GameMenuCommand kMenuCmdOverview = kMenuCmdNoCommand + 1;
+static const GameMenuCommand kMenuCmdStartAdventure = kMenuCmdOverview + 1;
+static const GameMenuCommand kMenuCmdStartWalkthrough = kMenuCmdStartAdventure + 1;
+static const GameMenuCommand kMenuCmdRestore = kMenuCmdStartWalkthrough + 1;
+static const GameMenuCommand kMenuCmdCredits = kMenuCmdRestore + 1;
+static const GameMenuCommand kMenuCmdQuit = kMenuCmdCredits + 1;
+
+static const GameMenuCommand kMenuCmdDeathContinue = kMenuCmdQuit + 1;
+
+static const GameMenuCommand kMenuCmdDeathQuitDemo = kMenuCmdDeathContinue + 1;
+static const GameMenuCommand kMenuCmdDeathMainMenuDemo = kMenuCmdDeathQuitDemo + 1;
+
+static const GameMenuCommand kMenuCmdDeathRestore = kMenuCmdDeathMainMenuDemo + 1;
+static const GameMenuCommand kMenuCmdDeathMainMenu = kMenuCmdDeathRestore + 1;
+
+static const GameMenuCommand kMenuCmdPauseSave = kMenuCmdDeathMainMenu + 1;
+static const GameMenuCommand kMenuCmdPauseContinue = kMenuCmdPauseSave + 1;
+static const GameMenuCommand kMenuCmdPauseRestore = kMenuCmdPauseContinue + 1;
+static const GameMenuCommand kMenuCmdPauseQuit = kMenuCmdPauseRestore + 1;
+
+static const GameMenuCommand kMenuCmdCreditsMainMenu = kMenuCmdPauseQuit + 1;
+
+static const GameMenuCommand kMenuCmdCancelRestart = kMenuCmdCreditsMainMenu + 1;
+static const GameMenuCommand kMenuCmdEjectRestart = kMenuCmdCancelRestart + 1;
+
+static const TimeValue kMenuButtonHiliteTime = 20;
+static const TimeScale kMenuButtonHiliteScale = kSixtyTicksPerSecond;
+
+// PICT resources:
+
+// Warning light PICTs:
+
+static const ResIDType kLightOffID = 128;
+static const ResIDType kLightYellowID = 129;
+static const ResIDType kLightOrangeID = 130;
+static const ResIDType kLightRedID = 131;
+
+// Date PICTs:
+
+static const ResIDType kDatePrehistoricID = 138;
+static const ResIDType kDate2112ID = 139;
+static const ResIDType kDate2185ID = 140;
+static const ResIDType kDate2310ID = 141;
+static const ResIDType kDate2318ID = 142;
+
+/////////////////////////////////////////////
+//
+// Display Order
+
+static const DisplayOrder kCroppedMovieLayer = 11000;
+
+static const DisplayOrder kMonitorLayer = 12000;
+
+static const DisplayOrder kDragSpriteLayer = 15000;
+static const DisplayOrder kDragSpriteOrder = kDragSpriteLayer;
+
+static const DisplayOrder kInterfaceLayer = 20000;
+static const DisplayOrder kBackground1Order = kInterfaceLayer;
+static const DisplayOrder kBackground2Order = kBackground1Order + 1;
+static const DisplayOrder kBackground3Order = kBackground2Order + 1;
+static const DisplayOrder kBackground4Order = kBackground3Order + 1;
+static const DisplayOrder kDateOrder = kBackground4Order + 1;
+static const DisplayOrder kCompassOrder = kDateOrder + 1;
+static const DisplayOrder kEnergyBarOrder = kCompassOrder + 1;
+static const DisplayOrder kEnergyLightOrder = kEnergyBarOrder + 1;
+
+static const DisplayOrder kAILayer = 22000;
+static const DisplayOrder kAILeftAreaOrder = kAILayer;
+static const DisplayOrder kAIMiddleAreaOrder = kAILeftAreaOrder + 1;
+static const DisplayOrder kAIRightAreaOrder = kAIMiddleAreaOrder + 1;
+static const DisplayOrder kAIMovieOrder = kAIRightAreaOrder + 1;
+
+static const DisplayOrder kHilitesLayer = 23000;
+static const DisplayOrder kInventoryHiliteOrder = kHilitesLayer;
+static const DisplayOrder kBiochipHiliteOrder = kInventoryHiliteOrder + 1;
+
+static const DisplayOrder kPanelsLayer = 25000;
+static const DisplayOrder kInventoryPushOrder = kPanelsLayer;
+static const DisplayOrder kInventoryLidOrder = kInventoryPushOrder + 1;
+static const DisplayOrder kBiochipPushOrder = kInventoryLidOrder + 1;
+static const DisplayOrder kBiochipLidOrder = kBiochipPushOrder + 1;
+static const DisplayOrder kFinalMessageOrder = kBiochipLidOrder + 1;
+
+static const DisplayOrder kInfoLayer = 26000;
+static const DisplayOrder kInfoBackgroundOrder = kInfoLayer;
+static const DisplayOrder kInfoSpinOrder = kInfoBackgroundOrder + 1;
+
+static const DisplayOrder kScreenDimmerOrder = 30000;
+
+static const DisplayOrder kPauseScreenLayer = 31000;
+static const DisplayOrder kPauseMenuOrder = kPauseScreenLayer;
+static const DisplayOrder kSaveGameOrder = kPauseMenuOrder + 1;
+static const DisplayOrder kContinueOrder = kSaveGameOrder + 1;
+static const DisplayOrder kRestoreOrder = kContinueOrder + 1;
+static const DisplayOrder kSoundFXOrder = kRestoreOrder + 1;
+static const DisplayOrder kAmbienceOrder = kSoundFXOrder + 1;
+static const DisplayOrder kWalkthruOrder = kAmbienceOrder + 1;
+static const DisplayOrder kQuitToMainMenuOrder = kWalkthruOrder + 1;
+static const DisplayOrder kPauseLargeHiliteOrder = kQuitToMainMenuOrder + 1;
+static const DisplayOrder kPauseSmallHiliteOrder = kPauseLargeHiliteOrder + 1;
+
+/////////////////////////////////////////////
+//
+// Death reasons.
+enum {
+ // Caldoria
+ kDeathUncreatedInCaldoria = 1,
+ kDeathCardBomb,
+ kDeathShotBySinclair,
+ kDeathSinclairShotDelegate,
+ kDeathNuclearExplosion,
+
+ // TSA
+ kDeathUncreatedInTSA,
+ kDeathShotByTSARobots,
+
+ // Prehistoric
+ kDeathFallOffCliff,
+ kDeathEatenByDinosaur,
+ kDeathStranded,
+
+ // Norad
+ kDeathGassedInNorad,
+ kDeathArrestedInNorad,
+ kDeathWokeUpNorad,
+ kDeathSubDestroyed, // Unused
+ kDeathRobotThroughNoradDoor,
+ kDeathRobotSubControlRoom,
+
+ // Mars
+ kDeathWrongShuttleLock,
+ kDeathArrestedInMars,
+ kDeathRunOverByPod,
+ kDeathDidntGetOutOfWay,
+ kDeathReactorBurn,
+ kDeathDidntFindMarsBomb,
+ kDeathDidntDisarmMarsBomb,
+ kDeathNoMaskInMaze,
+ kDeathNoAirInMaze,
+ kDeathGroundByMazebot,
+ kDeathMissedOreBucket,
+ kDeathDidntLeaveBucket,
+ kDeathRanIntoCanyonWall, // Unused
+ kDeathRanIntoSpaceJunk,
+
+ // WSC
+ kDeathDidntStopPoison,
+ kDeathArrestedInWSC,
+ kDeathHitByPlasma,
+ kDeathShotOnCatwalk,
+
+ // Winning
+ kPlayerWonGame
+};
+
+static const CoordType kAILeftAreaLeft = 76;
+static const CoordType kAILeftAreaTop = 334;
+
+static const CoordType kAILeftAreaWidth = 96;
+static const CoordType kAILeftAreaHeight = 96;
+
+static const CoordType kAIMiddleAreaLeft = 172;
+static const CoordType kAIMiddleAreaTop = 334;
+
+static const CoordType kAIMiddleAreaWidth = 192;
+static const CoordType kAIMiddleAreaHeight = 96;
+
+static const CoordType kAIRightAreaLeft = 364;
+static const CoordType kAIRightAreaTop = 334;
+
+static const CoordType kAIRightAreaWidth = 96;
+static const CoordType kAIRightAreaHeight = 96;
+
+enum {
+ kTSAPlayerNotArrived, // initial state, must be zero
+ kTSAPlayerForcedReview, // Player must watch TBP before rip occurs.
+ kTSAPlayerDetectedRip, // Player finished TBP, rip alarm just went off.
+ kTSAPlayerNeedsHistoricalLog, // Player is instructed to get historical log
+ kTSAPlayerGotHistoricalLog,
+ kTSAPlayerInstalledHistoricalLog,
+ kTSABossSawHistoricalLog,
+ kRobotsAtCommandCenter,
+ kRobotsAtFrontDoor,
+ kRobotsAtReadyRoom,
+ kPlayerLockedInPegasus,
+ kPlayerOnWayToPrehistoric,
+ kPlayerWentToPrehistoric,
+ kPlayerOnWayToNorad,
+ kPlayerOnWayToMars,
+ kPlayerOnWayToWSC,
+ kPlayerFinishedWithTSA
+};
+
+/////////////////////////////////////////////
+//
+// Mode static constants.
+
+static const GameMode kModeInventoryPick = kLastGameShellMode + 1;
+static const GameMode kModeBiochipPick = kModeInventoryPick + 1;
+static const GameMode kModeInfoScreen = kModeBiochipPick + 1;
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/cursor.cpp b/engines/pegasus/cursor.cpp
new file mode 100644
index 0000000000..5babdf34af
--- /dev/null
+++ b/engines/pegasus/cursor.cpp
@@ -0,0 +1,213 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/events.h"
+#include "common/stream.h"
+#include "common/system.h"
+#include "graphics/cursorman.h"
+#include "graphics/surface.h"
+#include "graphics/decoders/pict.h"
+
+#include "pegasus/cursor.h"
+#include "pegasus/graphics.h"
+#include "pegasus/pegasus.h"
+
+namespace Pegasus {
+
+Cursor::Cursor() {
+ _cursorObscured = false;
+ _index = -1;
+ startIdling();
+}
+
+Cursor::~Cursor() {
+ for (uint32 i = 0; i < _info.size(); i++) {
+ if (_info[i].surface) {
+ _info[i].surface->free();
+ delete _info[i].surface;
+ }
+ delete[] _info[i].palette;
+ }
+
+ stopIdling();
+}
+
+void Cursor::addCursorFrames(uint16 id) {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+ Common::SeekableReadStream *cursStream = vm->_resFork->getResource(MKTAG('C', 'u', 'r', 's'), id);
+ if (!cursStream)
+ error("Could not load cursor frames set %d", id);
+
+ uint16 frameCount = cursStream->readUint16BE();
+ for (uint16 i = 0; i < frameCount; i++) {
+ CursorInfo info;
+ info.tag = cursStream->readUint16BE();
+ info.hotspot.x = cursStream->readUint16BE();
+ info.hotspot.y = cursStream->readUint16BE();
+ info.surface = 0;
+ info.palette = 0;
+ info.colorCount = 0;
+ _info.push_back(info);
+ }
+
+ delete cursStream;
+
+ setCurrentFrameIndex(0);
+}
+
+void Cursor::setCurrentFrameIndex(int32 index) {
+ if (_index != index) {
+ _index = index;
+ if (index != -1) {
+ loadCursorImage(_info[index]);
+ CursorMan.replaceCursorPalette(_info[index].palette, 0, _info[index].colorCount);
+ CursorMan.replaceCursor((byte *)_info[index].surface->pixels, _info[index].surface->w, _info[index].surface->h, _info[index].hotspot.x, _info[index].hotspot.y, 0);
+ ((PegasusEngine *)g_engine)->_gfx->markCursorAsDirty();
+ }
+ }
+}
+
+int32 Cursor::getCurrentFrameIndex() const {
+ return _index;
+}
+
+void Cursor::show() {
+ if (!isVisible())
+ CursorMan.showMouse(true);
+
+ _cursorObscured = false;
+ ((PegasusEngine *)g_engine)->_gfx->markCursorAsDirty();
+}
+
+void Cursor::hide() {
+ CursorMan.showMouse(false);
+ setCurrentFrameIndex(0);
+ ((PegasusEngine *)g_engine)->_gfx->markCursorAsDirty();
+}
+
+void Cursor::hideUntilMoved() {
+ if (!_cursorObscured) {
+ hide();
+ _cursorObscured = true;
+ }
+}
+
+void Cursor::useIdleTime() {
+ if (g_system->getEventManager()->getMousePos() != _cursorLocation) {
+ _cursorLocation = g_system->getEventManager()->getMousePos();
+ if (_index != -1 && _cursorObscured)
+ show();
+ ((PegasusEngine *)g_engine)->_gfx->markCursorAsDirty();
+ }
+}
+
+void Cursor::getCursorLocation(Common::Point &pt) const {
+ pt = _cursorLocation;
+}
+
+bool Cursor::isVisible() {
+ return CursorMan.isVisible();
+}
+
+void Cursor::loadCursorImage(CursorInfo &cursorInfo) {
+ if (cursorInfo.surface)
+ return;
+
+ cursorInfo.surface = new Graphics::Surface();
+
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+ Common::SeekableReadStream *cicnStream = vm->_resFork->getResource(MKTAG('c', 'i', 'c', 'n'), cursorInfo.tag);
+
+ if (!cicnStream)
+ error("Failed to find color icon %d", cursorInfo.tag);
+
+ // PixMap section
+ Graphics::PICTDecoder::PixMap pixMap = Graphics::PICTDecoder::readPixMap(*cicnStream);
+
+ // Mask section
+ cicnStream->readUint32BE(); // mask baseAddr
+ uint16 maskRowBytes = cicnStream->readUint16BE(); // mask rowBytes
+ cicnStream->skip(3 * 2); // mask rect
+ /* uint16 maskHeight = */ cicnStream->readUint16BE();
+
+ // Bitmap section
+ cicnStream->readUint32BE(); // baseAddr
+ uint16 rowBytes = cicnStream->readUint16BE();
+ cicnStream->readUint16BE(); // top
+ cicnStream->readUint16BE(); // left
+ uint16 height = cicnStream->readUint16BE(); // bottom
+ cicnStream->readUint16BE(); // right
+
+ // Data section
+ cicnStream->readUint32BE(); // icon handle
+ cicnStream->skip(maskRowBytes * height); // FIXME: maskHeight doesn't work here, though the specs say it should
+ cicnStream->skip(rowBytes * height);
+
+ // Palette section
+ cicnStream->readUint32BE(); // always 0
+ cicnStream->readUint16BE(); // always 0
+ cursorInfo.colorCount = cicnStream->readUint16BE() + 1;
+
+ cursorInfo.palette = new byte[cursorInfo.colorCount * 3];
+ for (uint16 i = 0; i < cursorInfo.colorCount; i++) {
+ cicnStream->readUint16BE();
+ cursorInfo.palette[i * 3] = cicnStream->readUint16BE() >> 8;
+ cursorInfo.palette[i * 3 + 1] = cicnStream->readUint16BE() >> 8;
+ cursorInfo.palette[i * 3 + 2] = cicnStream->readUint16BE() >> 8;
+ }
+
+ // PixMap data
+ if (pixMap.pixelSize == 8) {
+ cursorInfo.surface->create(pixMap.rowBytes, pixMap.bounds.height(), Graphics::PixelFormat::createFormatCLUT8());
+ cicnStream->read(cursorInfo.surface->pixels, pixMap.rowBytes * pixMap.bounds.height());
+
+ // While this looks sensible, it actually doesn't work for some cursors
+ // (ie. the 'can grab' hand)
+ //cursorInfo.surface->w = pixMap.bounds.width();
+ } else if (pixMap.pixelSize == 1) {
+ cursorInfo.surface->create(pixMap.bounds.width(), pixMap.bounds.height(), Graphics::PixelFormat::createFormatCLUT8());
+
+ for (int y = 0; y < pixMap.bounds.height(); y++) {
+ byte *line = (byte *)cursorInfo.surface->getBasePtr(0, y);
+
+ for (int x = 0; x < pixMap.bounds.width();) {
+ byte b = cicnStream->readByte();
+
+ for (int i = 0; i < 8; i++) {
+ *line++ = ((b & (1 << (7 - i))) != 0) ? 1 : 0;
+
+ if (++x == pixMap.bounds.width())
+ break;
+ }
+ }
+ }
+ } else {
+ error("Unhandled %dbpp cicn images", pixMap.pixelSize);
+ }
+
+ delete cicnStream;
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/cursor.h b/engines/pegasus/cursor.h
new file mode 100644
index 0000000000..ada82e3967
--- /dev/null
+++ b/engines/pegasus/cursor.h
@@ -0,0 +1,84 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_CURSOR_H
+#define PEGASUS_CURSOR_H
+
+#include "common/array.h"
+#include "common/rect.h"
+
+#include "pegasus/timers.h"
+
+namespace Graphics {
+ struct Surface;
+}
+
+namespace Pegasus {
+
+// The original cursor code was in the graphics code directly,
+// unlike ScummVM where we have the cursor code separate. We're
+// going to go with CursorManager here and therefore not inherit
+// from the Sprite class.
+
+class Cursor : private Idler {
+public:
+ Cursor();
+ virtual ~Cursor();
+
+ void addCursorFrames(uint16 id);
+
+ void setCurrentFrameIndex(int32 index);
+ int32 getCurrentFrameIndex() const;
+
+ void show();
+ void hide();
+ void hideUntilMoved();
+ bool isVisible();
+
+ void getCursorLocation(Common::Point &) const;
+
+protected:
+ virtual void useIdleTime();
+
+private:
+ struct CursorInfo {
+ uint16 tag;
+ Common::Point hotspot;
+ Graphics::Surface *surface;
+ byte *palette;
+ uint16 colorCount;
+ };
+
+ Common::Point _cursorLocation;
+ Common::Array<CursorInfo> _info;
+ bool _cursorObscured;
+ int _index;
+
+ void loadCursorImage(CursorInfo &cursorInfo);
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/detection.cpp b/engines/pegasus/detection.cpp
new file mode 100644
index 0000000000..908005b665
--- /dev/null
+++ b/engines/pegasus/detection.cpp
@@ -0,0 +1,157 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "base/plugins.h"
+
+#include "engines/advancedDetector.h"
+#include "common/config-manager.h"
+#include "common/file.h"
+#include "common/savefile.h"
+
+#include "pegasus/pegasus.h"
+
+namespace Pegasus {
+
+struct PegasusGameDescription {
+ ADGameDescription desc;
+};
+
+bool PegasusEngine::hasFeature(EngineFeature f) const {
+ return
+ (f == kSupportsRTL)
+ || (f == kSupportsLoadingDuringRuntime)
+ || (f == kSupportsSavingDuringRuntime);
+}
+
+bool PegasusEngine::isDemo() const {
+ return (_gameDescription->desc.flags & ADGF_DEMO) != 0;
+}
+
+} // End of namespace Pegasus
+
+static const PlainGameDescriptor pegasusGames[] = {
+ {"pegasus", "The Journeyman Project: Pegasus Prime"},
+ {0, 0}
+};
+
+
+namespace Pegasus {
+
+static const PegasusGameDescription gameDescriptions[] = {
+ {
+ {
+ "pegasus",
+ "",
+ AD_ENTRY1s("JMP PP Resources", "d13a602d2498010d720a6534f097f88b", 2009943),
+ Common::EN_ANY,
+ Common::kPlatformMacintosh,
+ ADGF_MACRESFORK,
+ GUIO0()
+ },
+ },
+
+ {
+ {
+ "pegasus",
+ "Demo",
+ AD_ENTRY1s("JMP PP Resources", "d13a602d2498010d720a6534f097f88b", 360129),
+ Common::EN_ANY,
+ Common::kPlatformMacintosh,
+ ADGF_MACRESFORK|ADGF_DEMO,
+ GUIO1(GUIO_NOLAUNCHLOAD)
+ },
+ },
+
+ { AD_TABLE_END_MARKER }
+};
+
+} // End of namespace Pegasus
+
+
+class PegasusMetaEngine : public AdvancedMetaEngine {
+public:
+ PegasusMetaEngine() : AdvancedMetaEngine(Pegasus::gameDescriptions, sizeof(Pegasus::PegasusGameDescription), pegasusGames) {
+ _singleid = "pegasus";
+ }
+
+ virtual const char *getName() const {
+ return "The Journeyman Project: Pegasus Prime";
+ }
+
+ virtual const char *getOriginalCopyright() const {
+ return "The Journeyman Project: Pegasus Prime (C) Presto Studios";
+ }
+
+ virtual bool hasFeature(MetaEngineFeature f) const;
+ virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+ virtual SaveStateList listSaves(const char *target) const;
+ virtual int getMaximumSaveSlot() const { return 999; }
+ virtual void removeSaveState(const char *target, int slot) const;
+};
+
+bool PegasusMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsListSaves)
+ || (f == kSupportsLoadingDuringStartup)
+ || (f == kSupportsDeleteSave);
+}
+
+SaveStateList PegasusMetaEngine::listSaves(const char *target) const {
+ // The original had no pattern, so the user must rename theirs
+ // Note that we ignore the target because saves are compatible between
+ // all versions
+ Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles("pegasus-*.sav");
+
+ SaveStateList saveList;
+ for (uint32 i = 0; i < filenames.size(); i++) {
+ // Isolate the description from the file name
+ Common::String desc = filenames[i].c_str() + 8;
+ for (int j = 0; j < 4; j++)
+ desc.deleteLastChar();
+
+ saveList.push_back(SaveStateDescriptor(i, desc));
+ }
+
+ return saveList;
+}
+
+void PegasusMetaEngine::removeSaveState(const char *target, int slot) const {
+ // See listSaves() for info on the pattern
+ Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles("pegasus-*.sav");
+ g_system->getSavefileManager()->removeSavefile(filenames[slot].c_str());
+}
+
+bool PegasusMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
+ const Pegasus::PegasusGameDescription *gd = (const Pegasus::PegasusGameDescription *)desc;
+
+ if (gd)
+ *engine = new Pegasus::PegasusEngine(syst, gd);
+
+ return (gd != 0);
+}
+
+#if PLUGIN_ENABLED_DYNAMIC(PEGASUS)
+ REGISTER_PLUGIN_DYNAMIC(PEGASUS, PLUGIN_TYPE_ENGINE, PegasusMetaEngine);
+#else
+ REGISTER_PLUGIN_STATIC(PEGASUS, PLUGIN_TYPE_ENGINE, PegasusMetaEngine);
+#endif
+
diff --git a/engines/pegasus/elements.cpp b/engines/pegasus/elements.cpp
new file mode 100644
index 0000000000..c84d555444
--- /dev/null
+++ b/engines/pegasus/elements.cpp
@@ -0,0 +1,568 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/macresman.h"
+#include "common/stream.h"
+
+#include "pegasus/elements.h"
+#include "pegasus/graphics.h"
+#include "pegasus/surface.h"
+
+namespace Pegasus {
+
+DisplayElement::DisplayElement(const DisplayElementID id) : IDObject(id) {
+ _elementIsDisplaying = false;
+ _elementIsVisible = false;
+ _elementOrder = 0;
+ _triggeredElement = this;
+ _nextElement = 0;
+}
+
+DisplayElement::~DisplayElement() {
+ if (isDisplaying())
+ ((PegasusEngine *)g_engine)->_gfx->removeDisplayElement(this);
+}
+
+void DisplayElement::setDisplayOrder(const DisplayOrder order) {
+ if (_elementOrder != order) {
+ _elementOrder = order;
+ if (isDisplaying()) {
+ ((PegasusEngine *)g_engine)->_gfx->removeDisplayElement(this);
+ ((PegasusEngine *)g_engine)->_gfx->addDisplayElement(this);
+ triggerRedraw();
+ }
+ }
+}
+
+void DisplayElement::startDisplaying() {
+ if (!isDisplaying()) {
+ ((PegasusEngine *)g_engine)->_gfx->addDisplayElement(this);
+ triggerRedraw();
+ }
+}
+
+void DisplayElement::stopDisplaying() {
+ if (isDisplaying()) {
+ triggerRedraw();
+ ((PegasusEngine *)g_engine)->_gfx->removeDisplayElement(this);
+ }
+}
+
+void DisplayElement::setBounds(const CoordType left, const CoordType top, const CoordType right, const CoordType bottom) {
+ setBounds(Common::Rect(left, top, right, bottom));
+}
+
+void DisplayElement::getBounds(Common::Rect &r) const {
+ r = _bounds;
+}
+
+void DisplayElement::sizeElement(const CoordType h, const CoordType v) {
+ Common::Rect newBounds = _bounds;
+ newBounds.right = _bounds.left + h;
+ newBounds.bottom = _bounds.top + v;
+ setBounds(newBounds);
+}
+
+void DisplayElement::moveElementTo(const CoordType h, const CoordType v) {
+ Common::Rect newBounds = _bounds;
+ newBounds.moveTo(h, v);
+ setBounds(newBounds);
+}
+
+void DisplayElement::moveElement(const CoordType dh, const CoordType dv) {
+ Common::Rect newBounds = _bounds;
+ newBounds.translate(dh, dv);
+ setBounds(newBounds);
+}
+
+void DisplayElement::getLocation(CoordType &h, CoordType &v) const {
+ h = _bounds.left;
+ v = _bounds.top;
+}
+
+void DisplayElement::centerElementAt(const CoordType h, const CoordType v) {
+ Common::Rect newBounds = _bounds;
+ newBounds.moveTo(h - (_bounds.width() / 2), v - (_bounds.height() / 2));
+ setBounds(newBounds);
+}
+
+void DisplayElement::getCenter(CoordType &h, CoordType &v) const {
+ h = (_bounds.left + _bounds.right) / 2;
+ v = (_bounds.top + _bounds.bottom) / 2;
+}
+
+void DisplayElement::setBounds(const Common::Rect &r) {
+ if (r != _bounds) {
+ triggerRedraw();
+ _bounds = r;
+ triggerRedraw();
+ }
+}
+
+void DisplayElement::hide() {
+ if (_elementIsVisible) {
+ triggerRedraw();
+ _elementIsVisible = false;
+ }
+}
+
+void DisplayElement::show() {
+ if (!_elementIsVisible) {
+ _elementIsVisible = true;
+ triggerRedraw();
+ }
+}
+
+// Only invalidates this element's bounding rectangle if all these conditions are true:
+// -- The triggered element is this element.
+// -- The element is displaying on the display list.
+// -- The element is visible.
+// -- The element is part of the active layer OR is one of the reserved items.
+void DisplayElement::triggerRedraw() {
+ GraphicsManager *gfx = ((PegasusEngine *)g_engine)->_gfx;
+
+ if (_triggeredElement == this) {
+ if (validToDraw(gfx->getBackOfActiveLayer(), gfx->getFrontOfActiveLayer()))
+ gfx->invalRect(_bounds);
+ } else {
+ _triggeredElement->triggerRedraw();
+ }
+}
+
+void DisplayElement::setTriggeredElement(DisplayElement *element) {
+ if (element)
+ _triggeredElement = element;
+ else
+ _triggeredElement = this;
+}
+
+bool DisplayElement::validToDraw(DisplayOrder backLayer, DisplayOrder frontLayer) {
+ return isDisplaying() && _elementIsVisible &&
+ (getObjectID() <= kHighestReservedElementID ||
+ (getDisplayOrder() >= backLayer &&
+ getDisplayOrder() <= frontLayer));
+}
+
+DropHighlight::DropHighlight(const DisplayElementID id) : DisplayElement(id) {
+ _highlightColor = 0;
+ _thickness = 2;
+ _cornerDiameter = 0;
+}
+
+void DropHighlight::draw(const Common::Rect &) {
+ Graphics::Surface *screen = ((PegasusEngine *)g_engine)->_gfx->getWorkArea();
+
+ // Since this is only used in two different ways, I'm only
+ // going to implement it in those two ways. Deal with it.
+
+ Common::Rect rect = _bounds;
+ rect.grow(-_thickness);
+ screen->frameRect(rect, _highlightColor);
+ rect.grow(1);
+ screen->frameRect(rect, _highlightColor);
+
+ if (_cornerDiameter == 8 && _thickness == 4) {
+ rect.grow(1);
+ screen->frameRect(rect, _highlightColor);
+ screen->hLine(rect.left + 1, rect.top - 1, rect.right - 2, _highlightColor);
+ screen->hLine(rect.left + 1, rect.bottom, rect.right - 2, _highlightColor);
+ screen->vLine(rect.left - 1, rect.top + 1, rect.bottom - 2, _highlightColor);
+ screen->vLine(rect.right, rect.top + 1, rect.bottom - 2, _highlightColor);
+ }
+}
+
+IdlerAnimation::IdlerAnimation(const DisplayElementID id) : Animation(id) {
+ _lastTime = 0xffffffff;
+}
+
+void IdlerAnimation::startDisplaying() {
+ if (!isDisplaying()) {
+ Animation::startDisplaying();
+ startIdling();
+ }
+}
+
+void IdlerAnimation::stopDisplaying() {
+ if (isDisplaying()) {
+ Animation::stopDisplaying();
+ stopIdling();
+ }
+}
+
+void IdlerAnimation::useIdleTime() {
+ uint32 currentTime = getTime();
+
+ if (currentTime != _lastTime) {
+ _lastTime = currentTime;
+ timeChanged(_lastTime);
+ }
+}
+
+void IdlerAnimation::timeChanged(const TimeValue) {
+ triggerRedraw();
+}
+
+FrameSequence::FrameSequence(const DisplayElementID id) : IdlerAnimation(id) {
+ _duration = 0;
+ _currentFrameNum = 0;
+ _resFork = new Common::MacResManager();
+ _numFrames = 0;
+}
+
+FrameSequence::~FrameSequence() {
+ delete _resFork;
+}
+
+void FrameSequence::useFileName(const Common::String &fileName) {
+ _resFork->open(fileName);
+}
+
+void FrameSequence::openFrameSequence() {
+ if (!_resFork->hasResFork())
+ return;
+
+ Common::SeekableReadStream *res = _resFork->getResource(MKTAG('P', 'F', 'r', 'm'), 0x80);
+
+ if (!res)
+ return;
+
+ uint32 scale = res->readUint32BE();
+ _bounds.top = res->readUint16BE();
+ _bounds.left = res->readUint16BE();
+ _bounds.bottom = res->readUint16BE();
+ _bounds.right = res->readUint16BE();
+ _numFrames = res->readUint16BE();
+ _duration = 0;
+
+ _frameTimes.clear();
+ for (uint32 i = 0; i < _numFrames; i++) {
+ TimeValue time = res->readUint32BE();
+ _duration += time;
+ _frameTimes.push_back(_duration);
+ }
+
+ setScale(scale);
+ setSegment(0, _duration);
+ setTime(0);
+ _currentFrameNum = 0;
+ newFrame(_currentFrameNum);
+ triggerRedraw();
+
+ delete res;
+}
+
+void FrameSequence::closeFrameSequence() {
+ stop();
+ _resFork->close();
+ _duration = 0;
+ _numFrames = 0;
+ _frameTimes.clear();
+}
+
+void FrameSequence::timeChanged(const TimeValue time) {
+ int16 frameNum = 0;
+ for (int16 i = _numFrames - 1; i >= 0; i--) {
+ if (_frameTimes[i] < time) {
+ frameNum = i;
+ break;
+ }
+ }
+
+ if (frameNum != _currentFrameNum) {
+ _currentFrameNum = frameNum;
+ newFrame(_currentFrameNum);
+ triggerRedraw();
+ }
+}
+
+void FrameSequence::setFrameNum(const int16 frameNum) {
+ int16 f = CLIP<int>(frameNum, 0, _numFrames);
+
+ if (_currentFrameNum != f) {
+ _currentFrameNum = f;
+ setTime(_frameTimes[f]);
+ newFrame(f);
+ triggerRedraw();
+ }
+}
+
+bool FrameSequence::isSequenceOpen() const {
+ return _numFrames != 0;
+}
+
+Sprite::Sprite(const DisplayElementID id) : DisplayElement(id) {
+ _numFrames = 0;
+ _currentFrameNum = 0xffffffff;
+ _currentFrame = 0;
+}
+
+Sprite::~Sprite() {
+ discardFrames();
+}
+
+void Sprite::discardFrames() {
+ if (!_frameArray.empty()) {
+ for (uint32 i = 0; i < _numFrames; i++) {
+ SpriteFrame *frame = _frameArray[i].frame;
+ frame->_referenceCount--;
+ if (frame->_referenceCount == 0)
+ delete frame;
+ }
+
+ _frameArray.clear();
+ _numFrames = 0;
+ _currentFrame = 0;
+ _currentFrameNum = 0xffffffff;
+ setBounds(0, 0, 0, 0);
+ }
+}
+
+void Sprite::addPICTResourceFrame(const ResIDType pictID, bool transparent, const CoordType left, const CoordType top) {
+ SpriteFrame *frame = new SpriteFrame();
+ frame->initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, pictID, transparent);
+ addFrame(frame, left, top);
+}
+
+uint32 Sprite::addFrame(SpriteFrame *frame, const CoordType left, const CoordType top) {
+ SpriteFrameRec frameRecord;
+ frameRecord.frame = frame;
+ frameRecord.frameLeft = left;
+ frameRecord.frameTop = top;
+ _frameArray.push_back(frameRecord);
+ _numFrames++;
+ frame->_referenceCount++;
+
+ Common::Rect frameBounds;
+ frame->getSurfaceBounds(frameBounds);
+
+ // 9/3/96
+ // BB Should this be + left or - left?
+ frameBounds.moveTo(_bounds.left + left, _bounds.top + top);
+
+ frameBounds.extend(_bounds);
+
+ if (_bounds != frameBounds)
+ setBounds(frameBounds);
+
+ return _numFrames - 1;
+}
+
+void Sprite::removeFrame(const uint32 frameNum) {
+ _frameArray[frameNum].frame->_referenceCount--;
+ if (_frameArray[frameNum].frame->_referenceCount == 0)
+ delete _frameArray[frameNum].frame;
+
+ // Calculate the new bounds
+ Common::Rect frameBounds;
+ for (uint32 i = 0; i < _numFrames; i++) {
+ if (i == frameNum)
+ continue;
+
+ Common::Rect r;
+ _frameArray[i].frame->getSurfaceBounds(r);
+ r.translate(_frameArray[i].frameLeft, _frameArray[i].frameTop);
+ frameBounds.extend(r);
+ }
+
+ _frameArray.remove_at(frameNum);
+
+ frameBounds.moveTo(_bounds.left, _bounds.top);
+ setBounds(frameBounds);
+
+ if (_currentFrameNum == frameNum)
+ triggerRedraw();
+ else if (_currentFrameNum != 0xffffffff && _currentFrameNum > frameNum)
+ --_currentFrameNum;
+}
+
+void Sprite::setCurrentFrameIndex(const int32 frameNum) {
+ if (frameNum < 0) {
+ if (_currentFrameNum != 0xffffffff) {
+ _currentFrameNum = 0xffffffff;
+ _currentFrame = 0;
+ triggerRedraw();
+ }
+ } else if (_numFrames > 0) {
+ uint32 f = frameNum % _numFrames;
+ if (f != _currentFrameNum) {
+ _currentFrameNum = f;
+ _currentFrame = &_frameArray[f];
+ triggerRedraw();
+ }
+ }
+}
+
+SpriteFrame *Sprite::getFrame(const int32 index) {
+ if (index < 0 || (uint32)index >= _numFrames)
+ return 0;
+
+ return _frameArray[index].frame;
+}
+
+void Sprite::draw(const Common::Rect &r) {
+ if (_currentFrame) {
+ Common::Rect frameBounds;
+ _currentFrame->frame->getSurfaceBounds(frameBounds);
+
+ frameBounds.translate(_bounds.left + _currentFrame->frameLeft, _bounds.top + _currentFrame->frameTop);
+ Common::Rect r1 = frameBounds.findIntersectingRect(r);
+
+ Common::Rect r2 = frameBounds;
+ r2.translate(-_bounds.left - _currentFrame->frameLeft, -_bounds.top - _currentFrame->frameTop);
+
+ _currentFrame->frame->drawImage(r2, r1);
+ }
+}
+
+SpriteSequence::SpriteSequence(const DisplayElementID id, const DisplayElementID spriteID) :
+ FrameSequence(id), _sprite(spriteID), _transparent(false) {
+}
+
+void SpriteSequence::openFrameSequence() {
+ if (!isSequenceOpen()) {
+ FrameSequence::openFrameSequence();
+
+ if (isSequenceOpen()) {
+ uint32 numFrames = getNumFrames();
+
+ for (uint32 i = 0; i < numFrames; ++i) {
+ SpriteFrame *frame = new SpriteFrame();
+ frame->initFromPICTResource(_resFork, i + 0x80, _transparent);
+ _sprite.addFrame(frame, 0, 0);
+ }
+
+ _sprite.setBounds(_bounds);
+ }
+ }
+}
+
+void SpriteSequence::closeFrameSequence() {
+ if (isSequenceOpen()) {
+ FrameSequence::closeFrameSequence();
+ _sprite.discardFrames();
+ }
+}
+
+void SpriteSequence::setBounds(const Common::Rect &bounds) {
+ FrameSequence::setBounds(bounds);
+ _sprite.setBounds(_bounds);
+}
+
+void SpriteSequence::draw(const Common::Rect &r) {
+ _sprite.draw(r);
+}
+
+void SpriteSequence::newFrame(const uint16 frame) {
+ _sprite.setCurrentFrameIndex(frame);
+}
+
+#define DRAW_PIXEL() \
+ if (bytesPerPixel == 2) \
+ *((uint16 *)dst) = black; \
+ else \
+ *((uint32 *)dst) = black; \
+ dst += bytesPerPixel
+
+#define SKIP_PIXEL() \
+ dst += bytesPerPixel
+
+void ScreenDimmer::draw(const Common::Rect &r) {
+ // We're going to emulate QuickDraw's srcOr+gray mode here
+ // In this mode, every other y column is all black (odd-columns).
+ // Basically, every row does three black and then one transparent
+ // repeatedly.
+
+ // The output is identical to the original
+
+ uint32 black = g_system->getScreenFormat().RGBToColor(0, 0, 0);
+ Graphics::Surface *screen = ((PegasusEngine *)g_engine)->_gfx->getWorkArea();
+ byte bytesPerPixel = g_system->getScreenFormat().bytesPerPixel;
+
+ // We're currently doing it to the whole screen to simplify the code
+
+ for (int y = 0; y < 480; y++) {
+ byte *dst = (byte *)screen->getBasePtr(0, y);
+
+ for (int x = 0; x < 640; x += 4) {
+ if (y & 1) {
+ DRAW_PIXEL();
+ DRAW_PIXEL();
+ SKIP_PIXEL();
+ DRAW_PIXEL();
+ } else {
+ SKIP_PIXEL();
+ DRAW_PIXEL();
+ DRAW_PIXEL();
+ DRAW_PIXEL();
+ }
+ }
+ }
+}
+
+#undef DRAW_PIXEL
+#undef SKIP_PIXEL
+
+SoundLevel::SoundLevel(const DisplayElementID id) : DisplayElement(id) {
+ _soundLevel = 0;
+}
+
+void SoundLevel::incrementLevel() {
+ if (_soundLevel < 12) {
+ _soundLevel++;
+ triggerRedraw();
+ }
+}
+
+void SoundLevel::decrementLevel() {
+ if (_soundLevel > 0) {
+ _soundLevel--;
+ triggerRedraw();
+ }
+}
+
+uint16 SoundLevel::getSoundLevel() {
+ return CLIP<int>(_soundLevel * 22, 0, 256);
+}
+
+void SoundLevel::setSoundLevel(uint16 level) {
+ uint16 newLevel = (level + 21) / 22;
+
+ if (newLevel != _soundLevel) {
+ _soundLevel = newLevel;
+ triggerRedraw();
+ }
+}
+
+void SoundLevel::draw(const Common::Rect &r) {
+ Common::Rect levelRect(_bounds.right + (8 * (_soundLevel - 12)), _bounds.top, _bounds.right, _bounds.bottom);
+ levelRect = r.findIntersectingRect(levelRect);
+
+ if (!levelRect.isEmpty()) {
+ Graphics::Surface *screen = ((PegasusEngine *)g_engine)->_gfx->getWorkArea();
+ screen->fillRect(levelRect, g_system->getScreenFormat().RGBToColor(0, 0, 0));
+ }
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/elements.h b/engines/pegasus/elements.h
new file mode 100644
index 0000000000..140553f675
--- /dev/null
+++ b/engines/pegasus/elements.h
@@ -0,0 +1,254 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_ELEMENTS_H
+#define PEGASUS_ELEMENTS_H
+
+#include "common/array.h"
+#include "common/rect.h"
+#include "common/str.h"
+#include "common/system.h"
+#include "graphics/surface.h"
+
+#include "pegasus/timers.h"
+#include "pegasus/util.h"
+
+namespace Common {
+ class MacResManager;
+}
+
+namespace Pegasus {
+
+class DisplayElement : public IDObject {
+friend class GraphicsManager;
+public:
+ DisplayElement(const DisplayElementID);
+ virtual ~DisplayElement();
+
+ void setDisplayOrder(const DisplayOrder);
+ DisplayOrder getDisplayOrder() const { return _elementOrder; }
+
+ bool validToDraw(DisplayOrder, DisplayOrder);
+
+ virtual void draw(const Common::Rect&) {}
+ bool isDisplaying() { return _elementIsDisplaying; }
+ virtual void startDisplaying();
+ virtual void stopDisplaying();
+
+ virtual void show();
+ virtual void hide();
+ bool isVisible() { return _elementIsVisible; }
+
+ // triggerRedraw only triggers a draw if the element is displaying and visible.
+ void triggerRedraw();
+ void setTriggeredElement(DisplayElement *);
+
+ virtual void setBounds(const CoordType, const CoordType, const CoordType, const CoordType);
+ virtual void setBounds(const Common::Rect &);
+ virtual void getBounds(Common::Rect &) const;
+ virtual void sizeElement(const CoordType, const CoordType);
+ virtual void moveElementTo(const CoordType, const CoordType);
+ virtual void moveElement(const CoordType, const CoordType);
+ virtual void getLocation(CoordType &, CoordType &) const;
+ virtual void getCenter(CoordType &, CoordType &) const;
+ virtual void centerElementAt(const CoordType, const CoordType);
+
+protected:
+ Common::Rect _bounds;
+ bool _elementIsVisible;
+ DisplayElement *_triggeredElement;
+
+ // Used only by PegasusEngine
+ bool _elementIsDisplaying;
+ DisplayOrder _elementOrder;
+ DisplayElement *_nextElement;
+};
+
+// I'm using the proper "highlight" instead of the evil
+// QuickDraw "hilite" :P (deal with it!)
+class DropHighlight : public DisplayElement {
+public:
+ DropHighlight(const DisplayElementID);
+ virtual ~DropHighlight() {}
+
+ void setHighlightColor(const uint32 &highlight) { _highlightColor = highlight; }
+ void getHighlightColor(uint32 &highlight) const { highlight = _highlightColor; }
+
+ void setHighlightThickness(const uint16 thickness) { _thickness = thickness; }
+ uint16 getHighlightThickness() const { return _thickness; }
+
+ void setHighlightCornerDiameter(const uint16 diameter) { _cornerDiameter = diameter; }
+ uint16 getHighlightCornerDiameter() const { return _cornerDiameter; }
+
+ virtual void draw(const Common::Rect&);
+
+protected:
+ uint32 _highlightColor;
+ uint16 _thickness;
+ uint16 _cornerDiameter;
+};
+
+class Animation : public DisplayElement, public DynamicElement {
+public:
+ Animation(const DisplayElementID id) : DisplayElement(id) {}
+};
+
+class IdlerAnimation : public Animation, public Idler {
+public:
+ IdlerAnimation(const DisplayElementID);
+
+ virtual void startDisplaying();
+ virtual void stopDisplaying();
+
+ TimeValue getLastTime() const { return _lastTime; }
+
+protected:
+ virtual void useIdleTime();
+ virtual void timeChanged(const TimeValue);
+
+ TimeValue _lastTime;
+};
+
+// This class reads PICT resources and plays them like a movie.
+// Assumes there is a resource of type 'PFrm' describing the time values for each
+// PICT frame, as well as the total time in the movie.
+// Assumes that PICT frames begin at PICT 128
+
+class FrameSequence : public IdlerAnimation {
+public:
+ FrameSequence(const DisplayElementID);
+ virtual ~FrameSequence();
+
+ void useFileName(const Common::String &fileName);
+
+ virtual void openFrameSequence();
+ virtual void closeFrameSequence();
+ bool isSequenceOpen() const;
+
+ uint16 getNumFrames() const { return _numFrames; }
+ virtual uint16 getFrameNum() const { return _currentFrameNum; }
+ virtual void setFrameNum(const int16);
+
+protected:
+ virtual void timeChanged(const TimeValue);
+ virtual void newFrame(const uint16) {}
+
+ Common::MacResManager *_resFork;
+ TimeValue _duration;
+
+ uint16 _numFrames;
+ Common::Array<TimeValue> _frameTimes;
+
+ uint16 _currentFrameNum;
+};
+
+class SpriteFrame;
+
+class Sprite : public DisplayElement {
+friend class SpriteFrame;
+public:
+ Sprite(const DisplayElementID);
+ virtual ~Sprite();
+
+ virtual void addPICTResourceFrame(const ResIDType, const bool, const CoordType, const CoordType);
+ virtual uint32 addFrame(SpriteFrame *, const CoordType, const CoordType);
+ virtual void removeFrame(const uint32);
+ virtual void discardFrames();
+
+ // Setting the current frame.
+ // If the index is negative, sets the current frame to NULL and hides the sprite.
+ // If the index is larger than the number of frames in the sprite, the number
+ // is treated modulo the number of frames.
+ virtual void setCurrentFrameIndex(const int32);
+ virtual uint32 getCurrentFrameIndex() const { return _currentFrameNum; }
+
+ virtual SpriteFrame *getFrame(const int32);
+
+ virtual void draw(const Common::Rect &);
+
+ uint32 getNumFrames() const { return _numFrames; }
+
+protected:
+ struct SpriteFrameRec {
+ SpriteFrame *frame;
+ CoordType frameLeft;
+ CoordType frameTop;
+ };
+
+ uint32 _numFrames;
+ uint32 _currentFrameNum;
+ SpriteFrameRec *_currentFrame;
+ Common::Array<SpriteFrameRec> _frameArray;
+};
+
+class SpriteSequence : public FrameSequence {
+public:
+ SpriteSequence(const DisplayElementID id, const DisplayElementID spriteID);
+ virtual ~SpriteSequence() {}
+
+ void useTransparent(bool transparent) { _transparent = transparent; }
+
+ virtual void openFrameSequence();
+ virtual void closeFrameSequence();
+
+ virtual void draw(const Common::Rect &);
+
+ virtual void setBounds(const Common::Rect &);
+
+protected:
+ virtual void newFrame(const uint16);
+
+ bool _transparent;
+ Sprite _sprite;
+};
+
+class ScreenDimmer : public DisplayElement {
+public:
+ ScreenDimmer() : DisplayElement(kScreenDimmerID) {}
+ virtual ~ScreenDimmer() {}
+
+ virtual void draw(const Common::Rect &);
+};
+
+class SoundLevel : public DisplayElement {
+public:
+ SoundLevel(const DisplayElementID);
+ virtual ~SoundLevel() {}
+
+ void incrementLevel();
+ void decrementLevel();
+
+ uint16 getSoundLevel();
+ void setSoundLevel(uint16);
+
+ void draw(const Common::Rect &);
+
+protected:
+ uint16 _soundLevel;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/energymonitor.cpp b/engines/pegasus/energymonitor.cpp
new file mode 100644
index 0000000000..8aa77eb341
--- /dev/null
+++ b/engines/pegasus/energymonitor.cpp
@@ -0,0 +1,296 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/energymonitor.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/surface.h"
+
+namespace Pegasus {
+
+Blinker::Blinker() {
+ _sprite = 0;
+ _frame1 = -1;
+ _frame2 = -1;
+ _blinkDuration = 0;
+}
+
+void Blinker::startBlinking(Sprite *sprite, int32 frame1, int32 frame2, uint32 numBlinks, TimeValue blinkDuration, TimeScale blinkScale) {
+ stopBlinking();
+ _sprite = sprite;
+ _frame1 = frame1;
+ _frame2 = frame2;
+ _blinkDuration = blinkDuration;
+ setScale(blinkScale);
+ setSegment(0, blinkDuration * numBlinks * 2, blinkScale);
+ setTime(0);
+ start();
+}
+
+void Blinker::stopBlinking() {
+ if (_sprite) {
+ _sprite->setCurrentFrameIndex(_frame2);
+ _sprite = 0;
+ stop();
+ }
+}
+
+void Blinker::timeChanged(const TimeValue time) {
+ if (_sprite && _blinkDuration != 0) {
+ if (((time / _blinkDuration) & 1) != 0 || time == getDuration()) {
+ _sprite->setCurrentFrameIndex(_frame2);
+ if (!isRunning())
+ stopBlinking();
+ } else {
+ _sprite->setCurrentFrameIndex(_frame1);
+ }
+ }
+}
+
+static const NotificationFlags kEnergyExpiredFlag = 1;
+
+EnergyMonitor *g_energyMonitor = 0;
+
+EnergyMonitor::EnergyMonitor() : IdlerAnimation(kEnergyBarID), _energyLight(kWarningLightID) {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ _stage = kStageNoStage;
+
+ _calibrating = false;
+ _dontFlash = false;
+
+ setBounds(338, 48, 434, 54);
+
+ setDisplayOrder(kEnergyBarOrder);
+ startDisplaying();
+
+ SpriteFrame *frame = new SpriteFrame();
+ frame->initFromPICTResource(vm->_resFork, kLightOffID);
+ _energyLight.addFrame(frame, 0, 0);
+
+ frame = new SpriteFrame();
+ frame->initFromPICTResource(vm->_resFork, kLightYellowID);
+ _energyLight.addFrame(frame, 0, 0);
+
+ frame = new SpriteFrame();
+ frame->initFromPICTResource(vm->_resFork, kLightOrangeID);
+ _energyLight.addFrame(frame, 0, 0);
+
+ frame = new SpriteFrame();
+ frame->initFromPICTResource(vm->_resFork, kLightRedID);
+ _energyLight.addFrame(frame, 0, 0);
+
+ _energyLight.setBounds(540, 35, 600, 59);
+ _energyLight.setDisplayOrder(kEnergyLightOrder);
+ _energyLight.startDisplaying();
+
+ setScale(1);
+ setSegment(0, kMaxJMPEnergy);
+
+ setEnergyValue(kCasualEnergy);
+
+ g_energyMonitor = this;
+}
+
+EnergyMonitor::~EnergyMonitor() {
+ g_energyMonitor = 0;
+}
+
+void EnergyMonitor::setEnergyValue(const uint32 value) {
+ if (isRunning()) {
+ stop();
+ setTime(getStop() - value);
+ start();
+ } else {
+ setTime(getStop() - value);
+ }
+}
+
+void EnergyMonitor::startEnergyDraining() {
+ if (!isRunning()) {
+ _energyLight.show();
+ start();
+ show();
+ }
+}
+
+void EnergyMonitor::setEnergyDrainRate(Common::Rational rate) {
+ setRate(rate);
+}
+
+Common::Rational EnergyMonitor::getEnergyDrainRate() {
+ return getRate();
+}
+
+void EnergyMonitor::stopEnergyDraining() {
+ if (isRunning()) {
+ stop();
+ _energyLight.hide();
+ hide();
+ }
+}
+
+void EnergyMonitor::drainEnergy(const int32 delta) {
+ setTime(getTime() + delta);
+}
+
+int32 EnergyMonitor::getCurrentEnergy() {
+ return kMaxJMPEnergy - getTime();
+}
+
+void EnergyMonitor::timeChanged(const TimeValue currentTime) {
+ if (currentTime == getStop()) {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+ if (vm->getEnergyDeathReason() != -1)
+ vm->die(vm->getEnergyDeathReason());
+ } else {
+ uint32 currentEnergy = kMaxJMPEnergy - currentTime;
+
+ EnergyStage newStage;
+ if (currentEnergy > kWorriedEnergy)
+ newStage = kStageCasual;
+ else if (currentEnergy > kNervousEnergy)
+ newStage = kStageWorried;
+ else if (currentEnergy > kPanicStrickenEnergy)
+ newStage = kStageNervous;
+ else
+ newStage = kStagePanicStricken;
+
+ if (_stage != newStage) {
+ uint32 newFrame;
+
+ switch (newStage) {
+ case kStageCasual:
+ _barColor = g_system->getScreenFormat().RGBToColor(0x48, 0xB0, 0xD8);
+ newFrame = kFrameLightOff;
+ break;
+ case kStageWorried:
+ _barColor = g_system->getScreenFormat().RGBToColor(0xD8, 0xC0, 0x30);
+ newFrame = kFrameLightYellow;
+ break;
+ case kStageNervous:
+ _barColor = g_system->getScreenFormat().RGBToColor(0xD8, 0x78, 0x38);
+ newFrame = kFrameLightOrange;
+ break;
+ case kStagePanicStricken:
+ _barColor = g_system->getScreenFormat().RGBToColor(0xD8, 0x40, 0x38);
+ newFrame = kFrameLightRed;
+ break;
+ default:
+ error("no stage in energy monitor?");
+ break;
+ }
+
+ _stage = newStage;
+ uint32 oldFrame = _energyLight.getCurrentFrameIndex();
+
+ if (!_calibrating) {
+ if (oldFrame > newFrame || oldFrame == 0xffffffff || _dontFlash) {
+ _energyLight.setCurrentFrameIndex(newFrame);
+ _dontFlash = false;
+ } else {
+ _lightBlinker.startBlinking(&_energyLight, oldFrame, newFrame, 4, 1, 3);
+ triggerRedraw();
+ }
+ }
+ }
+
+ Common::Rect r;
+ calcLevelRect(r);
+ if (r != _levelRect) {
+ _levelRect = r;
+ triggerRedraw();
+ }
+ }
+}
+
+void EnergyMonitor::calcLevelRect(Common::Rect &r) {
+ if (getStop() == 0) {
+ r = Common::Rect();
+ } else {
+ getBounds(r);
+ r.left = r.right - r.width() * (kMaxJMPEnergy - getTime()) / getStop();
+ }
+}
+
+void EnergyMonitor::draw(const Common::Rect &r) {
+ Common::Rect r2 = r.findIntersectingRect(_levelRect);
+
+ if (!r2.isEmpty()) {
+ Graphics::Surface *screen = ((PegasusEngine *)g_engine)->_gfx->getWorkArea();
+ screen->fillRect(r2, _barColor);
+ }
+}
+
+void EnergyMonitor::calibrateEnergyBar() {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ _calibrating = true;
+
+ vm->setEnergyDeathReason(-1);
+
+ uint32 numFrames = _energyLight.getNumFrames();
+ for (uint32 i = 1; i < numFrames; i++) {
+ _energyLight.setCurrentFrameIndex(i);
+ _energyLight.show();
+ vm->delayShell(1, 3);
+ _energyLight.hide();
+ vm->delayShell(1, 3);
+ }
+
+ _energyLight.setCurrentFrameIndex(0);
+ _energyLight.hide();
+
+ show();
+ setEnergyValue(0);
+ setEnergyDrainRate(-(int32)kMaxJMPEnergy / 2);
+
+ // Make sure warning light is hidden...
+ _energyLight.hide();
+ while (getCurrentEnergy() != (int32)kMaxJMPEnergy) {
+ vm->checkCallBacks();
+ vm->refreshDisplay();
+ g_system->delayMillis(10);
+ }
+
+ vm->refreshDisplay();
+ setEnergyDrainRate(0);
+ hide();
+
+ _calibrating = false;
+}
+
+void EnergyMonitor::restoreLastEnergyValue() {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ _dontFlash = true;
+ setEnergyValue(vm->getSavedEnergyValue());
+ vm->resetEnergyDeathReason();
+}
+
+void EnergyMonitor::saveCurrentEnergyValue() {
+ ((PegasusEngine *)g_engine)->setLastEnergyValue(getCurrentEnergy());
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/energymonitor.h b/engines/pegasus/energymonitor.h
new file mode 100644
index 0000000000..02377d515a
--- /dev/null
+++ b/engines/pegasus/energymonitor.h
@@ -0,0 +1,111 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_ENERGYMONITOR_H
+#define PEGASUS_ENERGYMONITOR_H
+
+#include "pegasus/elements.h"
+
+namespace Pegasus {
+
+class Sprite;
+
+class Blinker : private IdlerTimeBase {
+public:
+ Blinker();
+ virtual ~Blinker() {}
+
+ void startBlinking(Sprite *sprite, int32 frame1, int32 frame2, uint32 numBlinks, TimeValue blinkDuration, TimeScale blinkScale);
+ void stopBlinking();
+
+protected:
+ virtual void timeChanged(const TimeValue);
+
+ Sprite *_sprite;
+ int32 _frame1;
+ int32 _frame2;
+ TimeValue _blinkDuration;
+};
+
+// Energy monitor constants.
+
+// These are in seconds.
+// Max is two hours
+static const uint32 kMaxJMPEnergy = 7200;
+
+static const uint32 kCasualEnergy = kMaxJMPEnergy * 100 / 100; // 100%
+static const uint32 kWorriedEnergy = kMaxJMPEnergy * 50 / 100; // 50%
+static const uint32 kNervousEnergy = kMaxJMPEnergy * 25 / 100; // 25%
+static const uint32 kPanicStrickenEnergy = kMaxJMPEnergy * 5 / 100; // 5%
+
+static const uint32 kFullEnergy = kCasualEnergy;
+
+static const uint32 kFrameLightOff = 0;
+static const uint32 kFrameLightYellow = 1;
+static const uint32 kFrameLightOrange = 2;
+static const uint32 kFrameLightRed = 3;
+
+static const int kEnergyDrainNormal = 1;
+static const int kMarsReactorEnergyDrainNoShield = 6;
+static const int kMarsReactorEnergyDrainWithShield = 3;
+static const int kWSCPoisonEnergyDrainWithDart = 20;
+static const int kWSCPoisonEnergyDrainNoDart = 10;
+
+class EnergyMonitor : private IdlerAnimation {
+public:
+ EnergyMonitor();
+ virtual ~EnergyMonitor();
+
+ void setEnergyValue(const uint32);
+ void startEnergyDraining();
+ void setEnergyDrainRate(Common::Rational);
+ Common::Rational getEnergyDrainRate();
+ void stopEnergyDraining();
+ void drainEnergy(const int32);
+ int32 getCurrentEnergy();
+
+ void restoreLastEnergyValue();
+ void saveCurrentEnergyValue();
+
+ void calibrateEnergyBar();
+
+protected:
+ void timeChanged(const TimeValue);
+ void calcLevelRect(Common::Rect &);
+ void draw(const Common::Rect &);
+
+ uint32 _barColor;
+ Common::Rect _levelRect;
+ EnergyStage _stage;
+ Sprite _energyLight;
+ Blinker _lightBlinker;
+ bool _calibrating, _dontFlash;
+};
+
+extern EnergyMonitor *g_energyMonitor;
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/fader.cpp b/engines/pegasus/fader.cpp
new file mode 100644
index 0000000000..a2bbf22944
--- /dev/null
+++ b/engines/pegasus/fader.cpp
@@ -0,0 +1,218 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/fader.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/sound.h"
+#include "pegasus/util.h"
+
+namespace Pegasus {
+
+Fader::Fader() {
+ _currentValue = 0;
+ _currentFaderMove._numKnots = 0;
+}
+
+void Fader::setFaderValue(const int32 newValue) {
+ _currentValue = newValue;
+}
+
+bool Fader::initFaderMove(const FaderMoveSpec &spec) {
+ bool faderMoves = false;
+ int32 value = 0;
+
+ if (spec._numKnots > 0) {
+ stopFader();
+ value = spec._knots[0].knotValue;
+ TimeValue startTime = spec._knots[0].knotTime;
+
+ if (startTime != 0xffffffff) {
+ if (spec._numKnots > 1) {
+ TimeValue stopTime = spec._knots[spec._numKnots - 1].knotTime;
+
+ if (spec._faderScale > 0) {
+ if (stopTime > startTime) {
+ for (uint32 i = 1; i < spec._numKnots; ++i) {
+ if (spec._knots[i - 1].knotValue != spec._knots[i].knotValue) {
+ faderMoves = true;
+ break;
+ }
+ }
+
+ if (faderMoves)
+ _currentFaderMove = spec;
+ } else if (spec._knots[spec._numKnots - 1].knotValue != value) {
+ value = spec._knots[spec._numKnots - 1].knotValue;
+ }
+ }
+ }
+ }
+ }
+
+ setFaderValue(value);
+ return faderMoves;
+}
+
+void Fader::startFader(const FaderMoveSpec &spec) {
+ if (initFaderMove(spec)) {
+ setFlags(0);
+ setScale(spec._faderScale);
+ setSegment(spec._knots[0].knotTime, spec._knots[spec._numKnots - 1].knotTime);
+ setTime(spec._knots[0].knotTime);
+ start();
+ }
+}
+
+void Fader::startFaderSync(const FaderMoveSpec &spec) {
+ if (initFaderMove(spec)) {
+ setFlags(0);
+ setScale(spec._faderScale);
+ setSegment(spec._knots[0].knotTime, spec._knots[spec._numKnots - 1].knotTime);
+ setTime(spec._knots[0].knotTime);
+ start();
+
+ while (isFading()) {
+ ((PegasusEngine *)g_engine)->checkCallBacks();
+ useIdleTime();
+ }
+
+ // Once more, for good measure, to make sure that there are no boundary
+ // condition problems.
+ useIdleTime();
+ stopFader();
+ }
+}
+
+void Fader::loopFader(const FaderMoveSpec &spec) {
+ if (initFaderMove(spec)) {
+ setFlags(kLoopTimeBase);
+ setScale(spec._faderScale);
+ setSegment(spec._knots[0].knotTime, spec._knots[spec._numKnots - 1].knotTime);
+ setTime(spec._knots[0].knotTime);
+ start();
+ }
+}
+
+void Fader::stopFader() {
+ stop();
+}
+
+void Fader::pauseFader() {
+ stopFader();
+}
+
+void Fader::continueFader() {
+ if (getTime() < getStop())
+ start();
+}
+
+void Fader::timeChanged(const TimeValue newTime) {
+ if (_currentFaderMove._numKnots != 0) {
+ uint32 i;
+ for (i = 0; i < _currentFaderMove._numKnots; i++)
+ if (_currentFaderMove._knots[i].knotTime > newTime)
+ break;
+
+ int32 newValue;
+ if (i == 0)
+ newValue = _currentFaderMove._knots[0].knotValue;
+ else if (i == _currentFaderMove._numKnots)
+ newValue = _currentFaderMove._knots[i - 1].knotValue;
+ else
+ newValue = linearInterp(_currentFaderMove._knots[i - 1].knotTime, _currentFaderMove._knots[i].knotTime, newTime, _currentFaderMove._knots[i - 1].knotValue, _currentFaderMove._knots[i].knotValue);
+
+ if (newValue != _currentValue)
+ setFaderValue(newValue);
+ }
+}
+
+void FaderMoveSpec::makeOneKnotFaderSpec(const int32 knotValue) {
+ _numKnots = 1;
+ _knots[0].knotTime = 0;
+ _knots[0].knotValue = knotValue;
+}
+
+void FaderMoveSpec::makeTwoKnotFaderSpec(const TimeScale faderScale, const TimeValue time1, const int32 value1, const TimeValue time2, const int32 value2) {
+ _numKnots = 2;
+ _faderScale = faderScale;
+ _knots[0].knotTime = time1;
+ _knots[0].knotValue = value1;
+ _knots[1].knotTime = time2;
+ _knots[1].knotValue = value2;
+}
+
+void FaderMoveSpec::insertFaderKnot(const TimeValue knotTime, const int32 knotValue) {
+ if (_numKnots != kMaxFaderKnots) {
+ uint32 index;
+ for (index = 0; index < _numKnots; index++) {
+ if (knotTime == _knots[index].knotTime) {
+ _knots[index].knotValue = knotValue;
+ return;
+ } else if (knotTime < _knots[index].knotTime) {
+ break;
+ }
+ }
+
+ for (uint32 i = _numKnots; i > index; i--)
+ _knots[i] = _knots[i - 1];
+
+ _knots[index].knotTime = knotTime;
+ _knots[index].knotValue = knotValue;
+ _numKnots++;
+ }
+}
+
+void FaderAnimation::setFaderValue(const int32 newValue) {
+ if (getFaderValue() != newValue) {
+ Fader::setFaderValue(newValue);
+ triggerRedraw();
+ }
+}
+
+SoundFader::SoundFader() {
+ _sound = 0;
+ _masterVolume = 0xff;
+}
+
+void SoundFader::attachSound(Sound *sound) {
+ if (!sound && isFading())
+ stopFader();
+
+ _sound = sound;
+}
+
+void SoundFader::setFaderValue(const int32 newVolume) {
+ if (_sound)
+ _sound->setVolume((newVolume * _masterVolume) >> 8);
+
+ _currentValue = newVolume;
+}
+
+void SoundFader::setMasterVolume(const uint16 masterVolume) {
+ _masterVolume = masterVolume;
+ setFaderValue(getFaderValue());
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/fader.h b/engines/pegasus/fader.h
new file mode 100644
index 0000000000..0a8cd549e6
--- /dev/null
+++ b/engines/pegasus/fader.h
@@ -0,0 +1,130 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_FADER_H
+#define PEGASUS_FADER_H
+
+#include "pegasus/elements.h"
+#include "pegasus/timers.h"
+
+namespace Pegasus {
+
+class Fader;
+
+class FaderMoveSpec {
+friend class Fader;
+public:
+ FaderMoveSpec() {
+ _faderScale = kDefaultTimeScale;
+ _numKnots = 0;
+ }
+
+ FaderMoveSpec(const TimeScale scale) {
+ _faderScale = scale;
+ _numKnots = 0;
+ }
+
+ void setFaderScale(const TimeScale scale) { _faderScale = scale; }
+ TimeScale getFaderScale() const { return _faderScale; }
+
+ void makeOneKnotFaderSpec(const int32);
+ void makeTwoKnotFaderSpec(const TimeScale, const TimeValue, const int32, const TimeValue, const int32);
+
+ void insertFaderKnot(const TimeValue, const int32);
+
+ uint32 getNumKnots() const { return _numKnots; }
+ TimeValue getNthKnotTime(const uint32 index) const { return _knots[index].knotTime; }
+ int32 getNthKnotValue(const uint32 index) const { return _knots[index].knotValue; }
+
+protected:
+ struct FaderKnot {
+ TimeValue knotTime;
+ int32 knotValue;
+ };
+
+ TimeScale _faderScale;
+ uint32 _numKnots;
+
+ static const uint32 kMaxFaderKnots = 20;
+ FaderKnot _knots[kMaxFaderKnots];
+};
+
+class Fader : public IdlerTimeBase {
+public:
+ Fader();
+ virtual ~Fader() {}
+
+ virtual void setFaderValue(const int32);
+ int32 getFaderValue() const { return _currentValue; }
+ virtual void startFader(const FaderMoveSpec &);
+ virtual void startFaderSync(const FaderMoveSpec &);
+ virtual void loopFader(const FaderMoveSpec &);
+ virtual void stopFader();
+ virtual bool isFading() { return isRunning(); }
+
+ void pauseFader();
+ void continueFader();
+
+ void getCurrentFaderMove(FaderMoveSpec &spec) { spec = _currentFaderMove; }
+
+protected:
+ bool initFaderMove(const FaderMoveSpec &);
+ virtual void timeChanged(const TimeValue);
+
+ int32 _currentValue;
+ FaderMoveSpec _currentFaderMove;
+};
+
+class FaderAnimation : public DisplayElement, public Fader {
+public:
+ FaderAnimation(const DisplayElementID id) : DisplayElement(id) {}
+ virtual ~FaderAnimation() {}
+
+ void setFaderValue(const int32);
+};
+
+class Sound;
+
+class SoundFader : public Fader {
+friend class Sound;
+public:
+ SoundFader();
+ virtual ~SoundFader() {}
+
+ void setFaderValue(const int32);
+
+ void setMasterVolume(const uint16);
+ uint16 getMasterVolume() const { return _masterVolume; }
+
+protected:
+ void attachSound(Sound *);
+
+ Sound *_sound;
+ uint16 _masterVolume;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/gamestate.cpp b/engines/pegasus/gamestate.cpp
new file mode 100644
index 0000000000..7a4e657e02
--- /dev/null
+++ b/engines/pegasus/gamestate.cpp
@@ -0,0 +1,2359 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/error.h"
+#include "common/stream.h"
+
+#include "pegasus/constants.h"
+#include "pegasus/gamestate.h"
+#include "pegasus/scoring.h"
+
+namespace Common {
+DECLARE_SINGLETON(Pegasus::GameStateManager);
+}
+
+namespace Pegasus {
+
+Common::Error GameStateManager::writeGameState(Common::WriteStream *stream) {
+ stream->writeUint16BE(_currentNeighborhood);
+ stream->writeUint16BE(_currentRoom);
+ stream->writeByte(_currentDirection);
+ stream->writeUint16BE(_nexNeighborhoodID);
+ stream->writeUint16BE(_nextRoomID);
+ stream->writeByte(_nextDirection);
+ stream->writeUint16BE(_lastNeighborhood);
+ stream->writeUint16BE(_lastRoom);
+ stream->writeByte(_lastDirection);
+ stream->writeUint16BE(_openDoorRoom);
+ stream->writeByte(_openDoorDirection);
+
+ _globalFlags.writeToStream(stream);
+ _scoringFlags.writeToStream(stream);
+ _itemTakenFlags.writeToStream(stream);
+
+ writeCaldoriaState(stream);
+ writeTSAState(stream);
+ writePrehistoricState(stream);
+ writeNoradState(stream);
+ writeMarsState(stream);
+ writeWSCState(stream);
+
+ if (stream->err())
+ return Common::kWritingFailed;
+
+ return Common::kNoError;
+}
+
+Common::Error GameStateManager::readGameState(Common::ReadStream *stream) {
+ _currentNeighborhood = stream->readUint16BE();
+ _currentRoom = stream->readUint16BE();
+ _currentDirection = stream->readByte();
+ _nexNeighborhoodID = stream->readUint16BE();
+ _nextRoomID = stream->readUint16BE();
+ _nextDirection = stream->readByte();
+ _lastNeighborhood = stream->readUint16BE();
+ _lastRoom = stream->readUint16BE();
+ _lastDirection = stream->readByte();
+ _openDoorRoom = stream->readUint16BE();
+ _openDoorDirection = stream->readByte();
+
+ _globalFlags.readFromStream(stream);
+ _scoringFlags.readFromStream(stream);
+ _itemTakenFlags.readFromStream(stream);
+
+ readCaldoriaState(stream);
+ readTSAState(stream);
+ readPrehistoricState(stream);
+ readNoradState(stream);
+ readMarsState(stream);
+ readWSCState(stream);
+
+ if (stream->err())
+ return Common::kReadingFailed;
+
+ return Common::kNoError;
+}
+
+void GameStateManager::resetGameState() {
+ _currentNeighborhood = kNoNeighborhoodID;
+ _currentRoom = kNoRoomID;
+ _currentDirection = kNoDirection;
+ _nexNeighborhoodID = kNoNeighborhoodID;
+ _nextRoomID = kNoRoomID;
+ _nextDirection = kNoDirection;
+ _lastNeighborhood = kNoNeighborhoodID;
+ _lastRoom = kNoRoomID;
+ _lastDirection = kNoDirection;
+ _openDoorRoom = kNoRoomID;
+ _openDoorDirection = kNoDirection;
+
+ _globalFlags.clearAllFlags();
+ _scoringFlags.clearAllFlags();
+ _itemTakenFlags.clearAllFlags();
+
+ resetCaldoriaState();
+ resetTSAState();
+ resetPrehistoricState();
+ resetNoradState();
+ resetMarsState();
+ resetWSCState();
+}
+
+void GameStateManager::getCurrentLocation(NeighborhoodID &neighborhood, RoomID &room, DirectionConstant &direction) {
+ neighborhood = _currentNeighborhood;
+ room = _currentRoom;
+ direction = _currentDirection;
+}
+
+void GameStateManager::setCurrentLocation(const NeighborhoodID neighborhood, const RoomID room, const DirectionConstant direction) {
+ _lastNeighborhood = _currentNeighborhood;
+ _lastRoom = _currentRoom;
+ _lastDirection = _currentDirection;
+ _currentNeighborhood = neighborhood;
+ _currentRoom = room;
+ _currentDirection = direction;
+}
+
+NeighborhoodID GameStateManager::getCurrentNeighborhood() {
+ return _currentNeighborhood;
+}
+
+void GameStateManager::setCurrentNeighborhood(const NeighborhoodID neighborhood) {
+ _lastNeighborhood = _currentNeighborhood;
+ _currentNeighborhood = neighborhood;
+}
+
+RoomID GameStateManager::getCurrentRoom() {
+ return _currentRoom;
+}
+
+void GameStateManager::setCurrentRoom(const RoomID room) {
+ _lastRoom = _currentRoom;
+ _currentRoom = room;
+}
+
+DirectionConstant GameStateManager::getCurrentDirection() {
+ return _currentDirection;
+}
+
+void GameStateManager::setCurrentDirection(const DirectionConstant direction) {
+ _lastDirection = _currentDirection;
+ _currentDirection = direction;
+}
+
+RoomViewID GameStateManager::getCurrentRoomAndView() {
+ return MakeRoomView(_currentRoom, _currentDirection);
+}
+
+void GameStateManager::getNextLocation(NeighborhoodID &neighborhood, RoomID &room, DirectionConstant &direction) {
+ neighborhood = _nexNeighborhoodID;
+ room = _nextRoomID;
+ direction = _nextDirection;
+}
+
+void GameStateManager::setNextLocation(const NeighborhoodID neighborhood, const RoomID room, const DirectionConstant direction) {
+ _nexNeighborhoodID = neighborhood;
+ _nextRoomID = room;
+ _nextDirection = direction;
+}
+
+NeighborhoodID GameStateManager::getNextNeighborhood() {
+ return _nexNeighborhoodID;
+}
+
+void GameStateManager::setNextNeighborhood(const NeighborhoodID neighborhood) {
+ _nexNeighborhoodID = neighborhood;
+}
+
+RoomID GameStateManager::getNextRoom() {
+ return _nextRoomID;
+}
+
+void GameStateManager::setNextRoom(const RoomID room) {
+ _nextRoomID = room;
+}
+
+DirectionConstant GameStateManager::getNextDirection() {
+ return _nextDirection;
+}
+
+void GameStateManager::setNextDirection(const DirectionConstant direction) {
+ _nextDirection = direction;
+}
+
+void GameStateManager::getLastLocation(NeighborhoodID &neighborhood, RoomID &room, DirectionConstant &direction) {
+ neighborhood = _currentNeighborhood;
+ room = _currentRoom;
+ direction = _currentDirection;
+}
+
+void GameStateManager::setLastLocation(const NeighborhoodID neighborhood, const RoomID room, const DirectionConstant direction) {
+ _currentNeighborhood = neighborhood;
+ _currentRoom = room;
+ _currentDirection = direction;
+}
+
+NeighborhoodID GameStateManager::getLastNeighborhood() {
+ return _lastNeighborhood;
+}
+
+void GameStateManager::setLastNeighborhood(const NeighborhoodID neighborhood) {
+ _lastNeighborhood = neighborhood;
+}
+
+RoomID GameStateManager::getLastRoom() {
+ return _lastRoom;
+}
+
+void GameStateManager::setLastRoom(const RoomID room) {
+ _lastRoom = room;
+}
+
+DirectionConstant GameStateManager::getLastDirection() {
+ return _lastDirection;
+}
+
+void GameStateManager::setLastDirection(const DirectionConstant direction) {
+ _lastDirection = direction;
+}
+
+RoomViewID GameStateManager::getLastRoomAndView() {
+ return MakeRoomView(_lastRoom, _lastDirection);
+}
+
+void GameStateManager::getOpenDoorLocation(RoomID &room, DirectionConstant &direction) {
+ room = _openDoorRoom;
+ direction = _openDoorDirection;
+}
+
+void GameStateManager::setOpenDoorLocation(const RoomID room, const DirectionConstant direction) {
+ _openDoorRoom = room;
+ _openDoorDirection = direction;
+}
+
+RoomID GameStateManager::getOpenDoorRoom() {
+ return _openDoorRoom;
+}
+
+void GameStateManager::setOpenDoorRoom(const RoomID room) {
+ _openDoorRoom = room;
+}
+
+DirectionConstant GameStateManager::getOpenDoorDirection() {
+ return _openDoorDirection;
+}
+
+void GameStateManager::setOpenDoorDirection(const DirectionConstant direction) {
+ _openDoorDirection = direction;
+}
+
+RoomViewID GameStateManager::getDoorOpenRoomAndView() {
+ return MakeRoomView(_openDoorRoom, _openDoorDirection);
+}
+
+bool GameStateManager::isCurrentDoorOpen() {
+ return _openDoorRoom == _currentRoom && _openDoorDirection == _currentDirection;
+}
+
+GameScoreType GameStateManager::getCaldoriaTSAScore() {
+ GameScoreType result = 0;
+
+ if (_scoringFlags.getFlag(kScoringSawINNFlag))
+ result += kSawINNScore;
+ if (_scoringFlags.getFlag(kScoringTookShowerFlag))
+ result += kTookShowerScore;
+ if (_scoringFlags.getFlag(kScoringFixedHairFlag))
+ result += kFixedHairScore;
+ if (_scoringFlags.getFlag(kScoringGotKeyCardFlag))
+ result += kGotKeyCardScore;
+ if (_scoringFlags.getFlag(kScoringReadPaperFlag))
+ result += kReadPaperScore;
+ if (_scoringFlags.getFlag(kScoringLookThroughTelescopeFlag))
+ result += kLookThroughTelescopeScore;
+ if (_scoringFlags.getFlag(kScoringSawCaldoriaKioskFlag))
+ result += kSawCaldoriaKioskScore;
+ if (_scoringFlags.getFlag(kScoringGoToTSAFlag))
+ result += kGoToTSAScore;
+ if (_scoringFlags.getFlag(kScoringEnterTSAFlag))
+ result += kEnterTSAScore;
+ if (_scoringFlags.getFlag(kScoringSawBust1Flag))
+ result += kSawBust1Score;
+ if (_scoringFlags.getFlag(kScoringSawBust2Flag))
+ result += kSawBust2Score;
+ if (_scoringFlags.getFlag(kScoringSawBust3Flag))
+ result += kSawBust3Score;
+ if (_scoringFlags.getFlag(kScoringSawBust4Flag))
+ result += kSawBust4Score;
+ if (_scoringFlags.getFlag(kScoringSawBust5Flag))
+ result += kSawBust5Score;
+ if (_scoringFlags.getFlag(kScoringSawBust6Flag))
+ result += kSawBust6Score;
+ if (_scoringFlags.getFlag(kScoringSawTheoryFlag))
+ result += kSawTheoryScore;
+ if (_scoringFlags.getFlag(kScoringSawBackgroundFlag))
+ result += kSawBackgroundScore;
+ if (_scoringFlags.getFlag(kScoringSawProcedureFlag))
+ result += kSawProcedureScore;
+ if (_scoringFlags.getFlag(kScoringGotJourneymanKeyFlag))
+ result += kGotJourneymanKeyScore;
+ if (_scoringFlags.getFlag(kScoringGotPegasusBiochipFlag))
+ result += kGotPegasusBiochipScore;
+ if (_scoringFlags.getFlag(kScoringGotBiosuitFlag))
+ result += kGotBiosuitScore;
+ if (_scoringFlags.getFlag(kScoringGoToPrehistoricFlag))
+ result += kGoToPrehistoricScore;
+ if (_scoringFlags.getFlag(kScoringPutLogInReaderFlag))
+ result += kPutLogInReaderScore;
+ if (_scoringFlags.getFlag(kScoringSawCaldoriaNormalFlag))
+ result += kSawCaldoriaNormalScore;
+ if (_scoringFlags.getFlag(kScoringSawCaldoriaAlteredFlag))
+ result += kSawCaldoriaAlteredScore;
+ if (_scoringFlags.getFlag(kScoringSawNoradNormalFlag))
+ result += kSawNoradNormalScore;
+ if (_scoringFlags.getFlag(kScoringSawNoradAlteredFlag))
+ result += kSawNoradAlteredScore;
+ if (_scoringFlags.getFlag(kScoringSawMarsNormalFlag))
+ result += kSawMarsNormalScore;
+ if (_scoringFlags.getFlag(kScoringSawMarsAlteredFlag))
+ result += kSawMarsAlteredScore;
+ if (_scoringFlags.getFlag(kScoringSawWSCNormalFlag))
+ result += kSawWSCNormalScore;
+ if (_scoringFlags.getFlag(kScoringSawWSCAlteredFlag))
+ result += kSawWSCAlteredScore;
+ if (_scoringFlags.getFlag(kScoringWentToReadyRoom2Flag))
+ result += kWentToReadyRoom2Score;
+ if (_scoringFlags.getFlag(kScoringWentAfterSinclairFlag))
+ result += kWentAfterSinclairScore;
+ if (_scoringFlags.getFlag(kScoringUsedCardBombFlag))
+ result += kUsedCardBombScore;
+ if (_scoringFlags.getFlag(kScoringShieldedCardBombFlag))
+ result += kShieldedCardBombScore;
+ if (_scoringFlags.getFlag(kScoringStunnedSinclairFlag))
+ result += kStunnedSinclairScore;
+ if (_scoringFlags.getFlag(kScoringDisarmedNukeFlag))
+ result += kDisarmedNukeScore;
+
+ return result;
+}
+
+GameScoreType GameStateManager::getPrehistoricScore() {
+ GameScoreType result = 0;
+
+ if (_scoringFlags.getFlag(kScoringThrewBreakerFlag))
+ result += kThrewBreakerScore;
+ if (_scoringFlags.getFlag(kScoringExtendedBridgeFlag))
+ result += kExtendedBridgeScore;
+ if (_scoringFlags.getFlag(kScoringGotHistoricalLogFlag))
+ result += kGotHistoricalLogScore;
+ if (_scoringFlags.getFlag(kScoringFinishedPrehistoricFlag))
+ result += kFinishedPrehistoricScore;
+
+ return result;
+}
+
+GameScoreType GameStateManager::getMarsScore() {
+ GameScoreType result = 0;
+
+ if (_scoringFlags.getFlag(kScoringThrownByRobotFlag))
+ result += kThrownByRobotScore;
+ if (_scoringFlags.getFlag(kScoringGotMarsCardFlag))
+ result += kGotMarsCardScore;
+ if (_scoringFlags.getFlag(kScoringSawMarsKioskFlag))
+ result += kSawMarsKioskScore;
+ if (_scoringFlags.getFlag(kScoringSawTransportMapFlag))
+ result += kSawTransportMapScore;
+ if (_scoringFlags.getFlag(kScoringGotCrowBarFlag))
+ result += kGotCrowBarScore;
+ if (_scoringFlags.getFlag(kScoringTurnedOnTransportFlag))
+ result += kTurnedOnTransportScore;
+ if (_scoringFlags.getFlag(kScoringGotOxygenMaskFlag))
+ result += kGotOxygenMaskScore;
+ if (_scoringFlags.getFlag(kScoringAvoidedRobotFlag))
+ result += kAvoidedRobotScore;
+ if (_scoringFlags.getFlag(kScoringActivatedPlatformFlag))
+ result += kActivatedPlatformScore;
+ if (_scoringFlags.getFlag(kScoringUsedLiquidNitrogenFlag))
+ result += kUsedLiquidNitrogenScore;
+ if (_scoringFlags.getFlag(kScoringUsedCrowBarFlag))
+ result += kUsedCrowBarScore;
+ if (_scoringFlags.getFlag(kScoringFoundCardBombFlag))
+ result += kFoundCardBombScore;
+ if (_scoringFlags.getFlag(kScoringDisarmedCardBombFlag))
+ result += kDisarmedCardBombScore;
+ if (_scoringFlags.getFlag(kScoringGotCardBombFlag))
+ result += kGotCardBombScore;
+ if (_scoringFlags.getFlag(kScoringThreadedMazeFlag))
+ result += kThreadedMazeScore;
+ if (_scoringFlags.getFlag(kScoringThreadedGearRoomFlag))
+ result += kThreadedGearRoomScore;
+ if (_scoringFlags.getFlag(kScoringEnteredShuttleFlag))
+ result += kEnteredShuttleScore;
+ if (_scoringFlags.getFlag(kScoringEnteredLaunchTubeFlag))
+ result += kEnteredLaunchTubeScore;
+ if (_scoringFlags.getFlag(kScoringStoppedRobotsShuttleFlag))
+ result += kStoppedRobotsShuttleScore;
+ if (_scoringFlags.getFlag(kScoringGotMarsOpMemChipFlag))
+ result += kGotMarsOpMemChipScore;
+ if (_scoringFlags.getFlag(kScoringFinishedMarsFlag))
+ result += kFinishedMarsScore;
+
+ return result;
+}
+
+GameScoreType GameStateManager::getNoradScore() {
+ GameScoreType result = 0;
+
+ if (_scoringFlags.getFlag(kScoringSawSecurityMonitorFlag))
+ result += kSawSecurityMonitorScore;
+ if (_scoringFlags.getFlag(kScoringFilledOxygenCanisterFlag))
+ result += kFilledOxygenCanisterScore;
+ if (_scoringFlags.getFlag(kScoringFilledArgonCanisterFlag))
+ result += kFilledArgonCanisterScore;
+ if (_scoringFlags.getFlag(kScoringSawUnconsciousOperatorFlag))
+ result += kSawUnconsciousOperatorScore;
+ if (_scoringFlags.getFlag(kScoringWentThroughPressureDoorFlag))
+ result += kWentThroughPressureDoorScore;
+ if (_scoringFlags.getFlag(kScoringPreppedSubFlag))
+ result += kPreppedSubScore;
+ if (_scoringFlags.getFlag(kScoringEnteredSubFlag))
+ result += kEnteredSubScore;
+ if (_scoringFlags.getFlag(kScoringExitedSubFlag))
+ result += kExitedSubScore;
+ if (_scoringFlags.getFlag(kScoringSawRobotAt54NorthFlag))
+ result += kSawRobotAt54NorthScore;
+ if (_scoringFlags.getFlag(kScoringPlayedWithClawFlag))
+ result += kPlayedWithClawScore;
+ if (_scoringFlags.getFlag(kScoringUsedRetinalChipFlag))
+ result += kUsedRetinalChipScore;
+ if (_scoringFlags.getFlag(kScoringFinishedGlobeGameFlag))
+ result += kFinishedGlobeGameScore;
+ if (_scoringFlags.getFlag(kScoringStoppedNoradRobotFlag))
+ result += kStoppedNoradRobotScore;
+ if (_scoringFlags.getFlag(kScoringGotNoradOpMemChipFlag))
+ result += kGotNoradOpMemChipScore;
+ if (_scoringFlags.getFlag(kScoringFinishedNoradFlag))
+ result += kFinishedNoradScore;
+
+ return result;
+}
+
+GameScoreType GameStateManager::getWSCScore() {
+ GameScoreType result = 0;
+
+ if (_scoringFlags.getFlag(kScoringRemovedDartFlag))
+ result += kRemovedDartScore;
+ if (_scoringFlags.getFlag(kScoringAnalyzedDartFlag))
+ result += kAnalyzedDartScore;
+ if (_scoringFlags.getFlag(kScoringBuiltAntidoteFlag))
+ result += kBuiltAntidoteScore;
+ if (_scoringFlags.getFlag(kScoringGotSinclairKeyFlag))
+ result += kGotSinclairKeyScore;
+ if (_scoringFlags.getFlag(kScoringGotArgonCanisterFlag))
+ result += kGotArgonCanisterScore;
+ if (_scoringFlags.getFlag(kScoringGotNitrogenCanisterFlag))
+ result += kGotNitrogenCanisterScore;
+ if (_scoringFlags.getFlag(kScoringPlayedWithMessagesFlag))
+ result += kPlayedWithMessagesScore;
+ if (_scoringFlags.getFlag(kScoringSawMorphExperimentFlag))
+ result += kSawMorphExperimentScore;
+ if (_scoringFlags.getFlag(kScoringEnteredSinclairOfficeFlag))
+ result += kEnteredSinclairOfficeScore;
+ if (_scoringFlags.getFlag(kScoringSawBrochureFlag))
+ result += kSawBrochureScore;
+ if (_scoringFlags.getFlag(kScoringSawSinclairEntry1Flag))
+ result += kSawSinclairEntry1Score;
+ if (_scoringFlags.getFlag(kScoringSawSinclairEntry2Flag))
+ result += kSawSinclairEntry2Score;
+ if (_scoringFlags.getFlag(kScoringSawSinclairEntry3Flag))
+ result += kSawSinclairEntry3Score;
+ if (_scoringFlags.getFlag(kScoringSawWSCDirectoryFlag))
+ result += kSawWSCDirectoryScore;
+ if (_scoringFlags.getFlag(kScoringUsedCrowBarInWSCFlag))
+ result += kUsedCrowBarInWSCScore;
+ if (_scoringFlags.getFlag(kScoringFinishedPlasmaDodgeFlag))
+ result += kFinishedPlasmaDodgeScore;
+ if (_scoringFlags.getFlag(kScoringOpenedCatwalkFlag))
+ result += kOpenedCatwalkScore;
+ if (_scoringFlags.getFlag(kScoringStoppedWSCRobotFlag))
+ result += kStoppedWSCRobotScore;
+ if (_scoringFlags.getFlag(kScoringGotWSCOpMemChipFlag))
+ result += kGotWSCOpMemChipScore;
+ if (_scoringFlags.getFlag(kScoringFinishedWSCFlag))
+ result += kFinishedWSCScore;
+
+ return result;
+}
+
+GameScoreType GameStateManager::getGandhiScore() {
+ GameScoreType result = 0;
+
+ if (_scoringFlags.getFlag(kScoringMarsGandhiFlag))
+ result += kMarsGandhiScore;
+ if (_scoringFlags.getFlag(kScoringNoradGandhiFlag))
+ result += kNoradGandhiScore;
+ if (_scoringFlags.getFlag(kScoringWSCGandhiFlag))
+ result += kWSCGandhiScore;
+
+ return result;
+}
+
+GameScoreType GameStateManager::getTotalScore() {
+ return getCaldoriaTSAScore() +
+ getPrehistoricScore() +
+ getMarsScore() +
+ getNoradScore() +
+ getWSCScore() +
+ getGandhiScore();
+}
+
+/////////////////////////////////////////////
+//
+// Caldoria data
+
+void GameStateManager::writeCaldoriaState(Common::WriteStream *stream) {
+ _caldoriaFlags.writeToStream(stream);
+ stream->writeUint32BE(_caldoriaFuseTimeLimit);
+}
+
+void GameStateManager::readCaldoriaState(Common::ReadStream *stream) {
+ _caldoriaFlags.readFromStream(stream);
+ _caldoriaFuseTimeLimit = stream->readUint32BE();
+}
+
+void GameStateManager::resetCaldoriaState() {
+ _caldoriaFlags.clearAllFlags();
+ _caldoriaFuseTimeLimit = 0;
+}
+
+/////////////////////////////////////////////
+//
+// TSA data
+
+void GameStateManager::writeTSAState(Common::WriteStream *stream) {
+ _TSAFlags.writeToStream(stream);
+ stream->writeUint32BE(_TSARipTimerTime);
+ stream->writeUint32BE(_TSAFuseTimeLimit);
+ stream->writeByte(_TSAState);
+ stream->writeByte(_T0BMonitorMode);
+ stream->writeUint32BE(_T0BMonitorStart);
+}
+
+void GameStateManager::readTSAState(Common::ReadStream *stream) {
+ _TSAFlags.readFromStream(stream);
+ _TSARipTimerTime = stream->readUint32BE();
+ _TSAFuseTimeLimit = stream->readUint32BE();
+ _TSAState = stream->readByte();
+ _T0BMonitorMode = stream->readByte();
+ _T0BMonitorStart = stream->readUint32BE();
+}
+
+void GameStateManager::resetTSAState() {
+ _TSAFlags.clearAllFlags();
+ _TSAState = 0;
+ _T0BMonitorMode = 0;
+ _T0BMonitorStart = 0;
+ _TSARipTimerTime = 0;
+ _TSAFuseTimeLimit = kTSAUncreatedTimeLimit;
+}
+
+/////////////////////////////////////////////
+//
+// Prehistoric data
+
+void GameStateManager::writePrehistoricState(Common::WriteStream *stream) {
+ _prehistoricFlags.writeToStream(stream);
+}
+
+void GameStateManager::readPrehistoricState(Common::ReadStream *stream) {
+ _prehistoricFlags.readFromStream(stream);
+}
+
+void GameStateManager::resetPrehistoricState() {
+ _prehistoricFlags.clearAllFlags();
+}
+
+/////////////////////////////////////////////
+//
+// Norad data
+
+void GameStateManager::writeNoradState(Common::WriteStream *stream) {
+ _noradFlags.writeToStream(stream);
+ stream->writeUint16BE(_noradSubRoomPressure);
+ stream->writeByte(_noradSubPrepState);
+}
+
+void GameStateManager::readNoradState(Common::ReadStream *stream) {
+ _noradFlags.readFromStream(stream);
+ _noradSubRoomPressure = stream->readUint16BE();
+ _noradSubPrepState = (NoradSubPrepState)stream->readByte();
+}
+
+void GameStateManager::resetNoradState() {
+ _noradFlags.clearAllFlags();
+ _noradSubRoomPressure = 9;
+ _noradSubPrepState = kSubNotPrepped;
+}
+
+/////////////////////////////////////////////
+//
+// Mars data
+
+void GameStateManager::writeMarsState(Common::WriteStream *stream) {
+ _marsFlags.writeToStream(stream);
+}
+
+void GameStateManager::readMarsState(Common::ReadStream *stream) {
+ _marsFlags.readFromStream(stream);
+}
+
+void GameStateManager::resetMarsState() {
+ _marsFlags.clearAllFlags();
+}
+
+/////////////////////////////////////////////
+//
+// WSC data
+
+void GameStateManager::writeWSCState(Common::WriteStream *stream) {
+ _WSCFlags.writeToStream(stream);
+}
+
+void GameStateManager::readWSCState(Common::ReadStream *stream) {
+ _WSCFlags.readFromStream(stream);
+}
+
+void GameStateManager::resetWSCState() {
+ _WSCFlags.clearAllFlags();
+}
+
+void GameStateManager::setScoringSawINN(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawINNFlag, flag);
+}
+
+void GameStateManager::setScoringTookShower(const bool flag) {
+ _scoringFlags.setFlag(kScoringTookShowerFlag, flag);
+}
+
+void GameStateManager::setScoringFixedHair(const bool flag) {
+ _scoringFlags.setFlag(kScoringFixedHairFlag, flag);
+}
+
+void GameStateManager::setScoringGotKeyCard(const bool flag) {
+ _scoringFlags.setFlag(kScoringGotKeyCardFlag, flag);
+}
+
+void GameStateManager::setScoringReadPaper(const bool flag) {
+ _scoringFlags.setFlag(kScoringReadPaperFlag, flag);
+}
+
+void GameStateManager::setScoringLookThroughTelescope(const bool flag) {
+ _scoringFlags.setFlag(kScoringLookThroughTelescopeFlag, flag);
+}
+
+void GameStateManager::setScoringSawCaldoriaKiosk(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawCaldoriaKioskFlag, flag);
+}
+
+void GameStateManager::setScoringGoToTSA(const bool flag) {
+ _scoringFlags.setFlag(kScoringGoToTSAFlag, flag);
+}
+
+void GameStateManager::setScoringEnterTSA(const bool flag) {
+ _scoringFlags.setFlag(kScoringEnterTSAFlag, flag);
+}
+
+void GameStateManager::setScoringSawBust1(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawBust1Flag, flag);
+}
+
+void GameStateManager::setScoringSawBust2(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawBust2Flag, flag);
+}
+
+void GameStateManager::setScoringSawBust3(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawBust3Flag, flag);
+}
+
+void GameStateManager::setScoringSawBust4(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawBust4Flag, flag);
+}
+
+void GameStateManager::setScoringSawBust5(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawBust5Flag, flag);
+}
+
+void GameStateManager::setScoringSawBust6(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawBust6Flag, flag);
+}
+
+void GameStateManager::setScoringSawTheory(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawTheoryFlag, flag);
+}
+
+void GameStateManager::setScoringSawBackground(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawBackgroundFlag, flag);
+}
+
+void GameStateManager::setScoringSawProcedure(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawProcedureFlag, flag);
+}
+
+void GameStateManager::setScoringGotJourneymanKey(const bool flag) {
+ _scoringFlags.setFlag(kScoringGotJourneymanKeyFlag, flag);
+}
+
+void GameStateManager::setScoringGotPegasusBiochip(const bool flag) {
+ _scoringFlags.setFlag(kScoringGotPegasusBiochipFlag, flag);
+}
+
+void GameStateManager::setScoringGotBiosuit(const bool flag) {
+ _scoringFlags.setFlag(kScoringGotBiosuitFlag, flag);
+}
+
+void GameStateManager::setScoringGoToPrehistoric(const bool flag) {
+ _scoringFlags.setFlag(kScoringGoToPrehistoricFlag, flag);
+}
+
+void GameStateManager::setScoringPutLogInReader(const bool flag) {
+ _scoringFlags.setFlag(kScoringPutLogInReaderFlag, flag);
+}
+
+void GameStateManager::setScoringSawCaldoriaNormal(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawCaldoriaNormalFlag, flag);
+}
+
+void GameStateManager::setScoringSawCaldoriaAltered(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawCaldoriaAlteredFlag, flag);
+}
+
+void GameStateManager::setScoringSawNoradNormal(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawNoradNormalFlag, flag);
+}
+
+void GameStateManager::setScoringSawNoradAltered(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawNoradAlteredFlag, flag);
+}
+
+void GameStateManager::setScoringSawMarsNormal(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawMarsNormalFlag, flag);
+}
+
+void GameStateManager::setScoringSawMarsAltered(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawMarsAlteredFlag, flag);
+}
+
+void GameStateManager::setScoringSawWSCNormal(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawWSCNormalFlag, flag);
+}
+
+void GameStateManager::setScoringSawWSCAltered(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawWSCAlteredFlag, flag);
+}
+
+void GameStateManager::setScoringWentToReadyRoom2(const bool flag) {
+ _scoringFlags.setFlag(kScoringWentToReadyRoom2Flag, flag);
+}
+
+void GameStateManager::setScoringWentAfterSinclair(const bool flag) {
+ _scoringFlags.setFlag(kScoringWentAfterSinclairFlag, flag);
+}
+
+void GameStateManager::setScoringUsedCardBomb(const bool flag) {
+ _scoringFlags.setFlag(kScoringUsedCardBombFlag, flag);
+}
+
+void GameStateManager::setScoringShieldedCardBomb(const bool flag) {
+ _scoringFlags.setFlag(kScoringShieldedCardBombFlag, flag);
+}
+
+void GameStateManager::setScoringStunnedSinclair(const bool flag) {
+ _scoringFlags.setFlag(kScoringStunnedSinclairFlag, flag);
+}
+
+void GameStateManager::setScoringDisarmedNuke(const bool flag) {
+ _scoringFlags.setFlag(kScoringDisarmedNukeFlag, flag);
+}
+
+void GameStateManager::setScoringThrewBreaker(const bool flag) {
+ _scoringFlags.setFlag(kScoringThrewBreakerFlag, flag);
+}
+
+void GameStateManager::setScoringExtendedBridge(const bool flag) {
+ _scoringFlags.setFlag(kScoringExtendedBridgeFlag, flag);
+}
+
+void GameStateManager::setScoringGotHistoricalLog(const bool flag) {
+ _scoringFlags.setFlag(kScoringGotHistoricalLogFlag, flag);
+}
+
+void GameStateManager::setScoringFinishedPrehistoric(const bool flag) {
+ _scoringFlags.setFlag(kScoringFinishedPrehistoricFlag, flag);
+}
+
+void GameStateManager::setScoringThrownByRobot(const bool flag) {
+ _scoringFlags.setFlag(kScoringThrownByRobotFlag, flag);
+}
+
+void GameStateManager::setScoringGotMarsCard(const bool flag) {
+ _scoringFlags.setFlag(kScoringGotMarsCardFlag, flag);
+}
+
+void GameStateManager::setScoringSawMarsKiosk(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawMarsKioskFlag, flag);
+}
+
+void GameStateManager::setScoringSawTransportMap(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawTransportMapFlag, flag);
+}
+
+void GameStateManager::setScoringGotCrowBar(const bool flag) {
+ _scoringFlags.setFlag(kScoringGotCrowBarFlag, flag);
+}
+
+void GameStateManager::setScoringTurnedOnTransport(const bool flag) {
+ _scoringFlags.setFlag(kScoringTurnedOnTransportFlag, flag);
+}
+
+void GameStateManager::setScoringGotOxygenMask(const bool flag) {
+ _scoringFlags.setFlag(kScoringGotOxygenMaskFlag, flag);
+}
+
+void GameStateManager::setScoringAvoidedRobot(const bool flag) {
+ _scoringFlags.setFlag(kScoringAvoidedRobotFlag, flag);
+}
+
+void GameStateManager::setScoringActivatedPlatform(const bool flag) {
+ _scoringFlags.setFlag(kScoringActivatedPlatformFlag, flag);
+}
+
+void GameStateManager::setScoringUsedLiquidNitrogen(const bool flag) {
+ _scoringFlags.setFlag(kScoringUsedLiquidNitrogenFlag, flag);
+}
+
+void GameStateManager::setScoringUsedCrowBar(const bool flag) {
+ _scoringFlags.setFlag(kScoringUsedCrowBarFlag, flag);
+}
+
+void GameStateManager::setScoringFoundCardBomb(const bool flag) {
+ _scoringFlags.setFlag(kScoringFoundCardBombFlag, flag);
+}
+
+void GameStateManager::setScoringDisarmedCardBomb(const bool flag) {
+ _scoringFlags.setFlag(kScoringDisarmedCardBombFlag, flag);
+}
+
+void GameStateManager::setScoringGotCardBomb(const bool flag) {
+ _scoringFlags.setFlag(kScoringGotCardBombFlag, flag);
+}
+
+void GameStateManager::setScoringThreadedMaze(const bool flag) {
+ _scoringFlags.setFlag(kScoringThreadedMazeFlag, flag);
+}
+
+void GameStateManager::setScoringThreadedGearRoom(const bool flag) {
+ _scoringFlags.setFlag(kScoringThreadedGearRoomFlag, flag);
+}
+
+void GameStateManager::setScoringEnteredShuttle(const bool flag) {
+ _scoringFlags.setFlag(kScoringEnteredShuttleFlag, flag);
+}
+
+void GameStateManager::setScoringEnteredLaunchTube(const bool flag) {
+ _scoringFlags.setFlag(kScoringEnteredLaunchTubeFlag, flag);
+}
+
+void GameStateManager::setScoringStoppedRobotsShuttle(const bool flag) {
+ _scoringFlags.setFlag(kScoringStoppedRobotsShuttleFlag, flag);
+}
+
+void GameStateManager::setScoringGotMarsOpMemChip(const bool flag) {
+ _scoringFlags.setFlag(kScoringGotMarsOpMemChipFlag, flag);
+}
+
+void GameStateManager::setScoringFinishedMars(const bool flag) {
+ _scoringFlags.setFlag(kScoringFinishedMarsFlag, flag);
+}
+
+void GameStateManager::setScoringSawSecurityMonitor(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawSecurityMonitorFlag, flag);
+}
+
+void GameStateManager::setScoringFilledOxygenCanister(const bool flag) {
+ _scoringFlags.setFlag(kScoringFilledOxygenCanisterFlag, flag);
+}
+
+void GameStateManager::setScoringFilledArgonCanister(const bool flag) {
+ _scoringFlags.setFlag(kScoringFilledArgonCanisterFlag, flag);
+}
+
+void GameStateManager::setScoringSawUnconsciousOperator(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawUnconsciousOperatorFlag, flag);
+}
+
+void GameStateManager::setScoringWentThroughPressureDoor(const bool flag) {
+ _scoringFlags.setFlag(kScoringWentThroughPressureDoorFlag, flag);
+}
+
+void GameStateManager::setScoringPreppedSub(const bool flag) {
+ _scoringFlags.setFlag(kScoringPreppedSubFlag, flag);
+}
+
+void GameStateManager::setScoringEnteredSub(const bool flag) {
+ _scoringFlags.setFlag(kScoringEnteredSubFlag, flag);
+}
+
+void GameStateManager::setScoringExitedSub(const bool flag) {
+ _scoringFlags.setFlag(kScoringExitedSubFlag, flag);
+}
+
+void GameStateManager::setScoringSawRobotAt54North(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawRobotAt54NorthFlag, flag);
+}
+
+void GameStateManager::setScoringPlayedWithClaw(const bool flag) {
+ _scoringFlags.setFlag(kScoringPlayedWithClawFlag, flag);
+}
+
+void GameStateManager::setScoringUsedRetinalChip(const bool flag) {
+ _scoringFlags.setFlag(kScoringUsedRetinalChipFlag, flag);
+}
+
+void GameStateManager::setScoringFinishedGlobeGame(const bool flag) {
+ _scoringFlags.setFlag(kScoringFinishedGlobeGameFlag, flag);
+}
+
+void GameStateManager::setScoringStoppedNoradRobot(const bool flag) {
+ _scoringFlags.setFlag(kScoringStoppedNoradRobotFlag, flag);
+}
+
+void GameStateManager::setScoringGotNoradOpMemChip(const bool flag) {
+ _scoringFlags.setFlag(kScoringGotNoradOpMemChipFlag, flag);
+}
+
+void GameStateManager::setScoringFinishedNorad(const bool flag) {
+ _scoringFlags.setFlag(kScoringFinishedNoradFlag, flag);
+}
+
+void GameStateManager::setScoringRemovedDart(const bool flag) {
+ _scoringFlags.setFlag(kScoringRemovedDartFlag, flag);
+}
+
+void GameStateManager::setScoringAnalyzedDart(const bool flag) {
+ _scoringFlags.setFlag(kScoringAnalyzedDartFlag, flag);
+}
+
+void GameStateManager::setScoringBuiltAntidote(const bool flag) {
+ _scoringFlags.setFlag(kScoringBuiltAntidoteFlag, flag);
+}
+
+void GameStateManager::setScoringGotSinclairKey(const bool flag) {
+ _scoringFlags.setFlag(kScoringGotSinclairKeyFlag, flag);
+}
+
+void GameStateManager::setScoringGotArgonCanister(const bool flag) {
+ _scoringFlags.setFlag(kScoringGotArgonCanisterFlag, flag);
+}
+
+void GameStateManager::setScoringGotNitrogenCanister(const bool flag) {
+ _scoringFlags.setFlag(kScoringGotNitrogenCanisterFlag, flag);
+}
+
+void GameStateManager::setScoringPlayedWithMessages(const bool flag) {
+ _scoringFlags.setFlag(kScoringPlayedWithMessagesFlag, flag);
+}
+
+void GameStateManager::setScoringSawMorphExperiment(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawMorphExperimentFlag, flag);
+}
+
+void GameStateManager::setScoringEnteredSinclairOffice(const bool flag) {
+ _scoringFlags.setFlag(kScoringEnteredSinclairOfficeFlag, flag);
+}
+
+void GameStateManager::setScoringSawBrochure(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawBrochureFlag, flag);
+}
+
+void GameStateManager::setScoringSawSinclairEntry1(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawSinclairEntry1Flag, flag);
+}
+
+void GameStateManager::setScoringSawSinclairEntry2(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawSinclairEntry2Flag, flag);
+}
+
+void GameStateManager::setScoringSawSinclairEntry3(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawSinclairEntry3Flag, flag);
+}
+
+void GameStateManager::setScoringSawWSCDirectory(const bool flag) {
+ _scoringFlags.setFlag(kScoringSawWSCDirectoryFlag, flag);
+}
+
+void GameStateManager::setScoringUsedCrowBarInWSC(const bool flag) {
+ _scoringFlags.setFlag(kScoringUsedCrowBarInWSCFlag, flag);
+}
+
+void GameStateManager::setScoringFinishedPlasmaDodge(const bool flag) {
+ _scoringFlags.setFlag(kScoringFinishedPlasmaDodgeFlag, flag);
+}
+
+void GameStateManager::setScoringOpenedCatwalk(const bool flag) {
+ _scoringFlags.setFlag(kScoringOpenedCatwalkFlag, flag);
+}
+
+void GameStateManager::setScoringStoppedWSCRobot(const bool flag) {
+ _scoringFlags.setFlag(kScoringStoppedWSCRobotFlag, flag);
+}
+
+void GameStateManager::setScoringGotWSCOpMemChip(const bool flag) {
+ _scoringFlags.setFlag(kScoringGotWSCOpMemChipFlag, flag);
+}
+
+void GameStateManager::setScoringFinishedWSC(const bool flag) {
+ _scoringFlags.setFlag(kScoringFinishedWSCFlag, flag);
+}
+
+void GameStateManager::setScoringMarsGandhi(const bool flag) {
+ _scoringFlags.setFlag(kScoringMarsGandhiFlag, flag);
+}
+
+void GameStateManager::setScoringNoradGandhi(const bool flag) {
+ _scoringFlags.setFlag(kScoringNoradGandhiFlag, flag);
+}
+
+void GameStateManager::setScoringWSCGandhi(const bool flag) {
+ _scoringFlags.setFlag(kScoringWSCGandhiFlag, flag);
+}
+
+bool GameStateManager::getScoringSawINN() {
+ return _scoringFlags.getFlag(kScoringSawINNFlag);
+}
+
+bool GameStateManager::getScoringTookShower() {
+ return _scoringFlags.getFlag(kScoringTookShowerFlag);
+}
+
+bool GameStateManager::getScoringFixedHair() {
+ return _scoringFlags.getFlag(kScoringFixedHairFlag);
+}
+
+bool GameStateManager::getScoringGotKeyCard() {
+ return _scoringFlags.getFlag(kScoringGotKeyCardFlag);
+}
+
+bool GameStateManager::getScoringReadPaper() {
+ return _scoringFlags.getFlag(kScoringReadPaperFlag);
+}
+
+bool GameStateManager::getScoringLookThroughTelescope() {
+ return _scoringFlags.getFlag(kScoringLookThroughTelescopeFlag);
+}
+
+bool GameStateManager::getScoringSawCaldoriaKiosk() {
+ return _scoringFlags.getFlag(kScoringSawCaldoriaKioskFlag);
+}
+
+bool GameStateManager::getScoringGoToTSA() {
+ return _scoringFlags.getFlag(kScoringGoToTSAFlag);
+}
+
+bool GameStateManager::getScoringEnterTSA() {
+ return _scoringFlags.getFlag(kScoringEnterTSAFlag);
+}
+
+bool GameStateManager::getScoringSawBust1() {
+ return _scoringFlags.getFlag(kScoringSawBust1Flag);
+}
+
+bool GameStateManager::getScoringSawBust2() {
+ return _scoringFlags.getFlag(kScoringSawBust2Flag);
+}
+
+bool GameStateManager::getScoringSawBust3() {
+ return _scoringFlags.getFlag(kScoringSawBust3Flag);
+}
+
+bool GameStateManager::getScoringSawBust4() {
+ return _scoringFlags.getFlag(kScoringSawBust4Flag);
+}
+
+bool GameStateManager::getScoringSawBust5() {
+ return _scoringFlags.getFlag(kScoringSawBust5Flag);
+}
+
+bool GameStateManager::getScoringSawBust6() {
+ return _scoringFlags.getFlag(kScoringSawBust6Flag);
+}
+
+bool GameStateManager::getScoringSawTheory() {
+ return _scoringFlags.getFlag(kScoringSawTheoryFlag);
+}
+
+bool GameStateManager::getScoringSawBackground() {
+ return _scoringFlags.getFlag(kScoringSawBackgroundFlag);
+}
+
+bool GameStateManager::getScoringSawProcedure() {
+ return _scoringFlags.getFlag(kScoringSawProcedureFlag);
+}
+
+bool GameStateManager::getScoringGotJourneymanKey() {
+ return _scoringFlags.getFlag(kScoringGotJourneymanKeyFlag);
+}
+
+bool GameStateManager::getScoringGotPegasusBiochip() {
+ return _scoringFlags.getFlag(kScoringGotPegasusBiochipFlag);
+}
+
+bool GameStateManager::getScoringGotBiosuit() {
+ return _scoringFlags.getFlag(kScoringGotBiosuitFlag);
+}
+
+bool GameStateManager::getScoringGoToPrehistoric() {
+ return _scoringFlags.getFlag(kScoringGoToPrehistoricFlag);
+}
+
+bool GameStateManager::getScoringPutLogInReader() {
+ return _scoringFlags.getFlag(kScoringPutLogInReaderFlag);
+}
+
+bool GameStateManager::getScoringSawCaldoriaNormal() {
+ return _scoringFlags.getFlag(kScoringSawCaldoriaNormalFlag);
+}
+
+bool GameStateManager::getScoringSawCaldoriaAltered() {
+ return _scoringFlags.getFlag(kScoringSawCaldoriaAlteredFlag);
+}
+
+bool GameStateManager::getScoringSawNoradNormal() {
+ return _scoringFlags.getFlag(kScoringSawNoradNormalFlag);
+}
+
+bool GameStateManager::getScoringSawNoradAltered() {
+ return _scoringFlags.getFlag(kScoringSawNoradAlteredFlag);
+}
+
+bool GameStateManager::getScoringSawMarsNormal() {
+ return _scoringFlags.getFlag(kScoringSawMarsNormalFlag);
+}
+
+bool GameStateManager::getScoringSawMarsAltered() {
+ return _scoringFlags.getFlag(kScoringSawMarsAlteredFlag);
+}
+
+bool GameStateManager::getScoringSawWSCNormal() {
+ return _scoringFlags.getFlag(kScoringSawWSCNormalFlag);
+}
+
+bool GameStateManager::getScoringSawWSCAltered() {
+ return _scoringFlags.getFlag(kScoringSawWSCAlteredFlag);
+}
+
+bool GameStateManager::getScoringWentToReadyRoom2() {
+ return _scoringFlags.getFlag(kScoringWentToReadyRoom2Flag);
+}
+
+bool GameStateManager::getScoringWentAfterSinclair() {
+ return _scoringFlags.getFlag(kScoringWentAfterSinclairFlag);
+}
+
+bool GameStateManager::getScoringUsedCardBomb() {
+ return _scoringFlags.getFlag(kScoringUsedCardBombFlag);
+}
+
+bool GameStateManager::getScoringShieldedCardBomb() {
+ return _scoringFlags.getFlag(kScoringShieldedCardBombFlag);
+}
+
+bool GameStateManager::getScoringStunnedSinclair() {
+ return _scoringFlags.getFlag(kScoringStunnedSinclairFlag);
+}
+
+bool GameStateManager::getScoringDisarmedNuke() {
+ return _scoringFlags.getFlag(kScoringDisarmedNukeFlag);
+}
+
+bool GameStateManager::getScoringThrewBreaker() {
+ return _scoringFlags.getFlag(kScoringThrewBreakerFlag);
+}
+
+bool GameStateManager::getScoringExtendedBridge() {
+ return _scoringFlags.getFlag(kScoringExtendedBridgeFlag);
+}
+
+bool GameStateManager::getScoringGotHistoricalLog() {
+ return _scoringFlags.getFlag(kScoringGotHistoricalLogFlag);
+}
+
+bool GameStateManager::getScoringFinishedPrehistoric() {
+ return _scoringFlags.getFlag(kScoringFinishedPrehistoricFlag);
+}
+
+bool GameStateManager::getScoringThrownByRobot() {
+ return _scoringFlags.getFlag(kScoringThrownByRobotFlag);
+}
+
+bool GameStateManager::getScoringGotMarsCard() {
+ return _scoringFlags.getFlag(kScoringGotMarsCardFlag);
+}
+
+bool GameStateManager::getScoringSawMarsKiosk() {
+ return _scoringFlags.getFlag(kScoringSawMarsKioskFlag);
+}
+
+bool GameStateManager::getScoringSawTransportMap() {
+ return _scoringFlags.getFlag(kScoringSawTransportMapFlag);
+}
+
+bool GameStateManager::getScoringGotCrowBar() {
+ return _scoringFlags.getFlag(kScoringGotCrowBarFlag);
+}
+
+bool GameStateManager::getScoringTurnedOnTransport() {
+ return _scoringFlags.getFlag(kScoringTurnedOnTransportFlag);
+}
+
+bool GameStateManager::getScoringGotOxygenMask() {
+ return _scoringFlags.getFlag(kScoringGotOxygenMaskFlag);
+}
+
+bool GameStateManager::getScoringAvoidedRobot() {
+ return _scoringFlags.getFlag(kScoringAvoidedRobotFlag);
+}
+
+bool GameStateManager::getScoringActivatedPlatform() {
+ return _scoringFlags.getFlag(kScoringActivatedPlatformFlag);
+}
+
+bool GameStateManager::getScoringUsedLiquidNitrogen() {
+ return _scoringFlags.getFlag(kScoringUsedLiquidNitrogenFlag);
+}
+
+bool GameStateManager::getScoringUsedCrowBar() {
+ return _scoringFlags.getFlag(kScoringUsedCrowBarFlag);
+}
+
+bool GameStateManager::getScoringFoundCardBomb() {
+ return _scoringFlags.getFlag(kScoringFoundCardBombFlag);
+}
+
+bool GameStateManager::getScoringDisarmedCardBomb() {
+ return _scoringFlags.getFlag(kScoringDisarmedCardBombFlag);
+}
+
+bool GameStateManager::getScoringGotCardBomb() {
+ return _scoringFlags.getFlag(kScoringGotCardBombFlag);
+}
+
+bool GameStateManager::getScoringThreadedMaze() {
+ return _scoringFlags.getFlag(kScoringThreadedMazeFlag);
+}
+
+bool GameStateManager::getScoringThreadedGearRoom() {
+ return _scoringFlags.getFlag(kScoringThreadedGearRoomFlag);
+}
+
+bool GameStateManager::getScoringEnteredShuttle() {
+ return _scoringFlags.getFlag(kScoringEnteredShuttleFlag);
+}
+
+bool GameStateManager::getScoringEnteredLaunchTube() {
+ return _scoringFlags.getFlag(kScoringEnteredLaunchTubeFlag);
+}
+
+bool GameStateManager::getScoringStoppedRobotsShuttle() {
+ return _scoringFlags.getFlag(kScoringStoppedRobotsShuttleFlag);
+}
+
+bool GameStateManager::getScoringGotMarsOpMemChip() {
+ return _scoringFlags.getFlag(kScoringGotMarsOpMemChipFlag);
+}
+
+bool GameStateManager::getScoringFinishedMars() {
+ return _scoringFlags.getFlag(kScoringFinishedMarsFlag);
+}
+
+bool GameStateManager::getScoringSawSecurityMonitor() {
+ return _scoringFlags.getFlag(kScoringSawSecurityMonitorFlag);
+}
+
+bool GameStateManager::getScoringFilledOxygenCanister() {
+ return _scoringFlags.getFlag(kScoringFilledOxygenCanisterFlag);
+}
+
+bool GameStateManager::getScoringFilledArgonCanister() {
+ return _scoringFlags.getFlag(kScoringFilledArgonCanisterFlag);
+}
+
+bool GameStateManager::getScoringSawUnconsciousOperator() {
+ return _scoringFlags.getFlag(kScoringSawUnconsciousOperatorFlag);
+}
+
+bool GameStateManager::getScoringWentThroughPressureDoor() {
+ return _scoringFlags.getFlag(kScoringWentThroughPressureDoorFlag);
+}
+
+bool GameStateManager::getScoringPreppedSub() {
+ return _scoringFlags.getFlag(kScoringPreppedSubFlag);
+}
+
+bool GameStateManager::getScoringEnteredSub() {
+ return _scoringFlags.getFlag(kScoringEnteredSubFlag);
+}
+
+bool GameStateManager::getScoringExitedSub() {
+ return _scoringFlags.getFlag(kScoringExitedSubFlag);
+}
+
+bool GameStateManager::getScoringSawRobotAt54North() {
+ return _scoringFlags.getFlag(kScoringSawRobotAt54NorthFlag);
+}
+
+bool GameStateManager::getScoringPlayedWithClaw() {
+ return _scoringFlags.getFlag(kScoringPlayedWithClawFlag);
+}
+
+bool GameStateManager::getScoringUsedRetinalChip() {
+ return _scoringFlags.getFlag(kScoringUsedRetinalChipFlag);
+}
+
+bool GameStateManager::getScoringFinishedGlobeGame() {
+ return _scoringFlags.getFlag(kScoringFinishedGlobeGameFlag);
+}
+
+bool GameStateManager::getScoringStoppedNoradRobot() {
+ return _scoringFlags.getFlag(kScoringStoppedNoradRobotFlag);
+}
+
+bool GameStateManager::getScoringGotNoradOpMemChip() {
+ return _scoringFlags.getFlag(kScoringGotNoradOpMemChipFlag);
+}
+
+bool GameStateManager::getScoringFinishedNorad() {
+ return _scoringFlags.getFlag(kScoringFinishedNoradFlag);
+}
+
+bool GameStateManager::getScoringRemovedDart() {
+ return _scoringFlags.getFlag(kScoringRemovedDartFlag);
+}
+
+bool GameStateManager::getScoringAnalyzedDart() {
+ return _scoringFlags.getFlag(kScoringAnalyzedDartFlag);
+}
+
+bool GameStateManager::getScoringBuiltAntidote() {
+ return _scoringFlags.getFlag(kScoringBuiltAntidoteFlag);
+}
+
+bool GameStateManager::getScoringGotSinclairKey() {
+ return _scoringFlags.getFlag(kScoringGotSinclairKeyFlag);
+}
+
+bool GameStateManager::getScoringGotArgonCanister() {
+ return _scoringFlags.getFlag(kScoringGotArgonCanisterFlag);
+}
+
+bool GameStateManager::getScoringGotNitrogenCanister() {
+ return _scoringFlags.getFlag(kScoringGotNitrogenCanisterFlag);
+}
+
+bool GameStateManager::getScoringPlayedWithMessages() {
+ return _scoringFlags.getFlag(kScoringPlayedWithMessagesFlag);
+}
+
+bool GameStateManager::getScoringSawMorphExperiment() {
+ return _scoringFlags.getFlag(kScoringSawMorphExperimentFlag);
+}
+
+bool GameStateManager::getScoringEnteredSinclairOffice() {
+ return _scoringFlags.getFlag(kScoringEnteredSinclairOfficeFlag);
+}
+
+bool GameStateManager::getScoringSawBrochure() {
+ return _scoringFlags.getFlag(kScoringSawBrochureFlag);
+}
+
+bool GameStateManager::getScoringSawSinclairEntry1() {
+ return _scoringFlags.getFlag(kScoringSawSinclairEntry1Flag);
+}
+
+bool GameStateManager::getScoringSawSinclairEntry2() {
+ return _scoringFlags.getFlag(kScoringSawSinclairEntry2Flag);
+}
+
+bool GameStateManager::getScoringSawSinclairEntry3() {
+ return _scoringFlags.getFlag(kScoringSawSinclairEntry3Flag);
+}
+
+bool GameStateManager::getScoringSawWSCDirectory() {
+ return _scoringFlags.getFlag(kScoringSawWSCDirectoryFlag);
+}
+
+bool GameStateManager::getScoringUsedCrowBarInWSC() {
+ return _scoringFlags.getFlag(kScoringUsedCrowBarInWSCFlag);
+}
+
+bool GameStateManager::getScoringFinishedPlasmaDodge() {
+ return _scoringFlags.getFlag(kScoringFinishedPlasmaDodgeFlag);
+}
+
+bool GameStateManager::getScoringOpenedCatwalk() {
+ return _scoringFlags.getFlag(kScoringOpenedCatwalkFlag);
+}
+
+bool GameStateManager::getScoringStoppedWSCRobot() {
+ return _scoringFlags.getFlag(kScoringStoppedWSCRobotFlag);
+}
+
+bool GameStateManager::getScoringGotWSCOpMemChip() {
+ return _scoringFlags.getFlag(kScoringGotWSCOpMemChipFlag);
+}
+
+bool GameStateManager::getScoringFinishedWSC() {
+ return _scoringFlags.getFlag(kScoringFinishedWSCFlag);
+}
+
+bool GameStateManager::getScoringMarsGandhi() {
+ return _scoringFlags.getFlag(kScoringMarsGandhiFlag);
+}
+
+bool GameStateManager::getScoringNoradGandhi() {
+ return _scoringFlags.getFlag(kScoringNoradGandhiFlag);
+}
+
+bool GameStateManager::getScoringWSCGandhi() {
+ return _scoringFlags.getFlag(kScoringWSCGandhiFlag);
+}
+
+void GameStateManager::setWalkthroughMode(bool value) {
+ _globalFlags.setFlag(kGlobalWalkthroughFlag, value);
+}
+
+bool GameStateManager::getWalkthroughMode() {
+ return _globalFlags.getFlag(kGlobalWalkthroughFlag);
+}
+
+void GameStateManager::setShieldOn(bool value) {
+ _globalFlags.setFlag(kGlobalShieldOnFlag, value);
+}
+
+bool GameStateManager::getShieldOn() {
+ return _globalFlags.getFlag(kGlobalShieldOnFlag);
+}
+
+void GameStateManager::setEasterEgg(bool value) {
+ _globalFlags.setFlag(kGlobalEasterEggFlag, value);
+}
+
+bool GameStateManager::getEasterEgg() {
+ return _globalFlags.getFlag(kGlobalEasterEggFlag);
+}
+
+void GameStateManager::setBeenToWSC(bool value) {
+ _globalFlags.setFlag(kGlobalBeenToWSCFlag, value);
+}
+
+bool GameStateManager::getBeenToWSC() {
+ return _globalFlags.getFlag(kGlobalBeenToWSCFlag);
+}
+
+void GameStateManager::setBeenToMars(bool value) {
+ _globalFlags.setFlag(kGlobalBeenToMarsFlag, value);
+}
+
+bool GameStateManager::getBeenToMars() {
+ return _globalFlags.getFlag(kGlobalBeenToMarsFlag);
+}
+
+void GameStateManager::setBeenToNorad(bool value) {
+ _globalFlags.setFlag(kGlobalBeenToNoradFlag, value);
+}
+
+bool GameStateManager::getBeenToNorad() {
+ return _globalFlags.getFlag(kGlobalBeenToNoradFlag);
+}
+
+void GameStateManager::setWSCFinished(bool value) {
+ _globalFlags.setFlag(kGlobalWSCFinishedFlag, value);
+}
+
+bool GameStateManager::getWSCFinished() {
+ return _globalFlags.getFlag(kGlobalWSCFinishedFlag);
+}
+
+void GameStateManager::setMarsFinished(bool value) {
+ _globalFlags.setFlag(kGlobalMarsFinishedFlag, value);
+}
+
+bool GameStateManager::getMarsFinished() {
+ return _globalFlags.getFlag(kGlobalMarsFinishedFlag);
+}
+
+void GameStateManager::setNoradFinished(bool value) {
+ _globalFlags.setFlag(kGlobalNoradFinishedFlag, value);
+}
+
+bool GameStateManager::getNoradFinished() {
+ return _globalFlags.getFlag(kGlobalNoradFinishedFlag);
+}
+
+bool GameStateManager::allTimeZonesFinished() {
+ return getWSCFinished() && getMarsFinished() && getNoradFinished();
+}
+
+void GameStateManager::setTakenItemID(ItemID id, bool value) {
+ _itemTakenFlags.setFlag(id, value);
+}
+
+bool GameStateManager::isTakenItemID(ItemID id) {
+ return _itemTakenFlags.getFlag(id);
+}
+
+void GameStateManager::setTakenItem(Item *item, bool value) {
+ setTakenItemID(item->getObjectID(), value);
+}
+
+bool GameStateManager::isTakenItem(Item *item) {
+ return isTakenItemID(item->getObjectID());
+}
+
+void GameStateManager::setCaldoriaFuseTimeLimit(const TimeValue timeLimit) {
+ _caldoriaFuseTimeLimit = timeLimit;
+}
+
+TimeValue GameStateManager::getCaldoriaFuseTimeLimit() {
+ return _caldoriaFuseTimeLimit;
+}
+
+void GameStateManager::setCaldoriaSeenPullback(bool value) {
+ _caldoriaFlags.setFlag(kCaldoriaSeenPullbackFlag, value);
+}
+
+bool GameStateManager::getCaldoriaSeenPullback() {
+ return _caldoriaFlags.getFlag(kCaldoriaSeenPullbackFlag);
+}
+
+void GameStateManager::setCaldoriaMadeOJ(bool value) {
+ _caldoriaFlags.setFlag(kCaldoriaMadeOJFlag, value);
+}
+
+bool GameStateManager::getCaldoriaMadeOJ() {
+ return _caldoriaFlags.getFlag(kCaldoriaMadeOJFlag);
+}
+
+void GameStateManager::setCaldoriaWokenUp(bool value) {
+ _caldoriaFlags.setFlag(kCaldoriaWokenUpFlag, value);
+}
+
+bool GameStateManager::getCaldoriaWokenUp() {
+ return _caldoriaFlags.getFlag(kCaldoriaWokenUpFlag);
+}
+
+void GameStateManager::setCaldoriaDidRecalibration(bool value) {
+ _caldoriaFlags.setFlag(kCaldoriaDidRecalibrationFlag, value);
+}
+
+bool GameStateManager::getCaldoriaDidRecalibration() {
+ return _caldoriaFlags.getFlag(kCaldoriaDidRecalibrationFlag);
+}
+
+void GameStateManager::setCaldoriaSeenSinclairInElevator(bool value) {
+ _caldoriaFlags.setFlag(kCaldoriaSeenSinclairInElevatorFlag, value);
+}
+
+bool GameStateManager::getCaldoriaSeenSinclairInElevator() {
+ return _caldoriaFlags.getFlag(kCaldoriaSeenSinclairInElevatorFlag);
+}
+
+void GameStateManager::setCaldoriaINNAnnouncing(bool value) {
+ _caldoriaFlags.setFlag(kCaldoriaINNAnnouncingFlag, value);
+}
+
+bool GameStateManager::getCaldoriaINNAnnouncing() {
+ return _caldoriaFlags.getFlag(kCaldoriaINNAnnouncingFlag);
+}
+
+void GameStateManager::setCaldoriaSeenINN(bool value) {
+ _caldoriaFlags.setFlag(kCaldoriaSeenINNFlag, value);
+}
+
+bool GameStateManager::getCaldoriaSeenINN() {
+ return _caldoriaFlags.getFlag(kCaldoriaSeenINNFlag);
+}
+
+void GameStateManager::setCaldoriaSeenMessages(bool value) {
+ _caldoriaFlags.setFlag(kCaldoriaSeenMessagesFlag, value);
+}
+
+bool GameStateManager::getCaldoriaSeenMessages() {
+ return _caldoriaFlags.getFlag(kCaldoriaSeenMessagesFlag);
+}
+
+void GameStateManager::setCaldoriaSinclairShot(bool value) {
+ _caldoriaFlags.setFlag(kCaldoriaSinclairShotFlag, value);
+}
+
+bool GameStateManager::getCaldoriaSinclairShot() {
+ return _caldoriaFlags.getFlag(kCaldoriaSinclairShotFlag);
+}
+
+void GameStateManager::setCaldoriaBombDisarmed(bool value) {
+ _caldoriaFlags.setFlag(kCaldoriaBombDisarmedFlag, value);
+}
+
+bool GameStateManager::getCaldoriaBombDisarmed() {
+ return _caldoriaFlags.getFlag(kCaldoriaBombDisarmedFlag);
+}
+
+void GameStateManager::setCaldoriaRoofDoorOpen(bool value) {
+ _caldoriaFlags.setFlag(kCaldoriaRoofDoorOpenFlag, value);
+}
+
+bool GameStateManager::getCaldoriaRoofDoorOpen() {
+ return _caldoriaFlags.getFlag(kCaldoriaRoofDoorOpenFlag);
+}
+
+void GameStateManager::setCaldoriaDoneHygiene(bool value) {
+ _caldoriaFlags.setFlag(kCaldoriaDoneHygieneFlag, value);
+}
+
+bool GameStateManager::getCaldoriaDoneHygiene() {
+ return _caldoriaFlags.getFlag(kCaldoriaDoneHygieneFlag);
+}
+
+void GameStateManager::setCaldoriaSawVoiceAnalysis(bool value) {
+ _caldoriaFlags.setFlag(kCaldoriaSawVoiceAnalysisFlag, value);
+}
+
+bool GameStateManager::getCaldoriaSawVoiceAnalysis() {
+ return _caldoriaFlags.getFlag(kCaldoriaSawVoiceAnalysisFlag);
+}
+
+void GameStateManager::setCaldoriaDoorBombed(bool value) {
+ _caldoriaFlags.setFlag(kCaldoriaDoorBombedFlag, value);
+}
+
+bool GameStateManager::getCaldoriaDoorBombed() {
+ return _caldoriaFlags.getFlag(kCaldoriaDoorBombedFlag);
+}
+
+void GameStateManager::setCaldoriaGunAimed(bool value) {
+ _caldoriaFlags.setFlag(kCaldoriaGunAimedFlag, value);
+}
+
+bool GameStateManager::getCaldoriaGunAimed() {
+ return _caldoriaFlags.getFlag(kCaldoriaGunAimedFlag);
+}
+
+void GameStateManager::setRipTimerTime(TimeValue limit) {
+ _TSARipTimerTime = limit;
+}
+
+TimeValue GameStateManager::getRipTimerTime() {
+ return _TSARipTimerTime;
+}
+
+void GameStateManager::setTSAFuseTimeLimit(TimeValue limit) {
+ _TSAFuseTimeLimit = limit;
+}
+
+TimeValue GameStateManager::getTSAFuseTimeLimit() {
+ return _TSAFuseTimeLimit;
+}
+
+void GameStateManager::setTSAState(byte state) {
+ _TSAState = state;
+}
+
+byte GameStateManager::getTSAState() {
+ return _TSAState;
+}
+
+void GameStateManager::setT0BMonitorMode(byte mode) {
+ _T0BMonitorMode = mode;
+}
+
+byte GameStateManager::getT0BMonitorMode() {
+ return _T0BMonitorMode;
+}
+
+void GameStateManager::setT0BMonitorStart(TimeValue start) {
+ _T0BMonitorStart = start;
+}
+
+TimeValue GameStateManager::getT0BMonitorStart() {
+ return _T0BMonitorStart;
+}
+
+void GameStateManager::setTSAIDedAtDoor(bool value) {
+ _TSAFlags.setFlag(kTSAIDedAtDoorFlag, value);
+}
+
+bool GameStateManager::getTSAIDedAtDoor() {
+ return _TSAFlags.getFlag(kTSAIDedAtDoorFlag);
+}
+
+void GameStateManager::setTSA0BZoomedIn(bool value) {
+ _TSAFlags.setFlag(kTSA0BZoomedInFlag, value);
+}
+
+bool GameStateManager::getTSA0BZoomedIn() {
+ return _TSAFlags.getFlag(kTSA0BZoomedInFlag);
+}
+
+void GameStateManager::setTSAFrontDoorUnlockedOutside(bool value) {
+ _TSAFlags.setFlag(kTSAFrontDoorUnlockedOutsideFlag, value);
+}
+
+bool GameStateManager::getTSAFrontDoorUnlockedOutside() {
+ return _TSAFlags.getFlag(kTSAFrontDoorUnlockedOutsideFlag);
+}
+
+void GameStateManager::setTSAFrontDoorUnlockedInside(bool value) {
+ _TSAFlags.setFlag(kTSAFrontDoorUnlockedInsideFlag, value);
+}
+
+bool GameStateManager::getTSAFrontDoorUnlockedInside() {
+ return _TSAFlags.getFlag(kTSAFrontDoorUnlockedInsideFlag);
+}
+
+void GameStateManager::setTSASeenRobotGreeting(bool value) {
+ _TSAFlags.setFlag(kTSASeenRobotGreetingFlag, value);
+}
+
+bool GameStateManager::getTSASeenRobotGreeting() {
+ return _TSAFlags.getFlag(kTSASeenRobotGreetingFlag);
+}
+
+void GameStateManager::setTSASeenTheory(bool value) {
+ _TSAFlags.setFlag(kTSASeenTheoryFlag, value);
+}
+
+bool GameStateManager::getTSASeenTheory() {
+ return _TSAFlags.getFlag(kTSASeenTheoryFlag);
+}
+
+void GameStateManager::setTSASeenBackground(bool value) {
+ _TSAFlags.setFlag(kTSASeenBackgroundFlag, value);
+}
+
+bool GameStateManager::getTSASeenBackground() {
+ return _TSAFlags.getFlag(kTSASeenBackgroundFlag);
+}
+
+void GameStateManager::setTSASeenProcedure(bool value) {
+ _TSAFlags.setFlag(kTSASeenProcedureFlag, value);
+}
+
+bool GameStateManager::getTSASeenProcedure() {
+ return _TSAFlags.getFlag(kTSASeenProcedureFlag);
+}
+
+void GameStateManager::setTSASeenAgent3AtDoor(bool value) {
+ _TSAFlags.setFlag(kTSASeenAgent3AtDoorFlag, value);
+}
+
+bool GameStateManager::getTSASeenAgent3AtDoor() {
+ return _TSAFlags.getFlag(kTSASeenAgent3AtDoorFlag);
+}
+
+void GameStateManager::setTSACommandCenterLocked(bool value) {
+ _TSAFlags.setFlag(kTSACommandCenterLockedFlag, value);
+}
+
+bool GameStateManager::getTSACommandCenterLocked() {
+ return _TSAFlags.getFlag(kTSACommandCenterLockedFlag);
+}
+
+void GameStateManager::setTSASeenCaldoriaNormal(bool value) {
+ _TSAFlags.setFlag(kTSASeenCaldoriaNormalFlag, value);
+}
+
+bool GameStateManager::getTSASeenCaldoriaNormal() {
+ return _TSAFlags.getFlag(kTSASeenCaldoriaNormalFlag);
+}
+
+void GameStateManager::setTSASeenCaldoriaAltered(bool value) {
+ _TSAFlags.setFlag(kTSASeenCaldoriaAlteredFlag, value);
+}
+
+bool GameStateManager::getTSASeenCaldoriaAltered() {
+ return _TSAFlags.getFlag(kTSASeenCaldoriaAlteredFlag);
+}
+
+void GameStateManager::setTSASeenNoradNormal(bool value) {
+ _TSAFlags.setFlag(kTSASeenNoradNormalFlag, value);
+}
+
+bool GameStateManager::getTSASeenNoradNormal() {
+ return _TSAFlags.getFlag(kTSASeenNoradNormalFlag);
+}
+
+void GameStateManager::setTSASeenNoradAltered(bool value) {
+ _TSAFlags.setFlag(kTSASeenNoradAlteredFlag, value);
+}
+
+bool GameStateManager::getTSASeenNoradAltered() {
+ return _TSAFlags.getFlag(kTSASeenNoradAlteredFlag);
+}
+
+void GameStateManager::setTSASeenMarsNormal(bool value) {
+ _TSAFlags.setFlag(kTSASeenMarsNormalFlag, value);
+}
+
+bool GameStateManager::getTSASeenMarsNormal() {
+ return _TSAFlags.getFlag(kTSASeenMarsNormalFlag);
+}
+
+void GameStateManager::setTSASeenMarsAltered(bool value) {
+ _TSAFlags.setFlag(kTSASeenMarsAlteredFlag, value);
+}
+
+bool GameStateManager::getTSASeenMarsAltered() {
+ return _TSAFlags.getFlag(kTSASeenMarsAlteredFlag);
+}
+
+void GameStateManager::setTSASeenWSCNormal(bool value) {
+ _TSAFlags.setFlag(kTSASeenWSCNormalFlag, value);
+}
+
+bool GameStateManager::getTSASeenWSCNormal() {
+ return _TSAFlags.getFlag(kTSASeenWSCNormalFlag);
+}
+
+void GameStateManager::setTSASeenWSCAltered(bool value) {
+ _TSAFlags.setFlag(kTSASeenWSCAlteredFlag, value);
+}
+
+bool GameStateManager::getTSASeenWSCAltered() {
+ return _TSAFlags.getFlag(kTSASeenWSCAlteredFlag);
+}
+
+void GameStateManager::setTSABiosuitOn(bool value) {
+ _TSAFlags.setFlag(kTSABiosuitOnFlag, value);
+}
+
+bool GameStateManager::getTSABiosuitOn() {
+ return _TSAFlags.getFlag(kTSABiosuitOnFlag);
+}
+
+void GameStateManager::setPrehistoricTriedToExtendBridge(bool value) {
+ _prehistoricFlags.setFlag(kPrehistoricTriedToExtendBridgeFlag, value);
+}
+
+bool GameStateManager::getPrehistoricTriedToExtendBridge() {
+ return _prehistoricFlags.getFlag(kPrehistoricTriedToExtendBridgeFlag);
+}
+
+void GameStateManager::setPrehistoricSeenTimeStream(bool value) {
+ _prehistoricFlags.setFlag(kPrehistoricSeenTimeStreamFlag, value);
+}
+
+bool GameStateManager::getPrehistoricSeenTimeStream() {
+ return _prehistoricFlags.getFlag(kPrehistoricSeenTimeStreamFlag);
+}
+
+void GameStateManager::setPrehistoricSeenFlyer1(bool value) {
+ _prehistoricFlags.setFlag(kPrehistoricSeenFlyer1Flag, value);
+}
+
+bool GameStateManager::getPrehistoricSeenFlyer1() {
+ return _prehistoricFlags.getFlag(kPrehistoricSeenFlyer1Flag);
+}
+
+void GameStateManager::setPrehistoricSeenFlyer2(bool value) {
+ _prehistoricFlags.setFlag(kPrehistoricSeenFlyer2Flag, value);
+}
+
+bool GameStateManager::getPrehistoricSeenFlyer2() {
+ return _prehistoricFlags.getFlag(kPrehistoricSeenFlyer2Flag);
+}
+
+void GameStateManager::setPrehistoricSeenBridgeZoom(bool value) {
+ _prehistoricFlags.setFlag(kPrehistoricSeenBridgeZoomFlag, value);
+}
+
+bool GameStateManager::getPrehistoricSeenBridgeZoom() {
+ return _prehistoricFlags.getFlag(kPrehistoricSeenBridgeZoomFlag);
+}
+
+void GameStateManager::setPrehistoricBreakerThrown(bool value) {
+ _prehistoricFlags.setFlag(kPrehistoricBreakerThrownFlag, value);
+}
+
+bool GameStateManager::getPrehistoricBreakerThrown() {
+ return _prehistoricFlags.getFlag(kPrehistoricBreakerThrownFlag);
+}
+
+void GameStateManager::setNoradSeenTimeStream(bool value) {
+ _noradFlags.setFlag(kNoradSeenTimeStreamFlag, value);
+}
+
+bool GameStateManager::getNoradSeenTimeStream() {
+ return _noradFlags.getFlag(kNoradSeenTimeStreamFlag);
+}
+
+void GameStateManager::setNoradGassed(bool value) {
+ _noradFlags.setFlag(kNoradGassedFlag, value);
+}
+
+bool GameStateManager::getNoradGassed() {
+ return _noradFlags.getFlag(kNoradGassedFlag);
+}
+
+void GameStateManager::setNoradFillingStationOn(bool value) {
+ _noradFlags.setFlag(kNoradFillingStationOnFlag, value);
+}
+
+bool GameStateManager::getNoradFillingStationOn() {
+ return _noradFlags.getFlag(kNoradFillingStationOnFlag);
+}
+
+void GameStateManager::setNoradN22MessagePlayed(bool value) {
+ _noradFlags.setFlag(kNoradN22MessagePlayedFlag, value);
+}
+
+bool GameStateManager::getNoradN22MessagePlayed() {
+ return _noradFlags.getFlag(kNoradN22MessagePlayedFlag);
+}
+
+void GameStateManager::setNoradPlayedGlobeGame(bool value) {
+ _noradFlags.setFlag(kNoradPlayedGlobeGameFlag, value);
+}
+
+bool GameStateManager::getNoradPlayedGlobeGame() {
+ return _noradFlags.getFlag(kNoradPlayedGlobeGameFlag);
+}
+
+void GameStateManager::setNoradBeatRobotWithClaw(bool value) {
+ _noradFlags.setFlag(kNoradBeatRobotWithClawFlag, value);
+}
+
+bool GameStateManager::getNoradBeatRobotWithClaw() {
+ return _noradFlags.getFlag(kNoradBeatRobotWithClawFlag);
+}
+
+void GameStateManager::setNoradBeatRobotWithDoor(bool value) {
+ _noradFlags.setFlag(kNoradBeatRobotWithDoorFlag, value);
+}
+
+bool GameStateManager::getNoradBeatRobotWithDoor() {
+ return _noradFlags.getFlag(kNoradBeatRobotWithDoorFlag);
+}
+
+void GameStateManager::setNoradRetScanGood(bool value) {
+ _noradFlags.setFlag(kNoradRetScanGoodFlag, value);
+}
+
+bool GameStateManager::getNoradRetScanGood() {
+ return _noradFlags.getFlag(kNoradRetScanGoodFlag);
+}
+
+void GameStateManager::setNoradWaitingForLaser(bool value) {
+ _noradFlags.setFlag(kNoradWaitingForLaserFlag, value);
+}
+
+bool GameStateManager::getNoradWaitingForLaser() {
+ return _noradFlags.getFlag(kNoradWaitingForLaserFlag);
+}
+
+void GameStateManager::setNoradSubRoomPressure(uint16 pressure) {
+ _noradSubRoomPressure = pressure;
+}
+
+uint16 GameStateManager::getNoradSubRoomPressure() {
+ return _noradSubRoomPressure;
+}
+
+void GameStateManager::setNoradSubPrepState(NoradSubPrepState state) {
+ _noradSubPrepState = state;
+}
+
+NoradSubPrepState GameStateManager::getNoradSubPrepState() {
+ return _noradSubPrepState;
+}
+
+void GameStateManager::setNoradArrivedFromSub(bool value) {
+ _noradFlags.setFlag(kNoradArrivedFromSubFlag, value);
+}
+
+bool GameStateManager::getNoradArrivedFromSub() {
+ return _noradFlags.getFlag(kNoradArrivedFromSubFlag);
+}
+
+void GameStateManager::setMarsSeenTimeStream(bool value) {
+ _marsFlags.setFlag(kMarsSeenTimeStreamFlag, value);
+}
+
+bool GameStateManager::getMarsSeenTimeStream() {
+ return _marsFlags.getFlag(kMarsSeenTimeStreamFlag);
+}
+
+void GameStateManager::setMarsHeardUpperPodMessage(bool value) {
+ _marsFlags.setFlag(kMarsHeardUpperPodMessageFlag, value);
+}
+
+bool GameStateManager::getMarsHeardUpperPodMessage() {
+ return _marsFlags.getFlag(kMarsHeardUpperPodMessageFlag);
+}
+
+void GameStateManager::setMarsRobotThrownPlayer(bool value) {
+ _marsFlags.setFlag(kMarsRobotThrownPlayerFlag, value);
+}
+
+bool GameStateManager::getMarsRobotThrownPlayer() {
+ return _marsFlags.getFlag(kMarsRobotThrownPlayerFlag);
+}
+
+void GameStateManager::setMarsHeardCheckInMessage(bool value) {
+ _marsFlags.setFlag(kMarsHeardCheckInMessageFlag, value);
+}
+
+bool GameStateManager::getMarsHeardCheckInMessage() {
+ return _marsFlags.getFlag(kMarsHeardCheckInMessageFlag);
+}
+
+void GameStateManager::setMarsPodAtUpperPlatform(bool value) {
+ _marsFlags.setFlag(kMarsPodAtUpperPlatformFlag, value);
+}
+
+bool GameStateManager::getMarsPodAtUpperPlatform() {
+ return _marsFlags.getFlag(kMarsPodAtUpperPlatformFlag);
+}
+
+void GameStateManager::setMarsSeenThermalScan(bool value) {
+ _marsFlags.setFlag(kMarsSeenThermalScanFlag, value);
+}
+
+bool GameStateManager::getMarsSeenThermalScan() {
+ return _marsFlags.getFlag(kMarsSeenThermalScanFlag);
+}
+
+void GameStateManager::setMarsArrivedBelow(bool value) {
+ _marsFlags.setFlag(kMarsArrivedBelowFlag, value);
+}
+
+bool GameStateManager::getMarsArrivedBelow() {
+ return _marsFlags.getFlag(kMarsArrivedBelowFlag);
+}
+
+void GameStateManager::setMarsSeenRobotAtReactor(bool value) {
+ _marsFlags.setFlag(kMarsSeenRobotAtReactorFlag, value);
+}
+
+bool GameStateManager::getMarsSeenRobotAtReactor() {
+ return _marsFlags.getFlag(kMarsSeenRobotAtReactorFlag);
+}
+
+void GameStateManager::setMarsAvoidedReactorRobot(bool value) {
+ _marsFlags.setFlag(kMarsAvoidedReactorRobotFlag, value);
+}
+
+bool GameStateManager::getMarsAvoidedReactorRobot() {
+ return _marsFlags.getFlag(kMarsAvoidedReactorRobotFlag);
+}
+
+void GameStateManager::setMarsSecurityDown(bool value) {
+ _marsFlags.setFlag(kMarsSecurityDownFlag, value);
+}
+
+bool GameStateManager::getMarsSecurityDown() {
+ return _marsFlags.getFlag(kMarsSecurityDownFlag);
+}
+
+void GameStateManager::setMarsInAirlock(bool value) {
+ _marsFlags.setFlag(kMarsInAirlockFlag, value);
+}
+
+bool GameStateManager::getMarsInAirlock() {
+ return _marsFlags.getFlag(kMarsInAirlockFlag);
+}
+
+void GameStateManager::setMarsAirlockOpen(bool value) {
+ _marsFlags.setFlag(kMarsAirlockOpenFlag, value);
+}
+
+bool GameStateManager::getMarsAirlockOpen() {
+ return _marsFlags.getFlag(kMarsAirlockOpenFlag);
+}
+
+void GameStateManager::setMarsMaskOnFiller(bool value) {
+ _marsFlags.setFlag(kMarsMaskOnFillerFlag, value);
+}
+
+bool GameStateManager::getMarsMaskOnFiller() {
+ return _marsFlags.getFlag(kMarsMaskOnFillerFlag);
+}
+
+void GameStateManager::setMarsLockFrozen(bool value) {
+ _marsFlags.setFlag(kMarsLockFrozenFlag, value);
+}
+
+bool GameStateManager::getMarsLockFrozen() {
+ return _marsFlags.getFlag(kMarsLockFrozenFlag);
+}
+
+void GameStateManager::setMarsLockBroken(bool value) {
+ _marsFlags.setFlag(kMarsLockBrokenFlag, value);
+}
+
+bool GameStateManager::getMarsLockBroken() {
+ return _marsFlags.getFlag(kMarsLockBrokenFlag);
+}
+
+void GameStateManager::setMarsMazeDoorPair1(bool value) {
+ _marsFlags.setFlag(kMarsMazeDoorPair1Flag, value);
+}
+
+bool GameStateManager::getMarsMazeDoorPair1() {
+ return _marsFlags.getFlag(kMarsMazeDoorPair1Flag);
+}
+
+void GameStateManager::setMarsMazeDoorPair2(bool value) {
+ _marsFlags.setFlag(kMarsMazeDoorPair2Flag, value);
+}
+
+bool GameStateManager::getMarsMazeDoorPair2() {
+ return _marsFlags.getFlag(kMarsMazeDoorPair2Flag);
+}
+
+void GameStateManager::setMarsMazeDoorPair3(bool value) {
+ _marsFlags.setFlag(kMarsMazeDoorPair3Flag, value);
+}
+
+bool GameStateManager::getMarsMazeDoorPair3() {
+ return _marsFlags.getFlag(kMarsMazeDoorPair3Flag);
+}
+
+void GameStateManager::setMarsSawRobotLeave(bool value) {
+ _marsFlags.setFlag(kMarsSawRobotLeaveFlag, value);
+}
+
+bool GameStateManager::getMarsSawRobotLeave() {
+ return _marsFlags.getFlag(kMarsSawRobotLeaveFlag);
+}
+
+void GameStateManager::setMarsHitRobotWithCannon(bool flag) {
+ _marsFlags.setFlag(kMarsHitRobotWithCannonFlag, flag);
+}
+
+bool GameStateManager::getMarsHitRobotWithCannon() {
+ return _marsFlags.getFlag(kMarsHitRobotWithCannonFlag);
+}
+
+void GameStateManager::setMarsReadyForShuttleTransport(bool value) {
+ _marsFlags.setFlag(kMarsReadyForShuttleTransportFlag, value);
+}
+
+bool GameStateManager::getMarsReadyForShuttleTransport() {
+ return _marsFlags.getFlag(kMarsReadyForShuttleTransportFlag);
+}
+
+void GameStateManager::setMarsFinishedCanyonChase(bool flag) {
+ _marsFlags.setFlag(kMarsFinishedCanyonChaseFlag, flag);
+}
+
+bool GameStateManager::getMarsFinishedCanyonChase() {
+ return _marsFlags.getFlag(kMarsFinishedCanyonChaseFlag);
+}
+
+void GameStateManager::setMarsThreadedMaze(bool flag) {
+ _marsFlags.setFlag(kMarsThreadedMazeFlag, flag);
+}
+
+bool GameStateManager::getMarsThreadedMaze() {
+ return _marsFlags.getFlag(kMarsThreadedMazeFlag);
+}
+
+void GameStateManager::setWSCSeenTimeStream(bool value) {
+ _WSCFlags.setFlag(kWSCSeenTimeStreamFlag, value);
+}
+
+bool GameStateManager::getWSCSeenTimeStream() {
+ return _WSCFlags.getFlag(kWSCSeenTimeStreamFlag);
+}
+
+void GameStateManager::setWSCPoisoned(bool value) {
+ _WSCFlags.setFlag(kWSCPoisonedFlag, value);
+}
+
+bool GameStateManager::getWSCPoisoned() {
+ return _WSCFlags.getFlag(kWSCPoisonedFlag);
+}
+
+void GameStateManager::setWSCAnsweredAboutDart(bool value) {
+ _WSCFlags.setFlag(kWSCAnsweredAboutDartFlag, value);
+}
+
+bool GameStateManager::getWSCAnsweredAboutDart() {
+ return _WSCFlags.getFlag(kWSCAnsweredAboutDartFlag);
+}
+
+void GameStateManager::setWSCRemovedDart(bool value) {
+ _WSCFlags.setFlag(kWSCRemovedDartFlag, value);
+}
+
+bool GameStateManager::getWSCRemovedDart() {
+ return _WSCFlags.getFlag(kWSCRemovedDartFlag);
+}
+
+void GameStateManager::setWSCAnalyzerOn(bool value) {
+ _WSCFlags.setFlag(kWSCAnalyzerOnFlag, value);
+}
+
+bool GameStateManager::getWSCAnalyzerOn() {
+ return _WSCFlags.getFlag(kWSCAnalyzerOnFlag);
+}
+
+void GameStateManager::setWSCDartInAnalyzer(bool value) {
+ _WSCFlags.setFlag(kWSCDartInAnalyzerFlag, value);
+}
+
+bool GameStateManager::getWSCDartInAnalyzer() {
+ return _WSCFlags.getFlag(kWSCDartInAnalyzerFlag);
+}
+
+void GameStateManager::setWSCAnalyzedDart(bool value) {
+ _WSCFlags.setFlag(kWSCAnalyzedDartFlag, value);
+}
+
+bool GameStateManager::getWSCAnalyzedDart() {
+ return _WSCFlags.getFlag(kWSCAnalyzedDartFlag);
+}
+
+void GameStateManager::setWSCSawMorph(bool value) {
+ _WSCFlags.setFlag(kWSCSawMorphFlag, value);
+}
+
+bool GameStateManager::getWSCSawMorph() {
+ return _WSCFlags.getFlag(kWSCSawMorphFlag);
+}
+
+void GameStateManager::setWSCDesignedAntidote(bool value) {
+ _WSCFlags.setFlag(kWSCDesignedAntidoteFlag, value);
+}
+
+bool GameStateManager::getWSCDesignedAntidote() {
+ return _WSCFlags.getFlag(kWSCDesignedAntidoteFlag);
+}
+
+void GameStateManager::setWSCPickedUpAntidote(bool value) {
+ _WSCFlags.setFlag(kWSCPickedUpAntidoteFlag, value);
+}
+
+bool GameStateManager::getWSCPickedUpAntidote() {
+ return _WSCFlags.getFlag(kWSCPickedUpAntidoteFlag);
+}
+
+void GameStateManager::setWSCOfficeMessagesOpen(bool value) {
+ _WSCFlags.setFlag(kWSCOfficeMessagesOpenFlag, value);
+}
+
+bool GameStateManager::getWSCOfficeMessagesOpen() {
+ return _WSCFlags.getFlag(kWSCOfficeMessagesOpenFlag);
+}
+
+void GameStateManager::setWSCSeenNerd(bool value) {
+ _WSCFlags.setFlag(kWSCSeenNerdFlag, value);
+}
+
+bool GameStateManager::getWSCSeenNerd() {
+ return _WSCFlags.getFlag(kWSCSeenNerdFlag);
+}
+
+void GameStateManager::setWSCHeardPage1(bool value) {
+ _WSCFlags.setFlag(kWSCHeardPage1Flag, value);
+}
+
+bool GameStateManager::getWSCHeardPage1() {
+ return _WSCFlags.getFlag(kWSCHeardPage1Flag);
+}
+
+void GameStateManager::setWSCHeardPage2(bool value) {
+ _WSCFlags.setFlag(kWSCHeardPage2Flag, value);
+}
+
+bool GameStateManager::getWSCHeardPage2() {
+ return _WSCFlags.getFlag(kWSCHeardPage2Flag);
+}
+
+void GameStateManager::setWSCHeardCheckIn(bool value) {
+ _WSCFlags.setFlag(kWSCHeardCheckInFlag, value);
+}
+
+bool GameStateManager::getWSCHeardCheckIn() {
+ return _WSCFlags.getFlag(kWSCHeardCheckInFlag);
+}
+
+void GameStateManager::setWSCDidPlasmaDodge(bool value) {
+ _WSCFlags.setFlag(kWSCDidPlasmaDodgeFlag, value);
+}
+
+bool GameStateManager::getWSCDidPlasmaDodge() {
+ return _WSCFlags.getFlag(kWSCDidPlasmaDodgeFlag);
+}
+
+void GameStateManager::setWSCSeenSinclairLecture(bool value) {
+ _WSCFlags.setFlag(kWSCSeenSinclairLectureFlag, value);
+}
+
+bool GameStateManager::getWSCSeenSinclairLecture() {
+ return _WSCFlags.getFlag(kWSCSeenSinclairLectureFlag);
+}
+
+void GameStateManager::setWSCBeenAtWSC93(bool value) {
+ _WSCFlags.setFlag(kWSCBeenAtWSC93Flag, value);
+}
+
+bool GameStateManager::getWSCBeenAtWSC93() {
+ return _WSCFlags.getFlag(kWSCBeenAtWSC93Flag);
+}
+
+void GameStateManager::setWSCCatwalkDark(bool value) {
+ _WSCFlags.setFlag(kWSCCatwalkDarkFlag, value);
+}
+
+bool GameStateManager::getWSCCatwalkDark() {
+ return _WSCFlags.getFlag(kWSCCatwalkDarkFlag);
+}
+
+void GameStateManager::setWSCRobotDead(bool value) {
+ _WSCFlags.setFlag(kWSCRobotDeadFlag, value);
+}
+
+bool GameStateManager::getWSCRobotDead() {
+ return _WSCFlags.getFlag(kWSCRobotDeadFlag);
+}
+
+void GameStateManager::setWSCRobotGone(bool value) {
+ _WSCFlags.setFlag(kWSCRobotGoneFlag, value);
+}
+
+bool GameStateManager::getWSCRobotGone() {
+ return _WSCFlags.getFlag(kWSCRobotGoneFlag);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/gamestate.h b/engines/pegasus/gamestate.h
new file mode 100644
index 0000000000..dd47bd6e51
--- /dev/null
+++ b/engines/pegasus/gamestate.h
@@ -0,0 +1,886 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_GAMESTATE_H
+#define PEGASUS_GAMESTATE_H
+
+#include "common/singleton.h"
+#include "common/util.h"
+
+#include "pegasus/types.h"
+#include "pegasus/util.h"
+#include "pegasus/items/item.h"
+
+namespace Common {
+ class Error;
+ class ReadStream;
+ class WriteStream;
+}
+
+namespace Pegasus {
+
+// The only things saved in here are things which get written out to a saved game file...
+
+enum {
+ kGlobalWalkthroughFlag,
+ kGlobalShieldOnFlag,
+ kGlobalEasterEggFlag,
+ kGlobalBeenToWSCFlag,
+ kGlobalBeenToMarsFlag,
+ kGlobalBeenToNoradFlag,
+ kGlobalWSCFinishedFlag,
+ kGlobalMarsFinishedFlag,
+ kGlobalNoradFinishedFlag,
+ kNumGlobalFlags
+};
+
+enum {
+ kScoringSawINNFlag,
+ kScoringTookShowerFlag,
+ kScoringFixedHairFlag,
+ kScoringGotKeyCardFlag,
+ kScoringReadPaperFlag,
+ kScoringLookThroughTelescopeFlag,
+ kScoringSawCaldoriaKioskFlag,
+ kScoringGoToTSAFlag,
+ kScoringEnterTSAFlag,
+ kScoringSawBust1Flag,
+ kScoringSawBust2Flag,
+ kScoringSawBust3Flag,
+ kScoringSawBust4Flag,
+ kScoringSawBust5Flag,
+ kScoringSawBust6Flag,
+ kScoringSawTheoryFlag,
+ kScoringSawBackgroundFlag,
+ kScoringSawProcedureFlag,
+ kScoringGotJourneymanKeyFlag,
+ kScoringGotPegasusBiochipFlag,
+ kScoringGotBiosuitFlag,
+ kScoringGoToPrehistoricFlag,
+ kScoringPutLogInReaderFlag,
+ kScoringSawCaldoriaNormalFlag,
+ kScoringSawCaldoriaAlteredFlag,
+ kScoringSawNoradNormalFlag,
+ kScoringSawNoradAlteredFlag,
+ kScoringSawMarsNormalFlag,
+ kScoringSawMarsAlteredFlag,
+ kScoringSawWSCNormalFlag,
+ kScoringSawWSCAlteredFlag,
+ kScoringWentToReadyRoom2Flag,
+ kScoringWentAfterSinclairFlag,
+ kScoringUsedCardBombFlag,
+ kScoringShieldedCardBombFlag,
+ kScoringStunnedSinclairFlag,
+ kScoringDisarmedNukeFlag,
+
+ kScoringThrewBreakerFlag,
+ kScoringExtendedBridgeFlag,
+ kScoringGotHistoricalLogFlag,
+ kScoringFinishedPrehistoricFlag,
+
+ kScoringThrownByRobotFlag,
+ kScoringGotMarsCardFlag,
+ kScoringSawMarsKioskFlag,
+ kScoringSawTransportMapFlag,
+ kScoringGotCrowBarFlag,
+ kScoringTurnedOnTransportFlag,
+ kScoringGotOxygenMaskFlag,
+ kScoringAvoidedRobotFlag,
+ kScoringActivatedPlatformFlag,
+ kScoringUsedLiquidNitrogenFlag,
+ kScoringUsedCrowBarFlag,
+ kScoringFoundCardBombFlag,
+ kScoringDisarmedCardBombFlag,
+ kScoringGotCardBombFlag,
+ kScoringThreadedMazeFlag,
+ kScoringThreadedGearRoomFlag,
+ kScoringEnteredShuttleFlag,
+ kScoringEnteredLaunchTubeFlag,
+ kScoringStoppedRobotsShuttleFlag,
+ kScoringGotMarsOpMemChipFlag,
+ kScoringFinishedMarsFlag,
+
+ kScoringSawSecurityMonitorFlag,
+ kScoringFilledOxygenCanisterFlag,
+ kScoringFilledArgonCanisterFlag,
+ kScoringSawUnconsciousOperatorFlag,
+ kScoringWentThroughPressureDoorFlag,
+ kScoringPreppedSubFlag,
+ kScoringEnteredSubFlag,
+ kScoringExitedSubFlag,
+ kScoringSawRobotAt54NorthFlag,
+ kScoringPlayedWithClawFlag,
+ kScoringUsedRetinalChipFlag,
+ kScoringFinishedGlobeGameFlag,
+ kScoringStoppedNoradRobotFlag,
+ kScoringGotNoradOpMemChipFlag,
+ kScoringFinishedNoradFlag,
+
+ kScoringRemovedDartFlag,
+ kScoringAnalyzedDartFlag,
+ kScoringBuiltAntidoteFlag,
+ kScoringGotSinclairKeyFlag,
+ kScoringGotArgonCanisterFlag,
+ kScoringGotNitrogenCanisterFlag,
+ kScoringPlayedWithMessagesFlag,
+ kScoringSawMorphExperimentFlag,
+ kScoringEnteredSinclairOfficeFlag,
+ kScoringSawBrochureFlag,
+ kScoringSawSinclairEntry1Flag,
+ kScoringSawSinclairEntry2Flag,
+ kScoringSawSinclairEntry3Flag,
+ kScoringSawWSCDirectoryFlag,
+ kScoringUsedCrowBarInWSCFlag,
+ kScoringFinishedPlasmaDodgeFlag,
+ kScoringOpenedCatwalkFlag,
+ kScoringStoppedWSCRobotFlag,
+ kScoringGotWSCOpMemChipFlag,
+ kScoringFinishedWSCFlag,
+
+ kScoringMarsGandhiFlag,
+ kScoringNoradGandhiFlag,
+ kScoringWSCGandhiFlag,
+
+ kNumScoringFlags
+};
+
+enum {
+ kCaldoriaSeenPullbackFlag,
+ kCaldoriaMadeOJFlag,
+ kCaldoriaWokenUpFlag,
+ kCaldoriaDidRecalibrationFlag,
+ kCaldoriaSeenSinclairInElevatorFlag,
+ kCaldoriaINNAnnouncingFlag,
+ kCaldoriaSeenINNFlag,
+ kCaldoriaSeenMessagesFlag,
+ kCaldoriaSinclairShotFlag,
+ kCaldoriaBombDisarmedFlag,
+ kCaldoriaRoofDoorOpenFlag,
+ kCaldoriaDoneHygieneFlag,
+ kCaldoriaSawVoiceAnalysisFlag,
+ kCaldoriaDoorBombedFlag,
+ kCaldoriaGunAimedFlag,
+ kNumCaldoriaFlags
+};
+
+enum {
+ kCaldoriaNoFuseRunning,
+ kCaldoriaDoorBombFuseRunning,
+ kCaldoriaSinclairFuseRunning
+};
+
+enum {
+ kTSAIDedAtDoorFlag,
+ kTSA0BZoomedInFlag,
+ kTSAFrontDoorUnlockedOutsideFlag,
+ kTSAFrontDoorUnlockedInsideFlag,
+ kTSASeenRobotGreetingFlag,
+ kTSASeenTheoryFlag,
+ kTSASeenBackgroundFlag,
+ kTSASeenProcedureFlag,
+ kTSASeenAgent3AtDoorFlag,
+ kTSACommandCenterLockedFlag,
+ kTSASeenCaldoriaNormalFlag,
+ kTSASeenCaldoriaAlteredFlag,
+ kTSASeenNoradNormalFlag,
+ kTSASeenNoradAlteredFlag,
+ kTSASeenMarsNormalFlag,
+ kTSASeenMarsAlteredFlag,
+ kTSASeenWSCNormalFlag,
+ kTSASeenWSCAlteredFlag,
+ kTSABiosuitOnFlag,
+ kNumTSAFlags
+};
+
+enum {
+ kPrehistoricTriedToExtendBridgeFlag,
+ kPrehistoricSeenTimeStreamFlag,
+ kPrehistoricSeenFlyer1Flag,
+ kPrehistoricSeenFlyer2Flag,
+ kPrehistoricSeenBridgeZoomFlag,
+ kPrehistoricBreakerThrownFlag,
+ kNumPrehistoricFlags
+};
+
+enum {
+ kNoradSeenTimeStreamFlag,
+ kNoradGassedFlag,
+ kNoradFillingStationOnFlag,
+ kNoradN22MessagePlayedFlag,
+ kNoradArrivedFromSubFlag,
+ kNoradWaitingForLaserFlag,
+ kNoradRetScanGoodFlag,
+ kNoradPlayedGlobeGameFlag,
+ kNoradBeatRobotWithClawFlag,
+ kNoradBeatRobotWithDoorFlag,
+ kNumNoradFlags
+};
+
+enum {
+ kMarsSeenTimeStreamFlag,
+ kMarsHeardUpperPodMessageFlag,
+ kMarsRobotThrownPlayerFlag,
+ kMarsHeardCheckInMessageFlag,
+ kMarsPodAtUpperPlatformFlag,
+ kMarsSeenThermalScanFlag,
+ kMarsArrivedBelowFlag,
+ kMarsSeenRobotAtReactorFlag,
+ kMarsAvoidedReactorRobotFlag,
+ kMarsInAirlockFlag,
+ kMarsAirlockOpenFlag,
+ kMarsMaskOnFillerFlag,
+ kMarsLockFrozenFlag,
+ kMarsLockBrokenFlag,
+ kMarsMazeDoorPair1Flag,
+ kMarsMazeDoorPair2Flag,
+ kMarsMazeDoorPair3Flag,
+ kMarsSawRobotLeaveFlag,
+ kMarsSecurityDownFlag,
+ kMarsHitRobotWithCannonFlag,
+ kMarsReadyForShuttleTransportFlag,
+ kMarsFinishedCanyonChaseFlag,
+ kMarsThreadedMazeFlag,
+ kNumMarsFlags
+};
+
+enum {
+ kWSCSeenTimeStreamFlag,
+ kWSCPoisonedFlag,
+ kWSCAnsweredAboutDartFlag,
+ kWSCRemovedDartFlag,
+ kWSCAnalyzerOnFlag,
+ kWSCDartInAnalyzerFlag,
+ kWSCAnalyzedDartFlag,
+ kWSCSawMorphFlag,
+ kWSCDesignedAntidoteFlag,
+ kWSCPickedUpAntidoteFlag,
+ kWSCOfficeMessagesOpenFlag,
+ kWSCSeenNerdFlag,
+ kWSCHeardPage1Flag,
+ kWSCHeardPage2Flag,
+ kWSCHeardCheckInFlag,
+ kWSCDidPlasmaDodgeFlag,
+ kWSCSeenSinclairLectureFlag,
+ kWSCBeenAtWSC93Flag,
+ kWSCCatwalkDarkFlag,
+ kWSCRobotDeadFlag,
+ kWSCRobotGoneFlag,
+ kNumWSCFlags
+};
+
+class GameStateManager : public Common::Singleton<GameStateManager> {
+public:
+ GameStateManager() { resetGameState(); }
+
+ // Base game state
+ Common::Error writeGameState(Common::WriteStream *stream);
+ Common::Error readGameState(Common::ReadStream *stream);
+
+ void resetGameState();
+
+ void getCurrentLocation(NeighborhoodID &neighborhood, RoomID &room, DirectionConstant &direction);
+ void setCurrentLocation(const NeighborhoodID neighborhood, const RoomID room, const DirectionConstant direction);
+
+ NeighborhoodID getCurrentNeighborhood();
+ void setCurrentNeighborhood(const NeighborhoodID neighborhood);
+ RoomID getCurrentRoom();
+ void setCurrentRoom(const RoomID room);
+ DirectionConstant getCurrentDirection();
+ void setCurrentDirection(const DirectionConstant direction);
+
+ RoomViewID getCurrentRoomAndView();
+
+ void getNextLocation(NeighborhoodID &neighborhood, RoomID &room, DirectionConstant &direction);
+ void setNextLocation(const NeighborhoodID neighborhood, const RoomID room, const DirectionConstant direction);
+
+ NeighborhoodID getNextNeighborhood();
+ void setNextNeighborhood(const NeighborhoodID neighborhood);
+ RoomID getNextRoom();
+ void setNextRoom(const RoomID room);
+ DirectionConstant getNextDirection();
+ void setNextDirection(const DirectionConstant direction);
+
+ void getLastLocation(NeighborhoodID &neighborhood, RoomID &room, DirectionConstant &direction);
+ void setLastLocation(const NeighborhoodID neighborhood, const RoomID room, const DirectionConstant direction);
+
+ NeighborhoodID getLastNeighborhood();
+ void setLastNeighborhood(const NeighborhoodID neighborhood);
+ RoomID getLastRoom();
+ void setLastRoom(const RoomID room);
+ DirectionConstant getLastDirection();
+ void setLastDirection(const DirectionConstant direction);
+
+ RoomViewID getLastRoomAndView();
+
+ void getOpenDoorLocation(RoomID &room, DirectionConstant &direction);
+ void setOpenDoorLocation(const RoomID room, const DirectionConstant direction);
+ RoomID getOpenDoorRoom();
+ void setOpenDoorRoom(const RoomID room);
+ DirectionConstant getOpenDoorDirection();
+ void setOpenDoorDirection(const DirectionConstant direction);
+
+ RoomViewID getDoorOpenRoomAndView();
+
+ bool isCurrentDoorOpen();
+
+ // Pegasus Prime
+
+ // Scoring...
+ // Scoring "Set" functions.
+ // Caldoria/TSA scoring
+ void setScoringSawINN(const bool = true);
+ void setScoringTookShower(const bool = true);
+ void setScoringFixedHair(const bool = true);
+ void setScoringGotKeyCard(const bool = true);
+ void setScoringReadPaper(const bool = true);
+ void setScoringLookThroughTelescope(const bool = true);
+ void setScoringSawCaldoriaKiosk(const bool = true);
+ void setScoringGoToTSA(const bool = true);
+ void setScoringEnterTSA(const bool = true);
+ void setScoringSawBust1(const bool = true);
+ void setScoringSawBust2(const bool = true);
+ void setScoringSawBust3(const bool = true);
+ void setScoringSawBust4(const bool = true);
+ void setScoringSawBust5(const bool = true);
+ void setScoringSawBust6(const bool = true);
+ void setScoringSawTheory(const bool = true);
+ void setScoringSawBackground(const bool = true);
+ void setScoringSawProcedure(const bool = true);
+ void setScoringGotJourneymanKey(const bool = true);
+ void setScoringGotPegasusBiochip(const bool = true);
+ void setScoringGotBiosuit(const bool = true);
+ void setScoringGoToPrehistoric(const bool = true);
+ void setScoringPutLogInReader(const bool = true);
+ void setScoringSawCaldoriaNormal(const bool = true);
+ void setScoringSawCaldoriaAltered(const bool = true);
+ void setScoringSawNoradNormal(const bool = true);
+ void setScoringSawNoradAltered(const bool = true);
+ void setScoringSawMarsNormal(const bool = true);
+ void setScoringSawMarsAltered(const bool = true);
+ void setScoringSawWSCNormal(const bool = true);
+ void setScoringSawWSCAltered(const bool = true);
+ void setScoringWentToReadyRoom2(const bool = true);
+ void setScoringWentAfterSinclair(const bool = true);
+ void setScoringUsedCardBomb(const bool = true);
+ void setScoringShieldedCardBomb(const bool = true);
+ void setScoringStunnedSinclair(const bool = true);
+ void setScoringDisarmedNuke(const bool = true);
+
+ // Prehistoric scoring
+ void setScoringThrewBreaker(const bool = true);
+ void setScoringExtendedBridge(const bool = true);
+ void setScoringGotHistoricalLog(const bool = true);
+ void setScoringFinishedPrehistoric(const bool = true);
+
+ // Mars scoring
+ void setScoringThrownByRobot(const bool = true);
+ void setScoringGotMarsCard(const bool = true);
+ void setScoringSawMarsKiosk(const bool = true);
+ void setScoringSawTransportMap(const bool = true);
+ void setScoringGotCrowBar(const bool = true);
+ void setScoringTurnedOnTransport(const bool = true);
+ void setScoringGotOxygenMask(const bool = true);
+ void setScoringAvoidedRobot(const bool = true);
+ void setScoringActivatedPlatform(const bool = true);
+ void setScoringUsedLiquidNitrogen(const bool = true);
+ void setScoringUsedCrowBar(const bool = true);
+ void setScoringFoundCardBomb(const bool = true);
+ void setScoringDisarmedCardBomb(const bool = true);
+ void setScoringGotCardBomb(const bool = true);
+ void setScoringThreadedMaze(const bool = true);
+ void setScoringThreadedGearRoom(const bool = true);
+ void setScoringEnteredShuttle(const bool = true);
+ void setScoringEnteredLaunchTube(const bool = true);
+ void setScoringStoppedRobotsShuttle(const bool = true);
+ void setScoringGotMarsOpMemChip(const bool = true);
+ void setScoringFinishedMars(const bool = true);
+
+ // Norad scoring
+ void setScoringSawSecurityMonitor(const bool = true);
+ void setScoringFilledOxygenCanister(const bool = true);
+ void setScoringFilledArgonCanister(const bool = true);
+ void setScoringSawUnconsciousOperator(const bool = true);
+ void setScoringWentThroughPressureDoor(const bool = true);
+ void setScoringPreppedSub(const bool = true);
+ void setScoringEnteredSub(const bool = true);
+ void setScoringExitedSub(const bool = true);
+ void setScoringSawRobotAt54North(const bool = true);
+ void setScoringPlayedWithClaw(const bool = true);
+ void setScoringUsedRetinalChip(const bool = true);
+ void setScoringFinishedGlobeGame(const bool = true);
+ void setScoringStoppedNoradRobot(const bool = true);
+ void setScoringGotNoradOpMemChip(const bool = true);
+ void setScoringFinishedNorad(const bool = true);
+
+ // WSC scoring
+ void setScoringRemovedDart(const bool = true);
+ void setScoringAnalyzedDart(const bool = true);
+ void setScoringBuiltAntidote(const bool = true);
+ void setScoringGotSinclairKey(const bool = true);
+ void setScoringGotArgonCanister(const bool = true);
+ void setScoringGotNitrogenCanister(const bool = true);
+ void setScoringPlayedWithMessages(const bool = true);
+ void setScoringSawMorphExperiment(const bool = true);
+ void setScoringEnteredSinclairOffice(const bool = true);
+ void setScoringSawBrochure(const bool = true);
+ void setScoringSawSinclairEntry1(const bool = true);
+ void setScoringSawSinclairEntry2(const bool = true);
+ void setScoringSawSinclairEntry3(const bool = true);
+ void setScoringSawWSCDirectory(const bool = true);
+ void setScoringUsedCrowBarInWSC(const bool = true);
+ void setScoringFinishedPlasmaDodge(const bool = true);
+ void setScoringOpenedCatwalk(const bool = true);
+ void setScoringStoppedWSCRobot(const bool = true);
+ void setScoringGotWSCOpMemChip(const bool = true);
+ void setScoringFinishedWSC(const bool = true);
+
+ // Gandhi scoring
+ void setScoringMarsGandhi(const bool = true);
+ void setScoringNoradGandhi(const bool = true);
+ void setScoringWSCGandhi(const bool = true);
+
+ // Scoring "Get" functions.
+ bool getScoringSawINN();
+ bool getScoringTookShower();
+ bool getScoringFixedHair();
+ bool getScoringGotKeyCard();
+ bool getScoringReadPaper();
+ bool getScoringLookThroughTelescope();
+ bool getScoringSawCaldoriaKiosk();
+ bool getScoringGoToTSA();
+ bool getScoringEnterTSA();
+ bool getScoringSawBust1();
+ bool getScoringSawBust2();
+ bool getScoringSawBust3();
+ bool getScoringSawBust4();
+ bool getScoringSawBust5();
+ bool getScoringSawBust6();
+ bool getScoringSawTheory();
+ bool getScoringSawBackground();
+ bool getScoringSawProcedure();
+ bool getScoringGotJourneymanKey();
+ bool getScoringGotPegasusBiochip();
+ bool getScoringGotBiosuit();
+ bool getScoringGoToPrehistoric();
+ bool getScoringPutLogInReader();
+ bool getScoringSawCaldoriaNormal();
+ bool getScoringSawCaldoriaAltered();
+ bool getScoringSawNoradNormal();
+ bool getScoringSawNoradAltered();
+ bool getScoringSawMarsNormal();
+ bool getScoringSawMarsAltered();
+ bool getScoringSawWSCNormal();
+ bool getScoringSawWSCAltered();
+ bool getScoringWentToReadyRoom2();
+ bool getScoringWentAfterSinclair();
+ bool getScoringUsedCardBomb();
+ bool getScoringShieldedCardBomb();
+ bool getScoringStunnedSinclair();
+ bool getScoringDisarmedNuke();
+ bool getScoringThrewBreaker();
+ bool getScoringExtendedBridge();
+ bool getScoringGotHistoricalLog();
+ bool getScoringFinishedPrehistoric();
+ bool getScoringThrownByRobot();
+ bool getScoringGotMarsCard();
+ bool getScoringSawMarsKiosk();
+ bool getScoringSawTransportMap();
+ bool getScoringGotCrowBar();
+ bool getScoringTurnedOnTransport();
+ bool getScoringGotOxygenMask();
+ bool getScoringAvoidedRobot();
+ bool getScoringActivatedPlatform();
+ bool getScoringUsedLiquidNitrogen();
+ bool getScoringUsedCrowBar();
+ bool getScoringFoundCardBomb();
+ bool getScoringDisarmedCardBomb();
+ bool getScoringGotCardBomb();
+ bool getScoringThreadedMaze();
+ bool getScoringThreadedGearRoom();
+ bool getScoringEnteredShuttle();
+ bool getScoringEnteredLaunchTube();
+ bool getScoringStoppedRobotsShuttle();
+ bool getScoringGotMarsOpMemChip();
+ bool getScoringFinishedMars();
+ bool getScoringSawSecurityMonitor();
+ bool getScoringFilledOxygenCanister();
+ bool getScoringFilledArgonCanister();
+ bool getScoringSawUnconsciousOperator();
+ bool getScoringWentThroughPressureDoor();
+ bool getScoringPreppedSub();
+ bool getScoringEnteredSub();
+ bool getScoringExitedSub();
+ bool getScoringSawRobotAt54North();
+ bool getScoringPlayedWithClaw();
+ bool getScoringUsedRetinalChip();
+ bool getScoringFinishedGlobeGame();
+ bool getScoringStoppedNoradRobot();
+ bool getScoringGotNoradOpMemChip();
+ bool getScoringFinishedNorad();
+ bool getScoringRemovedDart();
+ bool getScoringAnalyzedDart();
+ bool getScoringBuiltAntidote();
+ bool getScoringGotSinclairKey();
+ bool getScoringGotArgonCanister();
+ bool getScoringGotNitrogenCanister();
+ bool getScoringPlayedWithMessages();
+ bool getScoringSawMorphExperiment();
+ bool getScoringEnteredSinclairOffice();
+ bool getScoringSawBrochure();
+ bool getScoringSawSinclairEntry1();
+ bool getScoringSawSinclairEntry2();
+ bool getScoringSawSinclairEntry3();
+ bool getScoringSawWSCDirectory();
+ bool getScoringUsedCrowBarInWSC();
+ bool getScoringFinishedPlasmaDodge();
+ bool getScoringOpenedCatwalk();
+ bool getScoringStoppedWSCRobot();
+ bool getScoringGotWSCOpMemChip();
+ bool getScoringFinishedWSC();
+ bool getScoringMarsGandhi();
+ bool getScoringNoradGandhi();
+ bool getScoringWSCGandhi();
+
+ GameScoreType getCaldoriaTSAScore();
+ GameScoreType getPrehistoricScore();
+ GameScoreType getMarsScore();
+ GameScoreType getNoradScore();
+ GameScoreType getWSCScore();
+ GameScoreType getGandhiScore();
+ GameScoreType getTotalScore();
+
+ void writeCaldoriaState(Common::WriteStream *stream);
+ void readCaldoriaState(Common::ReadStream *stream);
+ void resetCaldoriaState();
+
+ void writeTSAState(Common::WriteStream *stream);
+ void readTSAState(Common::ReadStream *stream);
+ void resetTSAState();
+
+ void writePrehistoricState(Common::WriteStream *stream);
+ void readPrehistoricState(Common::ReadStream *stream);
+ void resetPrehistoricState();
+
+ void writeNoradState(Common::WriteStream *stream);
+ void readNoradState(Common::ReadStream *stream);
+ void resetNoradState();
+
+ void writeMarsState(Common::WriteStream *stream);
+ void readMarsState(Common::ReadStream *stream);
+ void resetMarsState();
+
+ void writeWSCState(Common::WriteStream *stream);
+ void readWSCState(Common::ReadStream *stream);
+ void resetWSCState();
+
+ // Globals.
+ void setWalkthroughMode(bool);
+ bool getWalkthroughMode();
+ void setShieldOn(bool);
+ bool getShieldOn();
+ void setEasterEgg(bool);
+ bool getEasterEgg();
+ void setBeenToWSC(bool value);
+ bool getBeenToWSC();
+ void setBeenToMars(bool value);
+ bool getBeenToMars();
+ void setBeenToNorad(bool value);
+ bool getBeenToNorad();
+ void setWSCFinished(bool);
+ bool getWSCFinished();
+ void setMarsFinished(bool);
+ bool getMarsFinished();
+ void setNoradFinished(bool);
+ bool getNoradFinished();
+ bool allTimeZonesFinished();
+ void setTakenItemID(ItemID, bool);
+ bool isTakenItemID(ItemID);
+ void setTakenItem(Item *, bool);
+ bool isTakenItem(Item *);
+
+ // Caldoria
+ void setCaldoriaFuseTimeLimit(const TimeValue);
+ TimeValue getCaldoriaFuseTimeLimit();
+ void setCaldoriaSeenPullback(bool);
+ bool getCaldoriaSeenPullback();
+ void setCaldoriaMadeOJ(bool);
+ bool getCaldoriaMadeOJ();
+ void setCaldoriaWokenUp(bool);
+ bool getCaldoriaWokenUp();
+ void setCaldoriaDidRecalibration(bool);
+ bool getCaldoriaDidRecalibration();
+ void setCaldoriaSeenSinclairInElevator(bool);
+ bool getCaldoriaSeenSinclairInElevator();
+ void setCaldoriaINNAnnouncing(bool);
+ bool getCaldoriaINNAnnouncing();
+ void setCaldoriaSeenINN(bool);
+ bool getCaldoriaSeenINN();
+ void setCaldoriaSeenMessages(bool);
+ bool getCaldoriaSeenMessages();
+ void setCaldoriaSinclairShot(bool);
+ bool getCaldoriaSinclairShot();
+ void setCaldoriaBombDisarmed(bool);
+ bool getCaldoriaBombDisarmed();
+ void setCaldoriaRoofDoorOpen(bool);
+ bool getCaldoriaRoofDoorOpen();
+ void setCaldoriaDoneHygiene(bool);
+ bool getCaldoriaDoneHygiene();
+ void setCaldoriaSawVoiceAnalysis(bool);
+ bool getCaldoriaSawVoiceAnalysis();
+ void setCaldoriaDoorBombed(bool);
+ bool getCaldoriaDoorBombed();
+ void setCaldoriaGunAimed(bool);
+ bool getCaldoriaGunAimed();
+
+ // TSA
+ void setRipTimerTime(TimeValue);
+ TimeValue getRipTimerTime();
+ void setTSAFuseTimeLimit(TimeValue);
+ TimeValue getTSAFuseTimeLimit();
+ void setT0BMonitorMode(byte);
+ byte getT0BMonitorMode();
+ void setTSAState(byte);
+ byte getTSAState();
+ void setT0BMonitorStart(TimeValue);
+ TimeValue getT0BMonitorStart();
+ void setTSAIDedAtDoor(bool);
+ bool getTSAIDedAtDoor();
+ void setTSA0BZoomedIn(bool);
+ bool getTSA0BZoomedIn();
+ void setTSAFrontDoorUnlockedOutside(bool);
+ bool getTSAFrontDoorUnlockedOutside();
+ void setTSAFrontDoorUnlockedInside(bool);
+ bool getTSAFrontDoorUnlockedInside();
+ void setTSASeenRobotGreeting(bool);
+ bool getTSASeenRobotGreeting();
+ void setTSASeenTheory(bool);
+ bool getTSASeenTheory();
+ void setTSASeenBackground(bool);
+ bool getTSASeenBackground();
+ void setTSASeenProcedure(bool);
+ bool getTSASeenProcedure();
+ void setTSASeenAgent3AtDoor(bool);
+ bool getTSASeenAgent3AtDoor();
+ void setTSACommandCenterLocked(bool);
+ bool getTSACommandCenterLocked();
+ void setTSASeenCaldoriaNormal(bool);
+ bool getTSASeenCaldoriaNormal();
+ void setTSASeenCaldoriaAltered(bool);
+ bool getTSASeenCaldoriaAltered();
+ void setTSASeenNoradNormal(bool);
+ bool getTSASeenNoradNormal();
+ void setTSASeenNoradAltered(bool);
+ bool getTSASeenNoradAltered();
+ void setTSASeenMarsNormal(bool);
+ bool getTSASeenMarsNormal();
+ void setTSASeenMarsAltered(bool);
+ bool getTSASeenMarsAltered();
+ void setTSASeenWSCNormal(bool);
+ bool getTSASeenWSCNormal();
+ void setTSASeenWSCAltered(bool);
+ bool getTSASeenWSCAltered();
+ void setTSABiosuitOn(bool);
+ bool getTSABiosuitOn();
+
+ // Prehistoric
+ void setPrehistoricTriedToExtendBridge(bool);
+ bool getPrehistoricTriedToExtendBridge();
+ void setPrehistoricSeenTimeStream(bool);
+ bool getPrehistoricSeenTimeStream();
+ void setPrehistoricSeenFlyer1(bool);
+ bool getPrehistoricSeenFlyer1();
+ void setPrehistoricSeenFlyer2(bool);
+ bool getPrehistoricSeenFlyer2();
+ void setPrehistoricSeenBridgeZoom(bool);
+ bool getPrehistoricSeenBridgeZoom();
+ void setPrehistoricBreakerThrown(bool);
+ bool getPrehistoricBreakerThrown();
+
+ // Norad
+ void setNoradSeenTimeStream(bool);
+ bool getNoradSeenTimeStream();
+ void setNoradGassed(bool);
+ bool getNoradGassed();
+ void setNoradFillingStationOn(bool);
+ bool getNoradFillingStationOn();
+ void setNoradN22MessagePlayed(bool);
+ bool getNoradN22MessagePlayed();
+ void setNoradPlayedGlobeGame(bool);
+ bool getNoradPlayedGlobeGame();
+ void setNoradBeatRobotWithClaw(bool);
+ bool getNoradBeatRobotWithClaw();
+ void setNoradBeatRobotWithDoor(bool);
+ bool getNoradBeatRobotWithDoor();
+ void setNoradRetScanGood(bool);
+ bool getNoradRetScanGood();
+ void setNoradWaitingForLaser(bool);
+ bool getNoradWaitingForLaser();
+ void setNoradSubRoomPressure(uint16);
+ uint16 getNoradSubRoomPressure();
+ void setNoradSubPrepState(NoradSubPrepState);
+ NoradSubPrepState getNoradSubPrepState();
+ void setNoradArrivedFromSub(bool);
+ bool getNoradArrivedFromSub();
+
+ // Mars
+ void setMarsSeenTimeStream(bool);
+ bool getMarsSeenTimeStream();
+ void setMarsHeardUpperPodMessage(bool);
+ bool getMarsHeardUpperPodMessage();
+ void setMarsRobotThrownPlayer(bool);
+ bool getMarsRobotThrownPlayer();
+ void setMarsHeardCheckInMessage(bool);
+ bool getMarsHeardCheckInMessage();
+ void setMarsPodAtUpperPlatform(bool);
+ bool getMarsPodAtUpperPlatform();
+ void setMarsSeenThermalScan(bool);
+ bool getMarsSeenThermalScan();
+ void setMarsArrivedBelow(bool);
+ bool getMarsArrivedBelow();
+ void setMarsSeenRobotAtReactor(bool);
+ bool getMarsSeenRobotAtReactor();
+ void setMarsAvoidedReactorRobot(bool);
+ bool getMarsAvoidedReactorRobot();
+ void setMarsInAirlock(bool);
+ bool getMarsInAirlock();
+ void setMarsAirlockOpen(bool);
+ bool getMarsAirlockOpen();
+ void setMarsMaskOnFiller(bool);
+ bool getMarsMaskOnFiller();
+ void setMarsLockFrozen(bool);
+ bool getMarsLockFrozen();
+ void setMarsLockBroken(bool);
+ bool getMarsLockBroken();
+ void setMarsMazeDoorPair1(bool);
+ bool getMarsMazeDoorPair1();
+ void setMarsMazeDoorPair2(bool);
+ bool getMarsMazeDoorPair2();
+ void setMarsMazeDoorPair3(bool);
+ bool getMarsMazeDoorPair3();
+ void setMarsSawRobotLeave(bool);
+ bool getMarsSawRobotLeave();
+ void setMarsSecurityDown(bool);
+ bool getMarsSecurityDown();
+ void setMarsFinishedCanyonChase(bool);
+ bool getMarsFinishedCanyonChase();
+ void setMarsThreadedMaze(bool);
+ bool getMarsThreadedMaze();
+ void setMarsHitRobotWithCannon(bool);
+ bool getMarsHitRobotWithCannon();
+ void setMarsReadyForShuttleTransport(bool);
+ bool getMarsReadyForShuttleTransport();
+
+ // WSC
+ void setWSCSeenTimeStream(bool);
+ bool getWSCSeenTimeStream();
+ void setWSCPoisoned(bool);
+ bool getWSCPoisoned();
+ void setWSCAnsweredAboutDart(bool);
+ bool getWSCAnsweredAboutDart();
+ void setWSCRemovedDart(bool);
+ bool getWSCRemovedDart();
+ void setWSCAnalyzerOn(bool);
+ bool getWSCAnalyzerOn();
+ void setWSCDartInAnalyzer(bool);
+ bool getWSCDartInAnalyzer();
+ void setWSCAnalyzedDart(bool);
+ bool getWSCAnalyzedDart();
+ void setWSCSawMorph(bool);
+ bool getWSCSawMorph();
+ void setWSCDesignedAntidote(bool);
+ bool getWSCDesignedAntidote();
+ void setWSCPickedUpAntidote(bool);
+ bool getWSCPickedUpAntidote();
+ void setWSCOfficeMessagesOpen(bool);
+ bool getWSCOfficeMessagesOpen();
+ void setWSCSeenNerd(bool);
+ bool getWSCSeenNerd();
+ void setWSCHeardPage1(bool);
+ bool getWSCHeardPage1();
+ void setWSCHeardPage2(bool);
+ bool getWSCHeardPage2();
+ void setWSCHeardCheckIn(bool);
+ bool getWSCHeardCheckIn();
+ void setWSCDidPlasmaDodge(bool);
+ bool getWSCDidPlasmaDodge();
+ void setWSCSeenSinclairLecture(bool);
+ bool getWSCSeenSinclairLecture();
+ void setWSCBeenAtWSC93(bool);
+ bool getWSCBeenAtWSC93();
+ void setWSCCatwalkDark(bool);
+ bool getWSCCatwalkDark();
+ void setWSCRobotDead(bool);
+ bool getWSCRobotDead();
+ void setWSCRobotGone(bool);
+ bool getWSCRobotGone();
+
+protected:
+ friend class Common::Singleton<SingletonBaseType>;
+
+private:
+ // Base
+ NeighborhoodID _currentNeighborhood;
+ RoomID _currentRoom;
+ DirectionConstant _currentDirection;
+ NeighborhoodID _nexNeighborhoodID;
+ RoomID _nextRoomID;
+ DirectionConstant _nextDirection;
+ NeighborhoodID _lastNeighborhood;
+ RoomID _lastRoom;
+ DirectionConstant _lastDirection;
+ RoomID _openDoorRoom;
+ DirectionConstant _openDoorDirection;
+
+ // Pegasus Prime
+ FlagsArray<byte, kNumGlobalFlags> _globalFlags;
+ FlagsArray<byte, kNumScoringFlags> _scoringFlags;
+ FlagsArray<uint32, kNumItems> _itemTakenFlags;
+
+ FlagsArray<byte, kNumCaldoriaFlags> _caldoriaFlags;
+ TimeValue _caldoriaFuseTimeLimit;
+
+ TimeValue _TSARipTimerTime;
+ TimeValue _TSAFuseTimeLimit;
+ byte _TSAState;
+ byte _T0BMonitorMode;
+ TimeValue _T0BMonitorStart;
+ FlagsArray<byte, kNumTSAFlags> _TSAFlags;
+
+ FlagsArray<byte, kNumPrehistoricFlags> _prehistoricFlags;
+
+ FlagsArray<byte, kNumNoradFlags> _noradFlags;
+ uint16 _noradSubRoomPressure;
+ NoradSubPrepState _noradSubPrepState;
+
+ FlagsArray<byte, kNumMarsFlags> _marsFlags;
+
+ FlagsArray<byte, kNumWSCFlags> _WSCFlags;
+};
+
+} // End of namespace Pegasus
+
+#define GameState (::Pegasus::GameStateManager::instance())
+
+#endif
diff --git a/engines/pegasus/graphics.cpp b/engines/pegasus/graphics.cpp
new file mode 100644
index 0000000000..8dbd678809
--- /dev/null
+++ b/engines/pegasus/graphics.cpp
@@ -0,0 +1,346 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/events.h"
+#include "common/file.h"
+#include "common/textconsole.h"
+#include "engines/util.h"
+
+#include "pegasus/elements.h"
+#include "pegasus/graphics.h"
+#include "pegasus/transition.h"
+
+namespace Pegasus {
+
+GraphicsManager::GraphicsManager(PegasusEngine *vm) : _vm(vm) {
+ initGraphics(640, 480, true, NULL);
+
+ if (_vm->_system->getScreenFormat().bytesPerPixel == 1)
+ error("No true color mode available");
+
+ _backLayer = kMinAvailableOrder;
+ _frontLayer = kMaxAvailableOrder;
+ _firstDisplayElement = _lastDisplayElement = 0;
+ _workArea.create(640, 480, _vm->_system->getScreenFormat());
+ _modifiedScreen = false;
+ _curSurface = &_workArea;
+ _erase = false;
+ _updatesEnabled = true;
+ _screenFader = new ScreenFader();
+}
+
+GraphicsManager::~GraphicsManager() {
+ _workArea.free();
+ delete _screenFader;
+}
+
+void GraphicsManager::invalRect(const Common::Rect &rect) {
+ // We're using a simpler algorithm for dirty rect handling than the original
+ // The original was way too overcomplicated for what we need here now.
+
+ if (_dirtyRect.width() == 0 || _dirtyRect.height() == 0) {
+ // We have no dirty rect, so this is now our dirty rect
+ _dirtyRect = rect;
+ } else {
+ // Expand our dirty rect to include rect
+ _dirtyRect.extend(rect);
+ }
+
+ // Sanity check: clip our rect to the screen
+ _dirtyRect.right = MIN<int>(640, _dirtyRect.right);
+ _dirtyRect.bottom = MIN<int>(480, _dirtyRect.bottom);
+}
+
+void GraphicsManager::addDisplayElement(DisplayElement *newElement) {
+ newElement->_elementOrder = CLIP<int>(newElement->_elementOrder, kMinAvailableOrder, kMaxAvailableOrder);
+
+ if (_firstDisplayElement) {
+ DisplayElement *runner = _firstDisplayElement;
+ DisplayElement *lastRunner = 0;
+
+ // Search for first element whose display order is greater than
+ // the new element's and add the new element just before it.
+ while (runner) {
+ if (newElement->_elementOrder < runner->_elementOrder) {
+ if (lastRunner) {
+ lastRunner->_nextElement = newElement;
+ newElement->_nextElement = runner;
+ } else {
+ newElement->_nextElement = _firstDisplayElement;
+ _firstDisplayElement = newElement;
+ }
+ break;
+ }
+ lastRunner = runner;
+ runner = runner->_nextElement;
+ }
+
+ // If got here and runner == NULL, we ran through the whole list without
+ // inserting, so add at the end.
+ if (!runner) {
+ _lastDisplayElement->_nextElement = newElement;
+ _lastDisplayElement = newElement;
+ }
+ } else {
+ _firstDisplayElement = newElement;
+ _lastDisplayElement = newElement;
+ }
+
+ newElement->_elementIsDisplaying = true;
+}
+
+void GraphicsManager::removeDisplayElement(DisplayElement *oldElement) {
+ if (!_firstDisplayElement)
+ return;
+
+ if (oldElement == _firstDisplayElement) {
+ if (oldElement == _lastDisplayElement) {
+ _firstDisplayElement = 0;
+ _lastDisplayElement = 0;
+ } else {
+ _firstDisplayElement = oldElement->_nextElement;
+ }
+
+ invalRect(oldElement->_bounds);
+ } else {
+ // Scan list for element.
+ // If we get here, we know that the list has at least one item, and it
+ // is not the first item, so we can skip it.
+ DisplayElement *runner = _firstDisplayElement->_nextElement;
+ DisplayElement *lastRunner = _firstDisplayElement;
+
+ while (runner) {
+ if (runner == oldElement) {
+ lastRunner->_nextElement = runner->_nextElement;
+
+ if (oldElement == _lastDisplayElement)
+ _lastDisplayElement = lastRunner;
+
+ invalRect(oldElement->_bounds);
+ break;
+ }
+
+ lastRunner = runner;
+ runner = runner->_nextElement;
+ }
+ }
+
+ oldElement->_nextElement = 0;
+ oldElement->_elementIsDisplaying = false;
+}
+
+void GraphicsManager::updateDisplay() {
+ bool screenDirty = false;
+
+ if (!_dirtyRect.isEmpty()) {
+ // Fill the dirty area with black if erase mode is enabled
+ if (_erase)
+ _workArea.fillRect(_dirtyRect, _workArea.format.RGBToColor(0, 0, 0));
+
+ for (DisplayElement *runner = _firstDisplayElement; runner != 0; runner = runner->_nextElement) {
+ Common::Rect bounds;
+ runner->getBounds(bounds);
+
+ // TODO: Better logic; it does a bit more work than it probably needs to
+ // but it should work fine for now.
+ if (bounds.intersects(_dirtyRect) && runner->validToDraw(_backLayer, _frontLayer)) {
+ runner->draw(bounds);
+ screenDirty = true;
+ }
+ }
+
+ // Copy only the dirty rect to the screen
+ if (screenDirty)
+ g_system->copyRectToScreen((byte *)_workArea.getBasePtr(_dirtyRect.left, _dirtyRect.top), _workArea.pitch, _dirtyRect.left, _dirtyRect.top, _dirtyRect.width(), _dirtyRect.height());
+
+ // Clear the dirty rect
+ _dirtyRect = Common::Rect();
+ }
+
+ if (_updatesEnabled && (screenDirty || _modifiedScreen))
+ g_system->updateScreen();
+
+ _modifiedScreen = false;
+}
+
+void GraphicsManager::clearScreen() {
+ Graphics::Surface *screen = g_system->lockScreen();
+ screen->fillRect(Common::Rect(0, 0, 640, 480), g_system->getScreenFormat().RGBToColor(0, 0, 0));
+ g_system->unlockScreen();
+ _modifiedScreen = true;
+}
+
+DisplayElement *GraphicsManager::findDisplayElement(const DisplayElementID id) {
+ DisplayElement *runner = _firstDisplayElement;
+
+ while (runner) {
+ if (runner->getObjectID() == id)
+ return runner;
+ runner = runner->_nextElement;
+ }
+
+ return 0;
+}
+
+void GraphicsManager::doFadeOutSync(const TimeValue time, const TimeScale scale, bool isBlack) {
+ _updatesEnabled = false;
+ _screenFader->doFadeOutSync(time, scale, isBlack);
+}
+
+void GraphicsManager::doFadeInSync(const TimeValue time, const TimeScale scale, bool isBlack) {
+ _screenFader->doFadeInSync(time, scale, isBlack);
+ _updatesEnabled = true;
+}
+
+void GraphicsManager::markCursorAsDirty() {
+ _modifiedScreen = true;
+}
+
+void GraphicsManager::newShakePoint(int32 index1, int32 index2, int32 maxRadius) {
+ int32 index3 = (index1 + index2) >> 1;
+
+ if (maxRadius == 0) {
+ _shakeOffsets[index3].x = ((_shakeOffsets[index1].x + _shakeOffsets[index2].x) >> 1);
+ _shakeOffsets[index3].y = ((_shakeOffsets[index1].y + _shakeOffsets[index2].y) >> 1);
+ } else {
+ double angle = (int32)(_vm->getRandomNumber(360 - 1) * 3.1415926535 / 180);
+ int32 radius = maxRadius;
+ _shakeOffsets[index3].x = (int32)(((_shakeOffsets[index1].x + _shakeOffsets[index2].x) >> 1) +
+ cos(angle) / 2 * radius);
+ _shakeOffsets[index3].y = (int32)(((_shakeOffsets[index1].y + _shakeOffsets[index2].y) >> 1) +
+ sin(angle) * radius);
+ }
+
+ if (index1 < index3 - 1)
+ newShakePoint(index1, index3, maxRadius * 2 / 3);
+
+ if (index3 < index2 - 1)
+ newShakePoint(index3, index2, maxRadius * 2 / 3);
+}
+
+void GraphicsManager::shakeTheWorld(TimeValue duration, TimeScale scale) {
+ if (duration == 0 || scale == 0)
+ return;
+
+ _shakeOffsets[0].x = 0;
+ _shakeOffsets[0].y = 0;
+ _shakeOffsets[(kMaxShakeOffsets - 1) / 4].x = 0;
+ _shakeOffsets[(kMaxShakeOffsets - 1) / 4].y = 0;
+ _shakeOffsets[(kMaxShakeOffsets - 1) / 2].x = 0;
+ _shakeOffsets[(kMaxShakeOffsets - 1) / 2].y = 0;
+ _shakeOffsets[(kMaxShakeOffsets - 1) * 3 / 4].x = 0;
+ _shakeOffsets[(kMaxShakeOffsets - 1) * 3 / 4].y = 0;
+ _shakeOffsets[kMaxShakeOffsets - 1].x = 0;
+ _shakeOffsets[kMaxShakeOffsets - 1].y = 0;
+
+ newShakePoint(0, (kMaxShakeOffsets - 1) / 4, 8);
+ newShakePoint((kMaxShakeOffsets - 1) / 4, (kMaxShakeOffsets - 1) / 2, 6);
+ newShakePoint((kMaxShakeOffsets - 1) / 2, (kMaxShakeOffsets - 1) * 3 / 4, 4);
+ newShakePoint((kMaxShakeOffsets - 1) * 3 / 4, kMaxShakeOffsets - 1, 3);
+
+ Common::Point lastOffset(0, 0);
+
+ // Store the current screen for later use
+ Graphics::Surface oldScreen;
+ Graphics::Surface *curScreen = g_system->lockScreen();
+ oldScreen.copyFrom(*curScreen);
+ g_system->unlockScreen();
+
+ // Convert to millis
+ duration = duration * 1000 / scale;
+
+ uint32 startTime = g_system->getMillis();
+
+ while (g_system->getMillis() < startTime + duration) {
+ Common::Point thisOffset = _shakeOffsets[(g_system->getMillis() - startTime) * (kMaxShakeOffsets - 1) / duration];
+ if (thisOffset != lastOffset) {
+ // Fill the screen with black
+ Graphics::Surface *screen = g_system->lockScreen();
+ screen->fillRect(Common::Rect(0, 0, 640, 480), g_system->getScreenFormat().RGBToColor(0, 0, 0));
+ g_system->unlockScreen();
+
+ // Calculate the src/dst offsets and the width/height
+ int32 srcOffsetX, dstOffsetX, width;
+
+ if (thisOffset.x > 0) {
+ srcOffsetX = 0;
+ dstOffsetX = thisOffset.x;
+ width = 640 - dstOffsetX;
+ } else {
+ srcOffsetX = -thisOffset.x;
+ dstOffsetX = 0;
+ width = 640 - srcOffsetX;
+ }
+
+ int32 srcOffsetY, dstOffsetY, height;
+
+ if (thisOffset.y > 0) {
+ srcOffsetY = 0;
+ dstOffsetY = thisOffset.y;
+ height = 480 - dstOffsetY;
+ } else {
+ srcOffsetY = -thisOffset.y;
+ dstOffsetY = 0;
+ height = 480 - srcOffsetY;
+ }
+
+ // Now copy to the screen
+ g_system->copyRectToScreen((byte *)oldScreen.getBasePtr(srcOffsetX, srcOffsetY), oldScreen.pitch,
+ dstOffsetX, dstOffsetY, width, height);
+ g_system->updateScreen();
+
+ lastOffset = thisOffset;
+ }
+
+ g_system->delayMillis(10);
+ }
+
+ if (lastOffset.x != 0 || lastOffset.y != 0) {
+ g_system->copyRectToScreen((byte *)oldScreen.pixels, oldScreen.pitch, 0, 0, 640, 480);
+ g_system->updateScreen();
+ }
+
+ oldScreen.free();
+}
+
+void GraphicsManager::enableErase() {
+ _erase = true;
+}
+
+void GraphicsManager::disableErase() {
+ _erase = false;
+}
+
+void GraphicsManager::enableUpdates() {
+ _updatesEnabled = true;
+ _screenFader->setFaderValue(100);
+}
+
+void GraphicsManager::disableUpdates() {
+ _updatesEnabled = false;
+ _screenFader->setFaderValue(0);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/graphics.h b/engines/pegasus/graphics.h
new file mode 100644
index 0000000000..fcdf1c9e78
--- /dev/null
+++ b/engines/pegasus/graphics.h
@@ -0,0 +1,95 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_GRAPHICS_H
+#define PEGASUS_GRAPHICS_H
+
+#include "common/rect.h"
+#include "common/str.h"
+#include "common/system.h"
+#include "graphics/surface.h"
+
+#include "pegasus/constants.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/util.h"
+
+namespace Pegasus {
+
+class Cursor;
+class DisplayElement;
+class PegasusEngine;
+class ScreenFader;
+
+class GraphicsManager {
+friend class Cursor;
+public:
+ GraphicsManager(PegasusEngine *vm);
+ ~GraphicsManager();
+
+ void addDisplayElement(DisplayElement *element);
+ void removeDisplayElement(DisplayElement *element);
+ void invalRect(const Common::Rect &rect);
+ DisplayOrder getBackOfActiveLayer() const { return _backLayer; }
+ DisplayOrder getFrontOfActiveLayer() const { return _frontLayer; }
+ void updateDisplay();
+ Graphics::Surface *getCurSurface() { return _curSurface; }
+ void setCurSurface(Graphics::Surface *surface) { _curSurface = surface; }
+ Graphics::Surface *getWorkArea() { return &_workArea; }
+ void clearScreen();
+ DisplayElement *findDisplayElement(const DisplayElementID id);
+ void shakeTheWorld(TimeValue time, TimeScale scale);
+ void enableErase();
+ void disableErase();
+ void enableUpdates();
+ void disableUpdates();
+
+ // These default to black
+ void doFadeOutSync(const TimeValue = kOneSecondPerThirtyTicks, const TimeScale = kThirtyTicksPerSecond, bool isBlack = true);
+ void doFadeInSync(const TimeValue = kOneSecondPerThirtyTicks, const TimeScale = kThirtyTicksPerSecond, bool isBlack = true);
+
+protected:
+ void markCursorAsDirty();
+
+private:
+ PegasusEngine *_vm;
+
+ bool _modifiedScreen, _erase;
+ Common::Rect _dirtyRect;
+ DisplayOrder _backLayer, _frontLayer;
+ DisplayElement *_firstDisplayElement, *_lastDisplayElement;
+ Graphics::Surface _workArea, *_curSurface;
+
+ // Shake Shake Shake!
+ static const int kMaxShakeOffsets = 17;
+ Common::Point _shakeOffsets[kMaxShakeOffsets];
+ void newShakePoint(int32 index1, int32 index2, int32 maxRadius);
+
+ bool _updatesEnabled;
+ ScreenFader *_screenFader;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/hotspot.cpp b/engines/pegasus/hotspot.cpp
new file mode 100644
index 0000000000..d8b07a94f4
--- /dev/null
+++ b/engines/pegasus/hotspot.cpp
@@ -0,0 +1,325 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/stream.h"
+
+#include "pegasus/hotspot.h"
+
+namespace Pegasus {
+
+Region::Region(Common::ReadStream *stream) {
+ uint16 length = stream->readUint16BE();
+
+ assert(length >= 10);
+
+ _bounds.top = stream->readUint16BE();
+ _bounds.left = stream->readUint16BE();
+ _bounds.bottom = stream->readUint16BE();
+ _bounds.right = stream->readUint16BE();
+
+ _bounds.debugPrint(0, "Bounds:");
+
+ if (length == 10)
+ return;
+
+ length -= 10;
+
+ while (length > 0) {
+ Vector v;
+ v.y = stream->readUint16BE();
+ length -= 2;
+
+ if (v.y == 0x7fff)
+ break;
+
+ debug(0, "y: %d", v.y);
+
+ // Normalize y to _bounds
+ v.y -= _bounds.top;
+
+ while (length > 0) {
+ Run run;
+ run.start = stream->readUint16BE();
+ length -= 2;
+
+ if (run.start == 0x7fff)
+ break;
+
+ run.end = stream->readUint16BE();
+ length -= 2;
+
+ debug(0, "\t[%d, %d)", run.start, run.end);
+
+ // Normalize to _bounds
+ run.start -= _bounds.left;
+ run.end -= _bounds.left;
+
+ v.push_back(run);
+ }
+
+ _vectors.push_back(v);
+ }
+}
+
+Region::Region(const Common::Rect &rect) {
+ _bounds = rect;
+}
+
+bool Region::pointInRegion(const Common::Point &point) const {
+ if (!_bounds.contains(point))
+ return false;
+
+ bool pixelActive = false;
+
+ // Normalize the points to _bounds
+ uint16 x = point.x - _bounds.left;
+ uint16 y = point.y - _bounds.top;
+
+ for (Common::List<Vector>::const_iterator v = _vectors.begin(); v != _vectors.end(); v++) {
+ if (v->y > y)
+ return pixelActive;
+
+ for (Vector::const_iterator run = v->begin(); run != v->end(); run++) {
+ if (x >= run->start && x < run->end) {
+ pixelActive = !pixelActive;
+ break;
+ }
+ }
+ }
+
+ // the case if the region is just a rect
+ return true;
+}
+
+void Region::moveTo(CoordType h, CoordType v) {
+ _bounds.moveTo(h, v);
+}
+
+void Region::moveTo(const Common::Point &point) {
+ _bounds.moveTo(point);
+}
+
+void Region::translate(CoordType h, CoordType v) {
+ _bounds.translate(h, v);
+}
+
+void Region::translate(const Common::Point &point) {
+ _bounds.translate(point.x, point.y);
+}
+
+void Region::getCenter(CoordType &h, CoordType &v) const {
+ h = (_bounds.left + _bounds.right) / 2;
+ v = (_bounds.top + _bounds.bottom) / 2;
+}
+
+void Region::getCenter(Common::Point &point) const {
+ getCenter(point.x, point.y);
+}
+
+Hotspot::Hotspot(const HotSpotID id) : IDObject(id) {
+ _spotFlags = kNoHotSpotFlags;
+ _spotActive = false;
+}
+
+Hotspot::~Hotspot() {
+}
+
+void Hotspot::setArea(const Common::Rect &area) {
+ _spotArea = Region(area);
+}
+
+void Hotspot::setArea(const CoordType left, const CoordType top, const CoordType right, const CoordType bottom) {
+ _spotArea = Region(Common::Rect(left, top, right, bottom));
+}
+
+void Hotspot::getBoundingBox(Common::Rect &r) const {
+ r = _spotArea.getBoundingBox();
+}
+
+void Hotspot::getCenter(Common::Point &pt) const {
+ _spotArea.getCenter(pt);
+}
+
+void Hotspot::getCenter(CoordType &h, CoordType &v) const {
+ _spotArea.getCenter(h, v);
+}
+
+void Hotspot::setActive() {
+ _spotActive = true;
+}
+
+void Hotspot::setInactive() {
+ _spotActive = false;
+}
+
+void Hotspot::setHotspotFlags(const HotSpotFlags flags) {
+ _spotFlags = flags;
+}
+
+void Hotspot::setMaskedHotspotFlags(const HotSpotFlags flags, const HotSpotFlags mask) {
+ _spotFlags = (_spotFlags & ~mask) | flags;
+}
+
+bool Hotspot::isSpotActive() const {
+ return _spotActive;
+}
+
+void Hotspot::moveSpotTo(const CoordType h, const CoordType v) {
+ _spotArea.moveTo(h, v);
+}
+
+void Hotspot::moveSpotTo(const Common::Point pt) {
+ _spotArea.moveTo(pt);
+}
+
+void Hotspot::moveSpot(const CoordType h, const CoordType v) {
+ _spotArea.translate(h, v);
+}
+
+void Hotspot::moveSpot(const Common::Point pt) {
+ _spotArea.translate(pt.x, pt.y);
+}
+
+bool Hotspot::pointInSpot(const Common::Point where) const {
+ return _spotActive && _spotArea.pointInRegion(where);
+}
+
+HotSpotFlags Hotspot::getHotspotFlags() const {
+ return _spotFlags;
+}
+
+HotspotList::HotspotList() {
+}
+
+HotspotList::~HotspotList() {
+ // TODO: Should this call deleteHotspots()?
+}
+
+void HotspotList::deleteHotspots() {
+ for (HotspotIterator it = begin(); it != end(); it++)
+ delete *it;
+
+ clear();
+}
+
+Hotspot *HotspotList::findHotspot(const Common::Point where) {
+ for (HotspotIterator it = begin(); it != end(); it++)
+ if ((*it)->pointInSpot(where))
+ return *it;
+
+ return 0;
+}
+
+HotSpotID HotspotList::findHotspotID(const Common::Point where) {
+ Hotspot *hotspot = findHotspot(where);
+ return hotspot ? hotspot->getObjectID() : kNoHotSpotID;
+}
+
+Hotspot *HotspotList::findHotspotByID(const HotSpotID id) {
+ for (HotspotIterator it = begin(); it != end(); it++)
+ if ((*it)->getObjectID() == id)
+ return *it;
+
+ return 0;
+}
+
+Hotspot *HotspotList::findHotspotByMask(const HotSpotFlags flags) {
+ for (HotspotIterator it = begin(); it != end(); it++)
+ if (((*it)->getHotspotFlags() & flags) == flags)
+ return *it;
+
+ return 0;
+}
+
+void HotspotList::activateMaskedHotspots(const HotSpotFlags flags) {
+ for (HotspotIterator it = begin(); it != end(); it++)
+ if (flags == kNoHotSpotFlags || ((*it)->getHotspotFlags() & flags) != 0)
+ (*it)->setActive();
+}
+
+void HotspotList::deactivateAllHotspots() {
+ for (HotspotIterator it = begin(); it != end(); it++)
+ (*it)->setInactive();
+}
+
+void HotspotList::deactivateMaskedHotspots(const HotSpotFlags flags) {
+ for (HotspotIterator it = begin(); it != end(); it++)
+ if (((*it)->getHotspotFlags() & flags) != 0)
+ (*it)->setInactive();
+}
+
+void HotspotList::activateOneHotspot(const HotSpotID id) {
+ for (HotspotIterator it = begin(); it != end(); it++) {
+ if ((*it)->getObjectID() == id) {
+ (*it)->setActive();
+ return;
+ }
+ }
+}
+
+void HotspotList::deactivateOneHotspot(const HotSpotID id) {
+ for (HotspotIterator it = begin(); it != end(); it++) {
+ if ((*it)->getObjectID() == id) {
+ (*it)->setInactive();
+ return;
+ }
+ }
+}
+
+void HotspotList::removeOneHotspot(const HotSpotID id) {
+ for (HotspotIterator it = begin(); it != end(); it++) {
+ if ((*it)->getObjectID() == id) {
+ erase(it);
+ return;
+ }
+ }
+}
+
+void HotspotList::removeMaskedHotspots(const HotSpotFlags flags) {
+ if (flags != kNoHotSpotFlags) {
+ for (HotspotIterator it = begin(); it != end(); ) {
+ if (((*it)->getHotspotFlags() & flags) != 0)
+ it = erase(it);
+ else
+ it++;
+ }
+ } else {
+ clear();
+ }
+}
+
+void HotspotList::setHotspotRect(const HotSpotID id, const Common::Rect &r) {
+ Hotspot *hotspot = findHotspotByID(id);
+ if (hotspot)
+ hotspot->setArea(r);
+}
+
+void HotspotList::getHotspotRect(const HotSpotID id, Common::Rect &r) {
+ Hotspot *hotspot = findHotspotByID(id);
+ if (hotspot)
+ hotspot->getBoundingBox(r);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/hotspot.h b/engines/pegasus/hotspot.h
new file mode 100644
index 0000000000..64d3fb19f9
--- /dev/null
+++ b/engines/pegasus/hotspot.h
@@ -0,0 +1,152 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_HOTSPOT_H
+#define PEGASUS_HOTSPOT_H
+
+#include "common/list.h"
+#include "common/rect.h"
+
+#include "pegasus/constants.h"
+#include "pegasus/types.h"
+#include "pegasus/util.h"
+
+/*
+
+ Hot spots combine a pixel area, an ID value and an active flag.
+
+ A point is considered in a hot spot if the point is in the hot spot's pixel area and
+ the active flag is set.
+
+ In addition, hot spots have a 32 bit word of bit flags for filtering use.
+
+*/
+
+namespace Common {
+ class ReadStream;
+}
+
+namespace Pegasus {
+
+// Our implementation of QuickDraw regions
+class Region {
+public:
+ Region() {}
+ Region(Common::ReadStream *stream);
+ Region(const Common::Rect &rect);
+
+ Common::Rect getBoundingBox() const { return _bounds; }
+
+ bool pointInRegion(const Common::Point &point) const;
+
+ void moveTo(CoordType h, CoordType v);
+ void moveTo(const Common::Point &point);
+ void translate(CoordType h, CoordType v);
+ void translate(const Common::Point &point);
+ void getCenter(CoordType &h, CoordType &v) const;
+ void getCenter(Common::Point &point) const;
+
+private:
+ Common::Rect _bounds;
+
+ struct Run {
+ uint16 start, end;
+ };
+
+ class Vector : public Common::List<Run> {
+ public:
+ uint16 y;
+ };
+
+ Common::List<Vector> _vectors;
+};
+
+class Hotspot : public IDObject {
+public:
+ Hotspot(const HotSpotID);
+ virtual ~Hotspot();
+
+ void setArea(const Region &region) { _spotArea = region; }
+ void setArea(const Common::Rect &);
+ void setArea(const CoordType, const CoordType, const CoordType, const CoordType);
+ void getBoundingBox(Common::Rect &) const;
+ void getArea(Region &) const;
+ void getCenter(Common::Point&) const;
+ void getCenter(CoordType&, CoordType&) const;
+
+ void moveSpotTo(const CoordType, const CoordType);
+ void moveSpotTo(const Common::Point);
+ void moveSpot(const CoordType, const CoordType);
+ void moveSpot(const Common::Point);
+
+ bool pointInSpot(const Common::Point) const;
+
+ void setActive();
+ void setInactive();
+ bool isSpotActive() const;
+
+ HotSpotFlags getHotspotFlags() const;
+ void setHotspotFlags(const HotSpotFlags);
+ void setMaskedHotspotFlags(const HotSpotFlags flags, const HotSpotFlags mask);
+
+protected:
+ Region _spotArea;
+ HotSpotFlags _spotFlags;
+ bool _spotActive;
+};
+
+class HotspotList : public Common::List<Hotspot *> {
+public:
+ HotspotList();
+ virtual ~HotspotList();
+
+ void deleteHotspots();
+
+ Hotspot *findHotspot(const Common::Point);
+ HotSpotID findHotspotID(const Common::Point);
+ Hotspot *findHotspotByID(const HotSpotID);
+ Hotspot *findHotspotByMask(const HotSpotFlags);
+
+ void activateMaskedHotspots(const HotSpotFlags = kNoHotSpotFlags);
+ void deactivateAllHotspots();
+ void deactivateMaskedHotspots(const HotSpotFlags);
+
+ void activateOneHotspot(const HotSpotID);
+ void deactivateOneHotspot(const HotSpotID);
+
+ void removeOneHotspot(const HotSpotID);
+ void removeMaskedHotspots(const HotSpotFlags = kNoHotSpotFlags);
+
+ void setHotspotRect(const HotSpotID, const Common::Rect&);
+ void getHotspotRect(const HotSpotID, Common::Rect&);
+};
+
+typedef HotspotList::iterator HotspotIterator;
+
+#define g_allHotspots (((PegasusEngine *)g_engine)->getAllHotspots())
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/input.cpp b/engines/pegasus/input.cpp
new file mode 100644
index 0000000000..b74e4a4c45
--- /dev/null
+++ b/engines/pegasus/input.cpp
@@ -0,0 +1,373 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/events.h"
+#include "common/system.h"
+
+#include "pegasus/cursor.h"
+#include "pegasus/input.h"
+#include "pegasus/pegasus.h"
+
+namespace Common {
+DECLARE_SINGLETON(Pegasus::InputDeviceManager);
+}
+
+namespace Pegasus {
+
+InputDeviceManager::InputDeviceManager() {
+ // Set all keys to "not down"
+ _keyMap[Common::KEYCODE_UP] = false;
+ _keyMap[Common::KEYCODE_KP8] = false;
+ _keyMap[Common::KEYCODE_LEFT] = false;
+ _keyMap[Common::KEYCODE_KP4] = false;
+ _keyMap[Common::KEYCODE_DOWN] = false;
+ _keyMap[Common::KEYCODE_KP5] = false;
+ _keyMap[Common::KEYCODE_RIGHT] = false;
+ _keyMap[Common::KEYCODE_KP6] = false;
+ _keyMap[Common::KEYCODE_RETURN] = false;
+ _keyMap[Common::KEYCODE_SPACE] = false;
+ _keyMap[Common::KEYCODE_t] = false;
+ _keyMap[Common::KEYCODE_KP_EQUALS] = false;
+ _keyMap[Common::KEYCODE_i] = false;
+ _keyMap[Common::KEYCODE_KP_DIVIDE] = false;
+ _keyMap[Common::KEYCODE_q] = false;
+ _keyMap[Common::KEYCODE_ESCAPE] = false;
+ _keyMap[Common::KEYCODE_p] = false;
+ _keyMap[Common::KEYCODE_TILDE] = false;
+ _keyMap[Common::KEYCODE_BACKQUOTE] = false;
+ _keyMap[Common::KEYCODE_NUMLOCK] = false;
+ _keyMap[Common::KEYCODE_BACKSPACE] = false;
+ _keyMap[Common::KEYCODE_KP_MULTIPLY] = false;
+ _keyMap[Common::KEYCODE_LALT] = false;
+ _keyMap[Common::KEYCODE_RALT] = false;
+ _keyMap[Common::KEYCODE_e] = false;
+ _keyMap[Common::KEYCODE_KP_ENTER] = false;
+
+ g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 2, false);
+ _lastRawBits = kAllUpBits;
+ _consoleRequested = false;
+}
+
+InputDeviceManager::~InputDeviceManager() {
+ g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this);
+}
+
+void InputDeviceManager::getInput(Input &input, const InputBits filter) {
+ // Poll for events, but ignore them!
+ // We'll pick them up in notifyEvent()
+ // We do that so that any pollEvent() call can update the variables
+ // (ie. if one uses enter to access the restore menu, we never receive
+ // the key up event, which leads to bad things)
+ // This is to closely emulate what the GetKeys() function did on Mac OS
+ Common::Event event;
+ while (g_system->getEventManager()->pollEvent(event))
+ ;
+
+ // Now create the bitfield
+ InputBits currentBits = 0;
+
+ if (_keyMap[Common::KEYCODE_UP] || _keyMap[Common::KEYCODE_KP8])
+ currentBits |= (kRawButtonDown << kUpButtonShift);
+
+ if (_keyMap[Common::KEYCODE_DOWN] || _keyMap[Common::KEYCODE_KP5])
+ currentBits |= (kRawButtonDown << kDownButtonShift);
+
+ if (_keyMap[Common::KEYCODE_LEFT] || _keyMap[Common::KEYCODE_KP4])
+ currentBits |= (kRawButtonDown << kLeftButtonShift);
+
+ if (_keyMap[Common::KEYCODE_RIGHT] || _keyMap[Common::KEYCODE_KP6])
+ currentBits |= (kRawButtonDown << kRightButtonShift);
+
+ if (_keyMap[Common::KEYCODE_SPACE] || _keyMap[Common::KEYCODE_RETURN] || _keyMap[Common::KEYCODE_KP_ENTER])
+ currentBits |= (kRawButtonDown << kTwoButtonShift);
+
+ if (_keyMap[Common::KEYCODE_t] || _keyMap[Common::KEYCODE_KP_EQUALS])
+ currentBits |= (kRawButtonDown << kThreeButtonShift);
+
+ if (_keyMap[Common::KEYCODE_i] || _keyMap[Common::KEYCODE_KP_DIVIDE])
+ currentBits |= (kRawButtonDown << kFourButtonShift);
+
+ if (_keyMap[Common::KEYCODE_q])
+ currentBits |= (kRawButtonDown << kMod1ButtonShift);
+
+ if (_keyMap[Common::KEYCODE_ESCAPE] || _keyMap[Common::KEYCODE_p])
+ currentBits |= (kRawButtonDown << kMod3ButtonShift);
+
+ if (_keyMap[Common::KEYCODE_TILDE] || _keyMap[Common::KEYCODE_BACKQUOTE] || _keyMap[Common::KEYCODE_NUMLOCK])
+ currentBits |= (kRawButtonDown << kLeftFireButtonShift);
+
+ if (_keyMap[Common::KEYCODE_BACKSPACE] || _keyMap[Common::KEYCODE_KP_MULTIPLY])
+ currentBits |= (kRawButtonDown << kRightFireButtonShift);
+
+ // Update mouse button state
+ // Note that we don't use EVENT_LBUTTONUP/EVENT_LBUTTONDOWN because
+ // they do not show if the button is being held down. We're treating
+ // both mouse buttons as the same for ease of use.
+ if (g_system->getEventManager()->getButtonState() != 0)
+ currentBits |= (kRawButtonDown << kTwoButtonShift);
+
+ // Update the mouse position too
+ input.setInputLocation(g_system->getEventManager()->getMousePos());
+
+ // Set the outgoing bits
+ InputBits filteredBits = currentBits & filter;
+ input.setInputBits((filteredBits & kAllButtonDownBits) | (filteredBits & _lastRawBits & kAllAutoBits));
+
+ // Update the last bits
+ _lastRawBits = currentBits;
+
+ // Set the console to be requested or not
+ input.setConsoleRequested(_consoleRequested);
+
+ // WORKAROUND: The original had this in currentBits, but then
+ // pressing alt would count as an event (and mess up someone
+ // trying to do alt+enter or something). Since it's only used
+ // as an easter egg, I'm just going to handle it as a separate
+ // bool value.
+ // WORKAROUND x2: I'm also accepting 'e' here since an
+ // alt+click is often intercepted by the OS. 'e' is used as the
+ // easter egg key in Buried in Time and Legacy of Time.
+ input.setAltDown(_keyMap[Common::KEYCODE_LALT] || _keyMap[Common::KEYCODE_RALT] || _keyMap[Common::KEYCODE_e]);
+}
+
+// Wait until the input device stops returning input allowed by filter...
+void InputDeviceManager::waitInput(const InputBits filter) {
+ if (filter != 0) {
+ for (;;) {
+ Input input;
+ getInput(input, filter);
+ if (!input.anyInput())
+ break;
+ }
+ }
+}
+
+bool InputDeviceManager::notifyEvent(const Common::Event &event) {
+ // We're mapping from ScummVM events to pegasus events, which
+ // are based on pippin events.
+ _consoleRequested = false;
+
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ switch (event.kbd.keycode) {
+ case Common::KEYCODE_d:
+ if (event.kbd.flags & Common::KBD_CTRL) // Console!
+ _consoleRequested = true;
+ break;
+ case Common::KEYCODE_s:
+ // We support meta where available and control elsewhere
+ if (event.kbd.flags & (Common::KBD_CTRL|Common::KBD_META))
+ ((PegasusEngine *)g_engine)->requestSave();
+ break;
+ case Common::KEYCODE_o: // o for open (original)
+ case Common::KEYCODE_l: // l for load (ScummVM terminology)
+ // We support meta where available and control elsewhere
+ if (event.kbd.flags & (Common::KBD_CTRL|Common::KBD_META))
+ ((PegasusEngine *)g_engine)->requestLoad();
+ break;
+ default:
+ // Otherwise, set the key to down if we have it
+ if (_keyMap.contains(event.kbd.keycode))
+ _keyMap[event.kbd.keycode] = true;
+ break;
+ }
+ break;
+ case Common::EVENT_KEYUP:
+ // Set the key to up if we have it
+ if (_keyMap.contains(event.kbd.keycode))
+ _keyMap[event.kbd.keycode] = false;
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+int operator==(const Input &arg1, const Input &arg2) {
+ return arg1._inputState == arg2._inputState;
+}
+
+int operator!=(const Input &arg1, const Input &arg2) {
+ return !operator==(arg1, arg2);
+}
+
+InputHandler *InputHandler::_inputHandler = 0;
+bool InputHandler::_invalHotspots = false;
+InputBits InputHandler::_lastFilter = kFilterNoInput;
+
+InputHandler *InputHandler::setInputHandler(InputHandler *currentHandler) {
+ InputHandler *result = 0;
+
+ if (_inputHandler != currentHandler && (!_inputHandler || _inputHandler->releaseInputFocus())) {
+ result = _inputHandler;
+ _inputHandler = currentHandler;
+ if (_inputHandler)
+ _inputHandler->grabInputFocus();
+ }
+
+ return result;
+}
+
+void InputHandler::pollForInput() {
+ if (_inputHandler) {
+ Input input;
+ Hotspot *cursorSpot = 0;
+
+ InputHandler::getInput(input, cursorSpot);
+ if (_inputHandler->isClickInput(input, cursorSpot))
+ _inputHandler->clickInHotspot(input, cursorSpot);
+ else
+ _inputHandler->handleInput(input, cursorSpot);
+ }
+}
+
+void InputHandler::getInput(Input &input, Hotspot *&cursorSpot) {
+ Cursor *cursor = ((PegasusEngine *)g_engine)->_cursor;
+
+ if (_inputHandler)
+ _lastFilter = _inputHandler->getInputFilter();
+ else
+ _lastFilter = kFilterAllInput;
+
+ InputDevice.getInput(input, _lastFilter);
+
+ if (_inputHandler && _inputHandler->wantsCursor() && (_lastFilter & _inputHandler->getClickFilter()) != 0) {
+ if (cursor->isVisible()) {
+ g_allHotspots.deactivateAllHotspots();
+ _inputHandler->activateHotspots();
+
+ Common::Point cursorLocation;
+ cursor->getCursorLocation(cursorLocation);
+ cursorSpot = g_allHotspots.findHotspot(cursorLocation);
+
+ if (_inputHandler)
+ _inputHandler->updateCursor(cursorLocation, cursorSpot);
+ } else {
+ cursor->hideUntilMoved();
+ }
+ } else {
+ cursor->hide();
+ }
+}
+
+void InputHandler::readInputDevice(Input &input) {
+ InputDevice.getInput(input, kFilterAllInput);
+}
+
+InputHandler::InputHandler(InputHandler *nextHandler) {
+ _nextHandler = nextHandler;
+ allowInput(true);
+}
+
+InputHandler::~InputHandler() {
+ if (_inputHandler == this)
+ setInputHandler(_nextHandler);
+}
+
+void InputHandler::handleInput(const Input &input, const Hotspot *cursorSpot) {
+ if (_nextHandler)
+ _nextHandler->handleInput(input, cursorSpot);
+}
+
+void InputHandler::clickInHotspot(const Input &input, const Hotspot *cursorSpot) {
+ if (_nextHandler)
+ _nextHandler->clickInHotspot(input, cursorSpot);
+}
+
+bool InputHandler::isClickInput(const Input &input, const Hotspot *cursorSpot) {
+ if (_nextHandler)
+ return _nextHandler->isClickInput(input, cursorSpot);
+
+ return false;
+}
+
+void InputHandler::activateHotspots() {
+ if (_nextHandler)
+ _nextHandler->activateHotspots();
+}
+
+InputBits InputHandler::getInputFilter() {
+ if (_allowInput) {
+ if (_nextHandler)
+ return _nextHandler->getInputFilter();
+ else
+ return kFilterAllInput;
+ }
+
+ return kFilterNoInput;
+}
+
+InputBits InputHandler::getClickFilter() {
+ if (_allowInput && _nextHandler)
+ return _nextHandler->getClickFilter();
+
+ return kFilterNoInput;
+}
+
+void InputHandler::updateCursor(const Common::Point cursorLocation, const Hotspot *cursorSpot) {
+ if (_nextHandler)
+ _nextHandler->updateCursor(cursorLocation, cursorSpot);
+}
+
+bool InputHandler::wantsCursor() {
+ if (_allowInput) {
+ if (_nextHandler)
+ return _nextHandler->wantsCursor();
+ else
+ return true;
+ }
+
+ return false;
+}
+
+Tracker *Tracker::_currentTracker = 0;
+
+void Tracker::handleInput(const Input &input, const Hotspot *) {
+ if (stopTrackingInput(input))
+ stopTracking(input);
+ else if (isTracking())
+ continueTracking(input);
+}
+
+void Tracker::startTracking(const Input &) {
+ if (!isTracking()) {
+ _savedHandler = InputHandler::setInputHandler(this);
+ _currentTracker = this;
+ }
+}
+
+void Tracker::stopTracking(const Input &) {
+ if (isTracking()) {
+ _currentTracker = NULL;
+ InputHandler::setInputHandler(_savedHandler);
+ }
+}
+
+bool Tracker::isClickInput(const Input &input, const Hotspot *hotspot) {
+ return !isTracking() && InputHandler::isClickInput(input, hotspot);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/input.h b/engines/pegasus/input.h
new file mode 100644
index 0000000000..3e938fa42a
--- /dev/null
+++ b/engines/pegasus/input.h
@@ -0,0 +1,500 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_INPUT_H
+#define PEGASUS_INPUT_H
+
+#include "common/events.h"
+#include "common/hashmap.h"
+#include "common/rect.h"
+#include "common/singleton.h"
+
+#include "pegasus/constants.h"
+#include "pegasus/types.h"
+
+namespace Pegasus {
+
+class Hotspot;
+class Input;
+
+class InputDeviceManager : public Common::Singleton<InputDeviceManager>, public Common::EventObserver {
+public:
+ InputDeviceManager();
+ ~InputDeviceManager();
+
+ bool notifyEvent(const Common::Event &event);
+
+ void getInput(Input &, const InputBits);
+
+ void waitInput(const InputBits);
+
+protected:
+ friend class Common::Singleton<SingletonBaseType>;
+
+ // Keep track of which keys are down (= true) or not
+ Common::HashMap<uint, bool> _keyMap;
+ InputBits _lastRawBits;
+ bool _consoleRequested;
+};
+
+enum {
+ kButtonDownBit = 0,
+ kAutoButtonBit = 1,
+ kBitsPerButton = 2,
+
+ kButtonDownMask = 1 << kButtonDownBit,
+ kAutoButtonMask = 1 << kAutoButtonBit,
+
+ kButtonStateBits = kButtonDownMask | kAutoButtonMask,
+
+ kRawButtonUp = 0,
+ kRawButtonDown = kButtonDownMask | kAutoButtonMask,
+
+ kButtonUp = 0,
+ kButtonDown = kButtonDownMask,
+ kButtonAutoUp = kAutoButtonMask,
+ kButtonAutoDown = kButtonDownMask | kAutoButtonMask
+};
+
+enum {
+ kUpButtonNum = 0,
+ kLeftButtonNum = 1,
+ kDownButtonNum = 2,
+ kRightButtonNum = 3,
+ kLeftFireButtonNum = 4,
+ kRightFireButtonNum = 5,
+ kOneButtonNum = 6,
+ kTwoButtonNum = 7,
+ kThreeButtonNum = 8,
+ kFourButtonNum = 9,
+ kMod1ButtonNum = 10,
+ kMod2ButtonNum = 11,
+ kMod3ButtonNum = 12
+};
+
+enum {
+ kUpButtonShift = kUpButtonNum * kBitsPerButton,
+ kLeftButtonShift = kLeftButtonNum * kBitsPerButton,
+ kDownButtonShift = kDownButtonNum * kBitsPerButton,
+ kRightButtonShift = kRightButtonNum * kBitsPerButton,
+ kLeftFireButtonShift = kLeftFireButtonNum * kBitsPerButton,
+ kRightFireButtonShift = kRightFireButtonNum * kBitsPerButton,
+ kOneButtonShift = kOneButtonNum * kBitsPerButton,
+ kTwoButtonShift = kTwoButtonNum * kBitsPerButton,
+ kThreeButtonShift = kThreeButtonNum * kBitsPerButton,
+ kFourButtonShift = kFourButtonNum * kBitsPerButton,
+ kMod1ButtonShift = kMod1ButtonNum * kBitsPerButton,
+ kMod2ButtonShift = kMod2ButtonNum * kBitsPerButton,
+ kMod3ButtonShift = kMod3ButtonNum * kBitsPerButton
+};
+
+enum {
+ kAllUpBits = (kButtonUp << kUpButtonShift) |
+ (kButtonUp << kLeftButtonShift) |
+ (kButtonUp << kDownButtonShift) |
+ (kButtonUp << kRightButtonShift) |
+ (kButtonUp << kLeftFireButtonShift) |
+ (kButtonUp << kRightFireButtonShift) |
+ (kButtonUp << kOneButtonShift) |
+ (kButtonUp << kTwoButtonShift) |
+ (kButtonUp << kThreeButtonShift) |
+ (kButtonUp << kFourButtonShift) |
+ (kButtonUp << kMod1ButtonShift) |
+ (kButtonUp << kMod2ButtonShift) |
+ (kButtonUp << kMod3ButtonShift),
+ kDirectionBits = (kButtonDownMask << kUpButtonShift) |
+ (kButtonDownMask << kLeftButtonShift) |
+ (kButtonDownMask << kDownButtonShift) |
+ (kButtonDownMask << kRightButtonShift),
+ kButtonBits = (kButtonDownMask << kLeftFireButtonShift) |
+ (kButtonDownMask << kRightFireButtonShift) |
+ (kButtonDownMask << kOneButtonShift) |
+ (kButtonDownMask << kTwoButtonShift) |
+ (kButtonDownMask << kThreeButtonShift) |
+ (kButtonDownMask << kFourButtonShift) |
+ (kButtonDownMask << kMod1ButtonShift) |
+ (kButtonDownMask << kMod2ButtonShift) |
+ (kButtonDownMask << kMod3ButtonShift),
+ kAllButtonDownBits = kDirectionBits | kButtonBits,
+ kAllAutoBits = (kAutoButtonMask << kUpButtonShift) |
+ (kAutoButtonMask << kLeftButtonShift) |
+ (kAutoButtonMask << kDownButtonShift) |
+ (kAutoButtonMask << kRightButtonShift) |
+ (kAutoButtonMask << kLeftFireButtonShift) |
+ (kAutoButtonMask << kRightFireButtonShift) |
+ (kAutoButtonMask << kOneButtonShift) |
+ (kAutoButtonMask << kTwoButtonShift) |
+ (kAutoButtonMask << kThreeButtonShift) |
+ (kAutoButtonMask << kFourButtonShift) |
+ (kAutoButtonMask << kMod1ButtonShift) |
+ (kAutoButtonMask << kMod2ButtonShift) |
+ (kAutoButtonMask << kMod3ButtonShift),
+
+ kFilterUpButton = kButtonDownMask << kUpButtonShift,
+ kFilterUpAuto = kAutoButtonMask << kUpButtonShift,
+ kFilterUpButtonAny = kFilterUpButton | kFilterUpAuto,
+ kFilterLeftButton = kButtonDownMask << kLeftButtonShift,
+ kFilterLeftAuto = kAutoButtonMask << kLeftButtonShift,
+ kFilterLeftButtonAny = kFilterLeftButton | kFilterLeftAuto,
+ kFilterDownButton = kButtonDownMask << kDownButtonShift,
+ kFilterDownAuto = kAutoButtonMask << kDownButtonShift,
+ kFilterDownButtonAny = kFilterDownButton | kFilterDownAuto,
+ kFilterRightButton = kButtonDownMask << kRightButtonShift,
+ kFilterRightAuto = kAutoButtonMask << kRightButtonShift,
+ kFilterRightButtonAny = kFilterRightButton | kFilterRightAuto,
+ kFilterLeftFireButton = kButtonDownMask << kLeftFireButtonShift,
+ kFilterLeftFireAuto = kAutoButtonMask << kLeftFireButtonShift,
+ kFilterLeftFireButtonAny = kFilterLeftFireButton | kFilterLeftFireAuto,
+ kFilterRightFireButton = kButtonDownMask << kRightFireButtonShift,
+ kFilterRightFireAuto = kAutoButtonMask << kRightFireButtonShift,
+ kFilterRightFireButtonAny = kFilterRightFireButton | kFilterRightFireAuto,
+ kFilterOneButton = kButtonDownMask << kOneButtonShift,
+ kFilterOneAuto = kAutoButtonMask << kOneButtonShift,
+ kFilterOneButtonAny = kFilterOneButton | kFilterOneAuto,
+ kFilterTwoButton = kButtonDownMask << kTwoButtonShift,
+ kFilterTwoAuto = kAutoButtonMask << kTwoButtonShift,
+ kFilterTwoButtonAny = kFilterTwoButton | kFilterTwoAuto,
+ kFilterThreeButton = kButtonDownMask << kThreeButtonShift,
+ kFilterThreeAuto = kAutoButtonMask << kThreeButtonShift,
+ kFilterThreeButtonAny = kFilterThreeButton | kFilterThreeAuto,
+ kFilterFourButton = kButtonDownMask << kFourButtonShift,
+ kFilterFourAuto = kAutoButtonMask << kFourButtonShift,
+ kFilterFourButtonAny = kFilterFourButton | kFilterFourAuto,
+ kFilterMod1Button = kButtonDownMask << kMod1ButtonShift,
+ kFilterMod1Auto = kAutoButtonMask << kMod1ButtonShift,
+ kFilterMod1ButtonAny = kFilterMod1Button | kFilterMod1Auto,
+ kFilterMod2Button = kButtonDownMask << kMod2ButtonShift,
+ kFilterMod2Auto = kAutoButtonMask << kMod2ButtonShift,
+ kFilterMod2ButtonAny = kFilterMod2Button | kFilterMod2Auto,
+ kFilterMod3Button = kButtonDownMask << kMod3ButtonShift,
+ kFilterMod3Auto = kAutoButtonMask << kMod3ButtonShift,
+ kFilterMod3ButtonAny = kFilterMod3Button | kFilterMod3Auto,
+
+ kFilterNoInput = 0,
+ kFilterAllInput = kFilterUpButton |
+ kFilterUpAuto |
+ kFilterLeftButton |
+ kFilterLeftAuto |
+ kFilterDownButton |
+ kFilterDownAuto |
+ kFilterRightButton |
+ kFilterRightAuto |
+ kFilterLeftFireButton |
+ kFilterLeftFireAuto |
+ kFilterRightFireButton |
+ kFilterRightFireAuto |
+ kFilterOneButton |
+ kFilterOneAuto |
+ kFilterTwoButton |
+ kFilterTwoAuto |
+ kFilterThreeButton |
+ kFilterThreeAuto |
+ kFilterFourButton |
+ kFilterFourAuto |
+ kFilterMod1Button |
+ kFilterMod1Auto |
+ kFilterMod2Button |
+ kFilterMod2Auto |
+ kFilterMod3Button |
+ kFilterMod3Auto,
+
+ kFilterAllDirections = kFilterUpButton |
+ kFilterUpAuto |
+ kFilterLeftButton |
+ kFilterLeftAuto |
+ kFilterDownButton |
+ kFilterDownAuto |
+ kFilterRightButton |
+ kFilterRightAuto,
+
+ kFilterButtons = kFilterOneButton |
+ kFilterOneAuto |
+ kFilterTwoButton |
+ kFilterTwoAuto |
+ kFilterThreeButton |
+ kFilterThreeAuto |
+ kFilterFourButton |
+ kFilterFourAuto,
+
+ kFilterFireButtons = kFilterLeftFireButton |
+ kFilterLeftFireAuto |
+ kFilterRightFireButton |
+ kFilterRightFireAuto,
+
+ kFilterAllButtons = kFilterLeftFireButton |
+ kFilterLeftFireAuto |
+ kFilterRightFireButton |
+ kFilterRightFireAuto |
+ kFilterOneButton |
+ kFilterOneAuto |
+ kFilterTwoButton |
+ kFilterTwoAuto |
+ kFilterThreeButton |
+ kFilterThreeAuto |
+ kFilterFourButton |
+ kFilterFourAuto |
+ kFilterMod1Button |
+ kFilterMod1Auto |
+ kFilterMod2Button |
+ kFilterMod2Auto |
+ kFilterMod3Button |
+ kFilterMod3Auto,
+
+ kFilterAllInputNoAuto = kFilterUpButton |
+ kFilterLeftButton |
+ kFilterDownButton |
+ kFilterRightButton |
+ kFilterLeftFireButton |
+ kFilterRightFireButton |
+ kFilterOneButton |
+ kFilterTwoButton |
+ kFilterThreeButton |
+ kFilterFourButton |
+ kFilterMod1Button |
+ kFilterMod2Button |
+ kFilterMod3Button
+};
+
+static const InputBits kHintInterruption = kFilterAllInputNoAuto;
+static const InputBits kWarningInterruption = kFilterNoInput;
+static const InputBits kOpticalInterruption = kFilterAllInputNoAuto;
+
+/*
+
+ Buttons are defined as:
+ up, left, down, right direction buttons.
+ fireLeft, fireRight: fire buttons.
+ mod1, mod2, mod3: modifier buttons, similar to shift, control, etc.
+ a, b, c, d: general purpose buttons.
+
+ button state is held as bits in a long word, two bits per button.
+
+ Filter bits:
+ for each button, two bits are assigned for filtering. If bit 0 is set, the
+ corresponding button is available for "button down" input. If bit 1 is set,
+ the corresponding button is available for "auto down" input. Note that bit
+ 1 is meaningful only if bit 0 is set.
+
+*/
+
+class Input {
+friend int operator==(const Input &, const Input &);
+friend int operator!=(const Input &, const Input &);
+friend class InputDeviceManager;
+
+public:
+ Input() { clearInput(); }
+
+ bool upButtonDown() const { return (_inputState & (kButtonStateBits << kUpButtonShift)) == (kButtonDown << kUpButtonShift); }
+ bool upButtonAutoDown() const { return (_inputState & (kButtonStateBits << kUpButtonShift)) == (kButtonAutoDown << kUpButtonShift); }
+ bool upButtonAnyDown() const { return (_inputState & (kButtonAutoDown << kUpButtonShift)) != 0; }
+
+ bool leftButtonDown() const { return (_inputState & (kButtonStateBits << kLeftButtonShift)) == (kButtonDown << kLeftButtonShift); }
+ bool leftButtonAutoDown() const { return (_inputState & (kButtonStateBits << kLeftButtonShift)) == (kButtonAutoDown << kLeftButtonShift); }
+ bool leftButtonAnyDown() const { return (_inputState & (kButtonAutoDown << kLeftButtonShift)) != 0; }
+
+ bool downButtonDown() const { return (_inputState & (kButtonStateBits << kDownButtonShift)) == (kButtonDown << kDownButtonShift); }
+ bool downButtonAutoDown() const { return (_inputState & (kButtonStateBits << kDownButtonShift)) == (kButtonAutoDown << kDownButtonShift); }
+ bool downButtonAnyDown() const { return (_inputState & (kButtonAutoDown << kDownButtonShift)) != 0; }
+
+ bool rightButtonDown() const { return (_inputState & (kButtonStateBits << kRightButtonShift)) == (kButtonDown << kRightButtonShift); }
+ bool rightButtonAutoDown() const { return (_inputState & (kButtonStateBits << kRightButtonShift)) == (kButtonAutoDown << kRightButtonShift); }
+ bool rightButtonAnyDown() const { return (_inputState & (kButtonAutoDown << kRightButtonShift)) != 0; }
+
+ bool leftFireButtonDown() const { return (_inputState & (kButtonStateBits << kLeftFireButtonShift)) == (kButtonDown << kLeftFireButtonShift); }
+ bool leftFireButtonAutoDown() const { return (_inputState & (kButtonStateBits << kLeftFireButtonShift)) == (kButtonAutoDown << kLeftFireButtonShift); }
+ bool leftFireButtonAnyDown() const { return (_inputState & (kButtonAutoDown << kLeftFireButtonShift)) != 0; }
+
+ bool rightFireButtonDown() const { return (_inputState & (kButtonStateBits << kRightFireButtonShift)) == (kButtonDown << kRightFireButtonShift); }
+ bool rightFireButtonAutoDown() const { return (_inputState & (kButtonStateBits << kRightFireButtonShift)) == (kButtonAutoDown << kRightFireButtonShift); }
+ bool rightFireButtonAnyDown() const { return (_inputState & (kButtonAutoDown << kRightFireButtonShift)) != 0; }
+
+ bool oneButtonDown() const { return (_inputState & (kButtonStateBits << kOneButtonShift)) == (kButtonDown << kOneButtonShift); }
+ bool oneButtonAutoDown() const { return (_inputState & (kButtonStateBits << kOneButtonShift)) == (kButtonAutoDown << kOneButtonShift); }
+ bool oneButtonAnyDown() const { return (_inputState & (kButtonAutoDown << kOneButtonShift)) != 0; }
+
+ bool twoButtonDown() const { return (_inputState & (kButtonStateBits << kTwoButtonShift)) == (kButtonDown << kTwoButtonShift); }
+ bool twoButtonAutoDown() const { return (_inputState & (kButtonStateBits << kTwoButtonShift)) == (kButtonAutoDown << kTwoButtonShift); }
+ bool twoButtonAnyDown() const { return (_inputState & (kButtonAutoDown << kTwoButtonShift)) != 0; }
+
+ bool threeButtonDown() const { return (_inputState & (kButtonStateBits << kThreeButtonShift)) == (kButtonDown << kThreeButtonShift); }
+ bool threeButtonAutoDown() const { return (_inputState & (kButtonStateBits << kThreeButtonShift)) == (kButtonAutoDown << kThreeButtonShift); }
+ bool threeButtonAnyDown() const { return (_inputState & (kButtonAutoDown << kThreeButtonShift)) != 0; }
+
+ bool fourButtonDown() const { return (_inputState & (kButtonStateBits << kFourButtonShift)) == (kButtonDown << kFourButtonShift); }
+ bool fourButtonAutoDown() const { return (_inputState & (kButtonStateBits << kFourButtonShift)) == (kButtonAutoDown << kFourButtonShift); }
+ bool fourButtonAnyDown() const { return (_inputState & (kButtonAutoDown << kFourButtonShift)) != 0; }
+
+ bool mod1ButtonDown() const { return (_inputState & (kButtonStateBits << kMod1ButtonShift)) == (kButtonDown << kMod1ButtonShift); }
+ bool mod1ButtonAutoDown() const { return (_inputState & (kButtonStateBits << kMod1ButtonShift)) == (kButtonAutoDown << kMod1ButtonShift); }
+ bool mod1ButtonAnyDown() const { return (_inputState & (kButtonAutoDown << kMod1ButtonShift)) != 0; }
+
+ bool mod2ButtonDown() const { return (_inputState & (kButtonStateBits << kMod2ButtonShift)) == (kButtonDown << kMod2ButtonShift); }
+ bool mod2ButtonAutoDown() const { return (_inputState & (kButtonStateBits << kMod2ButtonShift)) == (kButtonAutoDown << kMod2ButtonShift); }
+ bool mod2ButtonAnyDown() const { return (_inputState & (kButtonAutoDown << kMod2ButtonShift)) != 0; }
+
+ bool mod3ButtonDown() const { return (_inputState & (kButtonStateBits << kMod3ButtonShift)) == (kButtonDown << kMod3ButtonShift); }
+ bool mod3ButtonAutoDown() const { return (_inputState & (kButtonStateBits << kMod3ButtonShift)) == (kButtonAutoDown << kMod3ButtonShift); }
+ bool mod3ButtonAnyDown() const { return (_inputState & (kButtonAutoDown << kMod3ButtonShift)) != 0; }
+
+ bool allAutoInput() const { return (_inputState & kAllAutoBits) != 0; }
+ bool anyDirectionInput() const { return (_inputState & kDirectionBits) != 0; }
+ bool anyButtonInput() const { return (_inputState & kButtonBits) != 0; }
+ bool anyInput() const { return _inputState != 0; }
+
+ void getInputLocation(Common::Point &where) const { where = _inputLocation; }
+
+ bool anyInputBitSet(const InputBits bits) const { return (_inputState & bits) != 0; }
+
+ bool isAltDown() const { return _altDown; }
+ bool isConsoleRequested() const { return _consoleRequested; }
+
+ void clearInput() {
+ _inputState = kAllUpBits;
+ _inputLocation.x = 0;
+ _inputLocation.y = 0;
+ _consoleRequested = false;
+ _altDown = false;
+ }
+
+protected:
+ void setInputBits(const InputBits state) { _inputState = state; }
+ void setInputLocation(const Common::Point &where) { _inputLocation = where; }
+ void setConsoleRequested(bool consoleRequested) { _consoleRequested = consoleRequested; }
+ void setAltDown(bool altDown) { _altDown = altDown; }
+
+ InputBits _inputState;
+ Common::Point _inputLocation;
+ bool _consoleRequested;
+ bool _altDown;
+};
+
+class InputHandler {
+public:
+ static InputHandler *setInputHandler(InputHandler*);
+ static InputHandler *getCurrentHandler() { return _inputHandler; }
+ static void pollForInput();
+ static void getInput(Input&, Hotspot*&);
+ static void readInputDevice(Input&);
+ static void invalHotspots() { _invalHotspots = true; }
+ static InputBits getCurrentFilter() { return _lastFilter; }
+
+ InputHandler(InputHandler*);
+ virtual ~InputHandler();
+
+ virtual void setNextHandler(InputHandler *nextHandler) { _nextHandler = nextHandler; }
+ virtual InputHandler *getNextHandler() { return _nextHandler; }
+
+ virtual void handleInput(const Input &, const Hotspot *);
+ virtual void clickInHotspot(const Input &, const Hotspot *);
+
+ virtual void activateHotspots();
+ virtual void updateCursor(const Common::Point, const Hotspot *);
+ virtual bool isClickInput(const Input &, const Hotspot *);
+ virtual bool wantsCursor();
+
+ virtual bool releaseInputFocus() { return true; }
+ virtual void grabInputFocus() {}
+
+ // This returns bits set for what kinds of input to accept.
+ virtual InputBits getInputFilter();
+
+ // This returns bits defining what input constitutes a "click."
+ virtual InputBits getClickFilter();
+
+ virtual void allowInput(const bool allow) { _allowInput = allow; }
+
+protected:
+ static InputHandler *_inputHandler;
+ static bool _invalHotspots;
+ static InputBits _lastFilter;
+
+ InputHandler *_nextHandler;
+ bool _allowInput;
+};
+
+
+/*
+
+ Tracker implements "dragging". A Tracker can receive a startTracking message,
+ which causes it to be the current tracker, as well as setting it up as the current
+ input handler. In addition, only one tracker can be tracking at a time, and no
+ other handler can be set up as the current handler until the track finishes. By
+ default, there is no next input handler for a Tracker, but this behavior can be
+ overridden if desired.
+
+*/
+
+class Tracker : public InputHandler {
+public:
+ Tracker() : InputHandler(0) {}
+ virtual ~Tracker() {}
+
+ virtual void handleInput(const Input &, const Hotspot *);
+ virtual bool stopTrackingInput(const Input &) { return false; }
+
+ virtual void startTracking(const Input &);
+ virtual void stopTracking(const Input &);
+ virtual void continueTracking(const Input &) {}
+
+ bool isTracking() { return this == _currentTracker; }
+ bool isClickInput(const Input &, const Hotspot *);
+
+ bool releaseInputFocus() { return !isTracking(); }
+
+protected:
+ static Tracker *_currentTracker;
+
+ InputHandler *_savedHandler;
+};
+
+class JMPPPInput {
+public:
+ static bool isMenuButtonPressInput(const Input &input) { return input.twoButtonDown(); }
+
+ static InputBits getClickInputFilter() { return kFilterTwoButton; }
+ static bool isClickInput(const Input &input) { return input.twoButtonDown(); }
+ static bool isDraggingInput(const Input &input) { return input.twoButtonAnyDown(); }
+ static bool isPressingInput(const Input &input) { return input.twoButtonAnyDown(); }
+
+ static bool isRaiseInventoryInput(const Input &input) { return input.leftFireButtonDown(); }
+ static bool isRaiseBiochipsInput(const Input &input) { return input.rightFireButtonDown(); }
+ static InputBits getItemPanelsInputFilter() { return kFilterLeftFireButton | kFilterRightFireButton; }
+
+ static bool isToggleAIMiddleInput(const Input &input) { return input.threeButtonDown(); }
+
+ static bool isToggleInfoInput(const Input &input) { return input.fourButtonDown(); }
+
+ // Hmmmmm....
+ static bool isEasterEggModifierInput(const Input &input) { return input.isAltDown(); }
+
+ static bool isTogglePauseInput(const Input &input) { return input.mod3ButtonDown(); }
+};
+
+} // End of namespace Pegasus
+
+#define InputDevice (::Pegasus::InputDeviceManager::instance())
+
+#endif
diff --git a/engines/pegasus/interaction.h b/engines/pegasus/interaction.h
new file mode 100644
index 0000000000..293ee6be83
--- /dev/null
+++ b/engines/pegasus/interaction.h
@@ -0,0 +1,110 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_INTERACTION_H
+#define PEGASUS_INTERACTION_H
+
+#include "pegasus/input.h"
+#include "pegasus/util.h"
+
+namespace Pegasus {
+
+static const InteractionID kNoInteractionID = -1;
+
+class Neighborhood;
+
+class GameInteraction : public IDObject, public InputHandler {
+public:
+ GameInteraction(const InteractionID id, Neighborhood *nextHandler) : IDObject(id), InputHandler((InputHandler *)nextHandler) {
+ _isInteracting = false;
+ _savedHandler = 0;
+ _owner = nextHandler;
+ }
+
+ // If the interaction is open (_isInteracting == true), it's too late to do anything
+ // about it here.
+ virtual ~GameInteraction() {}
+
+ // startInteraction and stopInteraction are called by the outside world to
+ // start and stop the interaction sequence.
+ // isInteracting returns a bool indicating whether or not the interaction
+ // is going.
+ void startInteraction() {
+ if (!isInteracting()) {
+ openInteraction();
+ initInteraction();
+ _isInteracting = true;
+ _savedHandler = InputHandler::setInputHandler(this);
+ }
+ }
+ void stopInteraction() {
+ if (isInteracting()) {
+ closeInteraction();
+ _isInteracting = false;
+ if (InputHandler::_inputHandler == this)
+ InputHandler::setInputHandler(_savedHandler);
+ }
+ }
+ void startOverInteraction() {
+ if (isInteracting())
+ resetInteraction();
+ }
+ bool isInteracting() const { return _isInteracting; }
+ Neighborhood *getOwner() const { return _owner; }
+
+ virtual Common::String getBriefingMovie() { return ""; }
+ virtual Common::String getEnvScanMovie() { return ""; }
+ virtual long getNumHints() { return 0; }
+ virtual Common::String getHintMovie(uint) { return ""; }
+ virtual bool canSolve() { return false; }
+
+ virtual void setSoundFXLevel(const uint16) {}
+ virtual void setAmbienceLevel(const uint16) {}
+
+ virtual void doSolve() {}
+
+protected:
+ // Subclasses override openInteraction and closeInteraction to perform
+ // specific initialization and cleanup. Override resetInteraction to
+ // "start the interaction over." resetInteraction is called only when
+ // the interaction is already open.
+ // These functions are only called in pairs, never two opens or closes
+ // in a row.
+ virtual void openInteraction() {}
+ virtual void initInteraction() {}
+ virtual void closeInteraction() {}
+ virtual void resetInteraction() {}
+
+ InputHandler *_savedHandler;
+ Neighborhood *_owner;
+
+private:
+ // Private so that only StartInteraction and StopInteraction can touch it.
+ bool _isInteracting;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/interface.cpp b/engines/pegasus/interface.cpp
new file mode 100644
index 0000000000..d9d3865192
--- /dev/null
+++ b/engines/pegasus/interface.cpp
@@ -0,0 +1,667 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/compass.h"
+#include "pegasus/energymonitor.h"
+#include "pegasus/interface.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/biochips/biochipitem.h"
+#include "pegasus/items/inventory/inventoryitem.h"
+
+namespace Pegasus {
+
+Interface *g_interface = 0;
+
+Interface::Interface() : InputHandler(0), _interfaceNotification(kInterfaceNotificationID, (NotificationManager *)((PegasusEngine *)g_engine)),
+ _currentItemSpot(kCurrentItemSpotID), _currentBiochipSpot(kCurrentBiochipSpotID),
+ _background1(kInterface1ID), _background2(kInterface2ID), _background3(kInterface3ID),
+ _background4(kInterface4ID), _datePicture(kDateID), _inventoryPush(kInventoryPushID),
+ _inventoryLid(kInventoryLidID, kNoDisplayElement),
+ _inventoryPanel(kNoDisplayElement, (InputHandler *)((PegasusEngine *)g_engine), ((PegasusEngine *)g_engine)->getItemsInventory()),
+ _biochipPush(kBiochipPushID), _biochipLid(kBiochipLidID, kNoDisplayElement),
+ _biochipPanel(kNoDisplayElement, (InputHandler *)((PegasusEngine *)g_engine), ((PegasusEngine *)g_engine)->getBiochipsInventory()) {
+ g_energyMonitor = 0;
+ _previousHandler = 0;
+ _inventoryRaised = false;
+ _biochipRaised = false;
+ _playingEndMessage = false;
+ g_interface = this;
+}
+
+Interface::~Interface() {
+ throwAwayInterface();
+ g_interface = 0;
+}
+
+void Interface::throwAwayInterface() {
+ g_allHotspots.removeOneHotspot(kCurrentItemSpotID);
+ g_allHotspots.removeOneHotspot(kCurrentBiochipSpotID);
+
+ throwAwayBackground();
+ throwAwayDateMonitor();
+ throwAwayEnergyMonitor();
+ throwAwayAIArea();
+ throwAwayCompass();
+ throwAwayNotifications();
+ throwAwayInventoryPanel();
+ throwAwayBiochipPanel();
+}
+
+void Interface::validateBackground() {
+ if (!_background1.isSurfaceValid()) {
+ _background1.initFromPICTFile("Images/Interface/3DInterface Left");
+ _background2.initFromPICTFile("Images/Interface/3DInterface Top");
+ _background3.initFromPICTFile("Images/Interface/3DInterface Right");
+ _background4.initFromPICTFile("Images/Interface/3DInterface Bottom");
+
+ _background1.setDisplayOrder(kBackground1Order);
+ _background1.startDisplaying();
+ _background1.moveElementTo(kBackground1Left, kBackground1Top);
+
+ _background2.setDisplayOrder(kBackground2Order);
+ _background2.startDisplaying();
+ _background2.moveElementTo(kBackground2Left, kBackground2Top);
+
+ _background3.setDisplayOrder(kBackground2Order);
+ _background3.startDisplaying();
+ _background3.moveElementTo(kBackground3Left, kBackground3Top);
+
+ _background4.setDisplayOrder(kBackground4Order);
+ _background4.startDisplaying();
+ _background4.moveElementTo(kBackground4Left, kBackground4Top);
+
+ _background1.show();
+ _background2.show();
+ _background3.show();
+ _background4.show();
+ }
+}
+
+void Interface::throwAwayBackground() {
+ _background1.stopDisplaying();
+ _background1.deallocateSurface();
+ _background2.stopDisplaying();
+ _background2.deallocateSurface();
+ _background3.stopDisplaying();
+ _background3.deallocateSurface();
+ _background4.stopDisplaying();
+ _background4.deallocateSurface();
+}
+
+void Interface::validateDateMonitor() {
+ if (!_datePicture.isSurfaceValid()) {
+ _datePicture.setDisplayOrder(kDateOrder);
+ _datePicture.startDisplaying();
+ _datePicture.moveElementTo(kDateLeft, kDateTop);
+ _datePicture.show();
+ }
+}
+
+void Interface::throwAwayDateMonitor() {
+ _datePicture.stopDisplaying();
+ _datePicture.deallocateSurface();
+}
+
+void Interface::setDate(const uint16 dateResID) {
+ validateDateMonitor();
+ _datePicture.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, dateResID);
+ _datePicture.triggerRedraw();
+}
+
+void Interface::validateCompass() {
+ if (!g_compass) {
+ new Compass();
+ g_compass->initCompass();
+ g_compass->setDisplayOrder(kCompassOrder);
+ g_compass->startDisplaying();
+ g_compass->moveElementTo(kCompassLeft, kCompassTop);
+ g_compass->show();
+ }
+}
+
+void Interface::throwAwayCompass() {
+ delete g_compass;
+}
+
+void Interface::validateNotifications() {
+ _interfaceNotification.notifyMe(this, kInterfaceNotificationFlags, kInterfaceNotificationFlags);
+ _inventoryLidCallBack.setNotification(&_interfaceNotification);
+ _inventoryPushCallBack.setNotification(&_interfaceNotification);
+ _biochipLidCallBack.setNotification(&_interfaceNotification);
+ _biochipPushCallBack.setNotification(&_interfaceNotification);
+}
+
+void Interface::throwAwayNotifications() {
+ _interfaceNotification.cancelNotification(this);
+}
+
+void Interface::validateAIArea() {
+ if (!g_AIArea) {
+ new AIArea((InputHandler *)((PegasusEngine *)g_engine));
+ if (g_AIArea)
+ g_AIArea->initAIArea();
+ }
+}
+
+void Interface::throwAwayAIArea() {
+ delete g_AIArea;
+}
+
+void Interface::validateInventoryPanel() {
+ if (!_inventoryPanel.isSurfaceValid()) {
+ _inventoryPanel.initInventoryImage(&_inventoryPush);
+ _inventoryPanel.moveElementTo(kInventoryPushLeft, kInventoryPushTop);
+ _inventoryPush.setSlideDirection(kSlideUpMask);
+ _inventoryPush.setInAndOutElements(&_inventoryPanel, 0);
+ _inventoryPush.setDisplayOrder(kInventoryPushOrder);
+ _inventoryPush.startDisplaying();
+
+ _inventoryLid.useFileName("Images/Lids/Inventory Lid Sequence");
+ _inventoryLid.useTransparent(true);
+ _inventoryLid.openFrameSequence();
+ _inventoryLid.moveElementTo(kInventoryLidLeft, kInventoryLidTop);
+ _inventoryLid.setDisplayOrder(kInventoryLidOrder);
+ _inventoryLid.startDisplaying();
+
+ _inventoryPushCallBack.initCallBack(&_inventoryPush, kCallBackAtExtremes);
+ _inventoryLidCallBack.initCallBack(&_inventoryLid, kCallBackAtExtremes);
+
+ _inventoryUp = false;
+ _inventoryRaised = false;
+
+ Item *item = getCurrentInventoryItem();
+ if (item)
+ item->select();
+ }
+}
+
+void Interface::throwAwayInventoryPanel() {
+ _inventoryPanel.stopDisplaying();
+ _inventoryPanel.throwAwayInventoryImage();
+ _inventoryPush.stopDisplaying();
+ _inventoryLid.stopDisplaying();
+ _inventoryLid.closeFrameSequence();
+ _inventoryPushCallBack.releaseCallBack();
+ _inventoryLidCallBack.releaseCallBack();
+
+ Item *item = getCurrentInventoryItem();
+ if (item)
+ item->deselect();
+
+ _inventoryUp = false;
+ _inventoryRaised = false;
+}
+
+void Interface::validateBiochipPanel() {
+ if (!_biochipPanel.isSurfaceValid()) {
+ _biochipPanel.initInventoryImage(&_biochipPush);
+ _biochipPanel.moveElementTo(kBiochipPushLeft, kBiochipPushTop);
+ _biochipPush.setSlideDirection(kSlideUpMask);
+ _biochipPush.setInAndOutElements(&_biochipPanel, 0);
+ _biochipPush.setDisplayOrder(kBiochipPushOrder);
+ _biochipPush.startDisplaying();
+
+ _biochipLid.useFileName("Images/Lids/Biochip Lid Sequence");
+ _biochipLid.useTransparent(true);
+ _biochipLid.openFrameSequence();
+ _biochipLid.moveElementTo(kBiochipLidLeft, kBiochipLidTop);
+ _biochipLid.setDisplayOrder(kBiochipLidOrder);
+ _biochipLid.startDisplaying();
+
+ _biochipPushCallBack.initCallBack(&_biochipPush, kCallBackAtExtremes);
+ _biochipLidCallBack.initCallBack(&_biochipLid, kCallBackAtExtremes);
+
+ _biochipUp = false;
+ _biochipRaised = false;
+
+ Item *item = getCurrentBiochip();
+ if (item)
+ item->select();
+ }
+}
+
+void Interface::throwAwayBiochipPanel() {
+ _biochipPanel.stopDisplaying();
+ _biochipPanel.throwAwayInventoryImage();
+ _biochipPush.stopDisplaying();
+ _biochipLid.stopDisplaying();
+ _biochipLid.closeFrameSequence();
+ _biochipPushCallBack.releaseCallBack();
+ _biochipLidCallBack.releaseCallBack();
+
+ Item *item = getCurrentBiochip();
+ if (item)
+ item->deselect();
+
+ _biochipUp = false;
+ _biochipRaised = false;
+}
+
+void Interface::validateEnergyMonitor() {
+ if (!g_energyMonitor)
+ new EnergyMonitor();
+}
+
+void Interface::throwAwayEnergyMonitor() {
+ delete g_energyMonitor;
+}
+
+void Interface::createInterface() {
+ validateBackground();
+ validateDateMonitor();
+ validateCompass();
+ validateNotifications();
+ validateAIArea();
+ validateBiochipPanel();
+ validateInventoryPanel();
+ validateEnergyMonitor();
+
+ if (!g_allHotspots.findHotspotByID(kCurrentItemSpotID)) {
+ _currentItemSpot.setArea(Common::Rect(76, 334, 172, 430));
+ _currentItemSpot.setHotspotFlags(kShellSpotFlag);
+ _currentItemSpot.setActive();
+ g_allHotspots.push_back(&_currentItemSpot);
+ }
+
+ if (!g_allHotspots.findHotspotByID(kCurrentBiochipSpotID)) {
+ _currentBiochipSpot.setArea(Common::Rect(364, 334, 460, 430));
+ _currentBiochipSpot.setHotspotFlags(kShellSpotFlag);
+ _currentBiochipSpot.setActive();
+ g_allHotspots.push_back(&_currentBiochipSpot);
+ }
+}
+
+InventoryResult Interface::addInventoryItem(InventoryItem *item) {
+ return _inventoryPanel.addInventoryItem(item);
+}
+
+InventoryResult Interface::removeInventoryItem(InventoryItem *item) {
+ return _inventoryPanel.removeInventoryItem(item);
+}
+
+void Interface::removeAllItemsFromInventory() {
+ _inventoryPanel.removeAllItems();
+}
+
+InventoryItem *Interface::getCurrentInventoryItem() {
+ return (InventoryItem *)_inventoryPanel.getCurrentItem();
+}
+
+void Interface::setCurrentInventoryItem(InventoryItem *item) {
+ setCurrentInventoryItemID(item->getObjectID());
+}
+
+void Interface::setCurrentInventoryItemID(ItemID id) {
+ _inventoryPanel.setCurrentItemID(id);
+}
+
+InventoryResult Interface::addBiochip(BiochipItem *item) {
+ return _biochipPanel.addInventoryItem(item);
+}
+
+void Interface::removeAllItemsFromBiochips() {
+ _biochipPanel.removeAllItems();
+}
+
+BiochipItem *Interface::getCurrentBiochip() {
+ return (BiochipItem *)_biochipPanel.getCurrentItem();
+}
+
+void Interface::setCurrentBiochip(BiochipItem *item) {
+ setCurrentBiochipID(item->getObjectID());
+}
+
+void Interface::setCurrentBiochipID(ItemID id) {
+ _biochipPanel.setCurrentItemID(id);
+}
+
+void Interface::receiveNotification(Notification *notification, const NotificationFlags flags) {
+ if (notification == &_interfaceNotification) {
+ switch (flags) {
+ case kInventoryLidOpenFlag:
+ inventoryLidOpen(true);
+ break;
+ case kInventoryLidClosedFlag:
+ inventoryLidClosed();
+ break;
+ case kInventoryDrawerUpFlag:
+ inventoryDrawerUp();
+ break;
+ case kInventoryDrawerDownFlag:
+ inventoryDrawerDown(true);
+ break;
+ case kBiochipLidOpenFlag:
+ biochipLidOpen(true);
+ break;
+ case kBiochipLidClosedFlag:
+ biochipLidClosed();
+ break;
+ case kBiochipDrawerUpFlag:
+ biochipDrawerUp();
+ break;
+ case kBiochipDrawerDownFlag:
+ biochipDrawerDown(true);
+ break;
+ }
+ }
+}
+
+void Interface::raiseInventoryDrawer(const bool doCallBacks) {
+ if (!_biochipUp)
+ _previousHandler = InputHandler::getCurrentHandler();
+
+ InputHandler::setInputHandler(&_inventoryPanel);
+ _inventoryUp = true;
+ _inventoryPanel.activateInventoryPicture();
+
+ if (doCallBacks) {
+ _inventoryLidCallBack.setCallBackFlag(kInventoryLidOpenFlag);
+ _inventoryLidCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ }
+
+ _inventoryLid.show();
+ _inventoryPush.show();
+ _inventoryLid.start();
+}
+
+void Interface::playEndMessage() {
+ raiseInventoryDrawerForMessage();
+ _playingEndMessage = true;
+ _inventoryPanel.playEndMessage(&_inventoryPush);
+ lowerInventoryDrawerForMessage();
+ _playingEndMessage = false;
+}
+
+void Interface::raiseInventoryDrawerForMessage() {
+ _inventoryPanel.disableLooping();
+ raiseInventoryDrawerSync();
+}
+
+void Interface::lowerInventoryDrawerForMessage() {
+ lowerInventoryDrawerSync();
+}
+
+void Interface::inventoryLidOpen(const bool doCallBacks) {
+ _inventoryLid.stop();
+
+ if (doCallBacks) {
+ _inventoryPushCallBack.setCallBackFlag(kInventoryDrawerUpFlag);
+ _inventoryPushCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ }
+
+ FaderMoveSpec moveSpec;
+ moveSpec.makeTwoKnotFaderSpec(60, 0, 0, 15, 1000);
+ _inventoryPush.startFader(moveSpec);
+}
+
+void Interface::inventoryDrawerUp() {
+ _inventoryPush.stopFader();
+ _inventoryPanel.panelUp();
+ _inventoryRaised = true;
+}
+
+bool Interface::isInventoryUp() {
+ return _inventoryRaised;
+}
+
+bool Interface::isInventoryDown() {
+ return !_inventoryUp;
+}
+
+void Interface::lowerInventoryDrawer(const bool doCallBacks) {
+ if (_inventoryRaised) {
+ _inventoryRaised = false;
+
+ if (!_playingEndMessage)
+ _inventoryPanel.deactivateInventoryPicture();
+
+ if (doCallBacks) {
+ _inventoryPushCallBack.setCallBackFlag(kInventoryDrawerDownFlag);
+ _inventoryPushCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ }
+
+ FaderMoveSpec moveSpec;
+ moveSpec.makeTwoKnotFaderSpec(60, 0, 1000, 15, 0);
+ _inventoryPush.startFader(moveSpec);
+ }
+}
+
+void Interface::inventoryDrawerDown(const bool doCallBacks) {
+ _inventoryPush.stopFader();
+
+ if (doCallBacks) {
+ _inventoryLidCallBack.setCallBackFlag(kInventoryLidClosedFlag);
+ _inventoryLidCallBack.scheduleCallBack(kTriggerAtStart, 0, 0);
+ }
+
+ _inventoryLid.setRate(-1);
+}
+
+void Interface::inventoryLidClosed() {
+ _inventoryLid.stop();
+
+ if (!_biochipUp)
+ InputHandler::setInputHandler(_previousHandler);
+
+ _inventoryLid.hide();
+ _inventoryPush.hide();
+ _inventoryUp = false;
+}
+
+void Interface::raiseBiochipDrawer(const bool doCallBacks) {
+ if (!_inventoryUp)
+ _previousHandler = InputHandler::getCurrentHandler();
+
+ InputHandler::setInputHandler(&_biochipPanel);
+ _biochipUp = true;
+ _biochipPanel.activateInventoryPicture();
+
+ if (doCallBacks) {
+ _biochipLidCallBack.setCallBackFlag(kBiochipLidOpenFlag);
+ _biochipLidCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ }
+
+ _biochipLid.show();
+ _biochipPush.show();
+ _biochipLid.start();
+}
+
+void Interface::biochipLidOpen(const bool doCallBacks) {
+ _biochipLid.stop();
+
+ if (doCallBacks) {
+ _biochipPushCallBack.setCallBackFlag(kBiochipDrawerUpFlag);
+ _biochipPushCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ }
+
+ FaderMoveSpec moveSpec;
+ moveSpec.makeTwoKnotFaderSpec(60, 0, 0, 9, 1000);
+ _biochipPush.startFader(moveSpec);
+}
+
+void Interface::biochipDrawerUp() {
+ _biochipPush.stopFader();
+ _biochipPanel.panelUp();
+ _biochipRaised = true;
+}
+
+void Interface::lowerBiochipDrawer(const bool doCallBacks) {
+ if (_biochipRaised) {
+ _biochipRaised = false;
+ _biochipPanel.deactivateInventoryPicture();
+
+ if (doCallBacks) {
+ _biochipPushCallBack.setCallBackFlag(kBiochipDrawerDownFlag);
+ _biochipPushCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ }
+
+ FaderMoveSpec moveSpec;
+ moveSpec.makeTwoKnotFaderSpec(60, 0, 1000, 9, 0);
+ _biochipPush.startFader(moveSpec);
+ }
+}
+
+void Interface::biochipDrawerDown(const bool doCallBacks) {
+ _biochipPush.stopFader();
+
+ if (doCallBacks) {
+ _biochipLidCallBack.setCallBackFlag(kBiochipLidClosedFlag);
+ _biochipLidCallBack.scheduleCallBack(kTriggerAtStart, 0, 0);
+ }
+
+ _biochipLid.setRate(-1);
+}
+
+void Interface::biochipLidClosed() {
+ _biochipLid.stop();
+
+ if (!_inventoryUp)
+ InputHandler::setInputHandler(_previousHandler);
+
+ _biochipLid.hide();
+ _biochipPush.hide();
+ _biochipUp = false;
+}
+
+void Interface::calibrateCompass() {
+ uint32 currentValue = g_compass->getFaderValue();
+ FaderMoveSpec compassMove;
+ compassMove.makeTwoKnotFaderSpec(15, 0, currentValue, 30, currentValue + 360);
+
+ g_compass->startFader(compassMove);
+
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ while (g_compass->isFading()) {
+ vm->refreshDisplay();
+ g_system->delayMillis(10);
+ }
+
+ vm->refreshDisplay();
+ g_compass->setFaderValue(currentValue);
+}
+
+void Interface::calibrateEnergyBar() {
+ g_energyMonitor->calibrateEnergyBar();
+}
+
+void Interface::raiseInventoryDrawerSync() {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ raiseInventoryDrawer(false);
+
+ while (_inventoryLid.isRunning()) {
+ vm->checkCallBacks();
+ vm->refreshDisplay();
+ g_system->delayMillis(10);
+ }
+
+ vm->refreshDisplay();
+ inventoryLidOpen(false);
+
+ while (_inventoryPush.isFading()) {
+ vm->checkCallBacks();
+ vm->refreshDisplay();
+ g_system->delayMillis(10);
+ }
+
+ vm->refreshDisplay();
+ inventoryDrawerUp();
+}
+
+void Interface::lowerInventoryDrawerSync() {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ lowerInventoryDrawer(false);
+
+ while (_inventoryPush.isFading()) {
+ vm->checkCallBacks();
+ vm->refreshDisplay();
+ g_system->delayMillis(10);
+ }
+
+ vm->refreshDisplay();
+ inventoryDrawerDown(false);
+
+ while (_inventoryLid.isRunning()) {
+ vm->checkCallBacks();
+ vm->refreshDisplay();
+ g_system->delayMillis(10);
+ }
+
+ vm->refreshDisplay();
+ inventoryLidClosed();
+}
+
+void Interface::raiseBiochipDrawerSync() {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ raiseBiochipDrawer(false);
+
+ while (_biochipLid.isRunning()) {
+ vm->checkCallBacks();
+ vm->refreshDisplay();
+ g_system->delayMillis(10);
+ }
+
+ vm->refreshDisplay();
+ biochipLidOpen(false);
+
+ while (_biochipPush.isFading()) {
+ vm->checkCallBacks();
+ vm->refreshDisplay();
+ g_system->delayMillis(10);
+ }
+
+ vm->refreshDisplay();
+ biochipDrawerUp();
+}
+
+void Interface::lowerBiochipDrawerSync() {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ lowerBiochipDrawer(false);
+
+ while (_biochipPush.isFading()) {
+ vm->checkCallBacks();
+ vm->refreshDisplay();
+ g_system->delayMillis(10);
+ }
+
+ vm->refreshDisplay();
+ biochipDrawerDown(false);
+
+ while (_biochipLid.isRunning()) {
+ vm->checkCallBacks();
+ vm->refreshDisplay();
+ g_system->delayMillis(10);
+ }
+
+ vm->refreshDisplay();
+ biochipLidClosed();
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/interface.h b/engines/pegasus/interface.h
new file mode 100644
index 0000000000..a65d9a595a
--- /dev/null
+++ b/engines/pegasus/interface.h
@@ -0,0 +1,148 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_INTERFACE_H
+#define PEGASUS_INTERFACE_H
+
+#include "pegasus/hotspot.h"
+#include "pegasus/input.h"
+#include "pegasus/notification.h"
+#include "pegasus/surface.h"
+#include "pegasus/transition.h"
+#include "pegasus/items/inventorypicture.h"
+
+namespace Pegasus {
+
+class BiochipItem;
+class InventoryItem;
+
+class Interface : public InputHandler, public NotificationReceiver {
+public:
+ Interface();
+ virtual ~Interface();
+
+ void createInterface();
+
+ // Recalibration functions...
+ void calibrateCompass();
+ void calibrateEnergyBar();
+ void raiseInventoryDrawerSync();
+ void lowerInventoryDrawerSync();
+ void raiseBiochipDrawerSync();
+ void lowerBiochipDrawerSync();
+
+ void raiseInventoryDrawer(const bool doCallBacks = true);
+ void raiseBiochipDrawer(const bool doCallBacks = true);
+ void lowerInventoryDrawer(const bool doCallBacks = true);
+ void lowerBiochipDrawer(const bool doCallBacks = true);
+
+ void raiseInventoryDrawerForMessage();
+ void lowerInventoryDrawerForMessage();
+ bool isInventoryUp();
+ bool isInventoryDown();
+
+ InventoryResult addInventoryItem(InventoryItem *);
+ InventoryResult removeInventoryItem(InventoryItem *);
+ void removeAllItemsFromInventory();
+ InventoryItem *getCurrentInventoryItem();
+ void setCurrentInventoryItem(InventoryItem *);
+ void setCurrentInventoryItemID(ItemID);
+ InventoryResult addBiochip(BiochipItem *);
+ void removeAllItemsFromBiochips();
+ BiochipItem *getCurrentBiochip();
+ void setCurrentBiochip(BiochipItem *);
+ void setCurrentBiochipID(ItemID);
+
+ void setDate(const uint16);
+
+ void playEndMessage();
+
+ void throwAwayInterface();
+
+protected:
+ void validateBackground();
+ void validateDateMonitor();
+ void validateCompass();
+ void validateNotifications();
+ void validateAIArea();
+ void validateInventoryPanel();
+ void validateBiochipPanel();
+ void validateEnergyMonitor();
+
+ void throwAwayBackground();
+ void throwAwayDateMonitor();
+ void throwAwayCompass();
+ void throwAwayNotifications();
+ void throwAwayAIArea();
+ void throwAwayInventoryPanel();
+ void throwAwayBiochipPanel();
+ void throwAwayEnergyMonitor();
+
+ void receiveNotification(Notification *, const NotificationFlags);
+ void inventoryLidOpen(const bool doCallBacks);
+ void inventoryLidClosed();
+ void inventoryDrawerUp();
+ void inventoryDrawerDown(const bool doCallBacks);
+ void biochipLidOpen(const bool doCallBacks);
+ void biochipLidClosed();
+ void biochipDrawerUp();
+ void biochipDrawerDown(const bool doCallBacks);
+
+ Picture _background1;
+ Picture _background2;
+ Picture _background3;
+ Picture _background4;
+
+ Picture _datePicture;
+
+ InputHandler *_previousHandler;
+
+ Push _inventoryPush;
+ SpriteSequence _inventoryLid;
+ NotificationCallBack _inventoryPushCallBack;
+ NotificationCallBack _inventoryLidCallBack;
+ InventoryItemsPicture _inventoryPanel;
+ bool _inventoryUp, _inventoryRaised;
+
+ Push _biochipPush;
+ SpriteSequence _biochipLid;
+ NotificationCallBack _biochipPushCallBack;
+ NotificationCallBack _biochipLidCallBack;
+ BiochipPicture _biochipPanel;
+ bool _biochipUp, _biochipRaised;
+
+ Hotspot _currentItemSpot;
+ Hotspot _currentBiochipSpot;
+
+ Notification _interfaceNotification;
+
+ bool _playingEndMessage;
+};
+
+extern Interface *g_interface;
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/items/autodragger.cpp b/engines/pegasus/items/autodragger.cpp
new file mode 100644
index 0000000000..40bad14a89
--- /dev/null
+++ b/engines/pegasus/items/autodragger.cpp
@@ -0,0 +1,91 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/elements.h"
+#include "pegasus/items/autodragger.h"
+
+namespace Pegasus {
+
+AutoDragger::AutoDragger() {
+ _draggingElement = NULL;
+ _lastTime = 0;
+ initCallBack(this, kCallBackAtExtremes);
+}
+
+void AutoDragger::autoDrag(DisplayElement *dragElement, const Common::Point &startPoint, const Common::Point &stopPoint,
+ TimeValue dragTime, TimeScale dragScale) {
+ _draggingElement = dragElement;
+
+ if (_draggingElement) {
+ _startLocation = startPoint;
+ _stopLocation = stopPoint;
+ _lastTime = 0;
+ _done = false;
+ _draggingElement->moveElementTo(_startLocation.x, _startLocation.y);
+ setScale(dragScale);
+ setSegment(0, dragTime);
+ setTime(0);
+ scheduleCallBack(kTriggerAtStop, 0, 0);
+ startIdling();
+ start();
+ } else {
+ stopDragging();
+ }
+}
+
+void AutoDragger::stopDragging() {
+ cancelCallBack();
+ stopIdling();
+ _draggingElement = 0;
+ _startLocation = Common::Point();
+ _stopLocation = Common::Point();
+ _lastTime = 0;
+ _done = true;
+}
+
+bool AutoDragger::isDragging() {
+ return isIdling();
+}
+
+void AutoDragger::useIdleTime() {
+ TimeValue thisTime = getTime();
+
+ if (thisTime != _lastTime) {
+ int32 offsetX = (_stopLocation.x - _startLocation.x) * (int32)thisTime / (int32)getDuration();
+ int32 offsetY = (_stopLocation.y - _startLocation.y) * (int32)thisTime / (int32)getDuration();
+ _draggingElement->moveElementTo(_startLocation.x + offsetX, _startLocation.y + offsetY);
+ _lastTime = thisTime;
+ }
+
+ if (_done)
+ stopDragging();
+}
+
+void AutoDragger::callBack() {
+ if (isIdling())
+ _done = true;
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/items/autodragger.h b/engines/pegasus/items/autodragger.h
new file mode 100644
index 0000000000..6783fdf9a3
--- /dev/null
+++ b/engines/pegasus/items/autodragger.h
@@ -0,0 +1,57 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_ITEMS_AUTODRAGGER_H
+#define PEGASUS_ITEMS_AUTODRAGGER_H
+
+#include "pegasus/timers.h"
+
+namespace Pegasus {
+
+class DisplayElement;
+
+class AutoDragger : private Idler, private TimeBase, private TimeBaseCallBack {
+public:
+ AutoDragger();
+ virtual ~AutoDragger() {}
+
+ void autoDrag(DisplayElement *, const Common::Point &, const Common::Point &, TimeValue, TimeScale);
+ bool isDragging();
+ void stopDragging();
+
+protected:
+ void useIdleTime();
+ void callBack();
+
+ DisplayElement *_draggingElement;
+ Common::Point _startLocation, _stopLocation;
+ TimeValue _lastTime;
+ bool _done;
+};
+
+} // End of namespace Pegasus
+
+#endif
+
diff --git a/engines/pegasus/items/biochips/aichip.cpp b/engines/pegasus/items/biochips/aichip.cpp
new file mode 100644
index 0000000000..cbcfc363e8
--- /dev/null
+++ b/engines/pegasus/items/biochips/aichip.cpp
@@ -0,0 +1,279 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/energymonitor.h"
+#include "pegasus/gamestate.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/biochips/aichip.h"
+#include "pegasus/neighborhood/neighborhood.h"
+
+namespace Pegasus {
+
+// indexed by [number of hints][number of solves (0, 1, or 2)][which button to highlight]
+static const ItemState s_highlightState[4][3][7] = {
+ {
+ {kAI000, -1, -1, -1, -1, kAI005, kAI006},
+ {kAI010, -1, -1, -1, -1, kAI015, kAI016},
+ {kAI020, -1, -1, -1, kAI024, -1, -1}
+ },
+ {
+ {kAI100, kAI101, -1, -1, -1, kAI105, kAI106},
+ {kAI110, kAI111, -1, -1, -1, kAI115, kAI116},
+ {kAI120, kAI121, -1, -1, kAI124, kAI125, kAI126}
+ },
+ {
+ {kAI200, kAI201, kAI202, -1, -1, kAI205, kAI206},
+ {kAI210, kAI211, kAI212, -1, -1, kAI215, kAI216},
+ {kAI220, kAI221, kAI222, -1, kAI224, kAI225, kAI226}
+ },
+ {
+ {kAI300, kAI301, kAI302, kAI303, -1, kAI305, kAI306},
+ {kAI310, kAI311, kAI312, kAI313, -1, kAI315, kAI316},
+ {kAI320, kAI321, kAI322, kAI323, kAI324, kAI325, kAI326}
+ }
+};
+
+AIChip *g_AIChip = 0;
+
+AIChip::AIChip(const ItemID id, const NeighborhoodID neighborhood, const RoomID room, const DirectionConstant direction) :
+ BiochipItem(id, neighborhood, room, direction), _briefingSpot(kAIBriefingSpotID), _scanSpot(kAIScanSpotID),
+ _hint1Spot(kAIHint1SpotID), _hint2Spot(kAIHint2SpotID), _hint3Spot(kAIHint3SpotID), _solveSpot(kAISolveSpotID) {
+ _briefingSpot.setArea(Common::Rect(kAIMiddleAreaLeft + 10, kAIMiddleAreaTop + 27, kAIMiddleAreaLeft + 10 + 81, kAIMiddleAreaTop + 27 + 31));
+ _briefingSpot.setHotspotFlags(kAIBiochipSpotFlag);
+ g_allHotspots.push_back(&_briefingSpot);
+
+ _scanSpot.setArea(Common::Rect(kAIMiddleAreaLeft + 100, kAIMiddleAreaTop + 27, kAIMiddleAreaLeft + 100 + 81, kAIMiddleAreaTop + 27 + 31));
+ _scanSpot.setHotspotFlags(kAIBiochipSpotFlag);
+ g_allHotspots.push_back(&_scanSpot);
+
+ _hint1Spot.setArea(Common::Rect(kAIMiddleAreaLeft + 70, kAIMiddleAreaTop + 67, kAIMiddleAreaLeft + 70 + 21, kAIMiddleAreaTop + 67 + 21));
+ _hint1Spot.setHotspotFlags(kAIBiochipSpotFlag);
+ g_allHotspots.push_back(&_hint1Spot);
+
+ _hint2Spot.setArea(Common::Rect(kAIMiddleAreaLeft + 91, kAIMiddleAreaTop + 67, kAIMiddleAreaLeft + 91 + 20, kAIMiddleAreaTop + 67 + 21));
+ _hint2Spot.setHotspotFlags(kAIBiochipSpotFlag);
+ g_allHotspots.push_back(&_hint2Spot);
+
+ _hint3Spot.setArea(Common::Rect(kAIMiddleAreaLeft + 111, kAIMiddleAreaTop + 67, kAIMiddleAreaLeft + 111 + 20, kAIMiddleAreaTop + 67 + 21));
+ _hint3Spot.setHotspotFlags(kAIBiochipSpotFlag);
+ g_allHotspots.push_back(&_hint3Spot);
+
+ _solveSpot.setArea(Common::Rect(kAIMiddleAreaLeft + 131, kAIMiddleAreaTop + 67, kAIMiddleAreaLeft + 131 + 50, kAIMiddleAreaTop + 67 + 21));
+ _solveSpot.setHotspotFlags(kAIBiochipSpotFlag);
+ g_allHotspots.push_back(&_solveSpot);
+
+ _playingMovie = false;
+ setItemState(kAI000);
+
+ g_AIChip = this;
+}
+
+AIChip::~AIChip() {
+ g_AIChip = NULL;
+
+ g_allHotspots.removeOneHotspot(kAIBriefingSpotID);
+ g_allHotspots.removeOneHotspot(kAIScanSpotID);
+ g_allHotspots.removeOneHotspot(kAIHint1SpotID);
+ g_allHotspots.removeOneHotspot(kAIHint2SpotID);
+ g_allHotspots.removeOneHotspot(kAIHint3SpotID);
+ g_allHotspots.removeOneHotspot(kAISolveSpotID);
+}
+
+void AIChip::select() {
+ BiochipItem::select();
+ setUpAIChip();
+}
+
+void AIChip::takeSharedArea() {
+ setUpAIChip();
+}
+
+void AIChip::setUpAIChip() {
+ if (!_playingMovie) {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ uint numSolves;
+ if (GameState.getWalkthroughMode()) {
+ if (vm->canSolve())
+ numSolves = 2;
+ else
+ numSolves = 1;
+ } else {
+ numSolves = 0;
+ }
+
+ setItemState(s_highlightState[vm->getNumHints()][numSolves][0]);
+ }
+}
+
+// Only does something when there are hints or solves available.
+void AIChip::setUpAIChipRude() {
+ if (!_playingMovie) {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ uint numSolves;
+ if (GameState.getWalkthroughMode()) {
+ if (vm->canSolve())
+ numSolves = 2;
+ else
+ numSolves = 1;
+ } else {
+ numSolves = 0;
+ }
+
+ uint numHints = vm->getNumHints();
+ if (numSolves == 2 || numHints != 0)
+ setItemState(s_highlightState[numHints][numSolves][0]);
+ }
+}
+
+void AIChip::activateAIHotspots() {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+ _briefingSpot.setActive();
+ _scanSpot.setActive();
+
+ switch (vm->getNumHints()) {
+ case 3:
+ _hint3Spot.setActive();
+ // fall through
+ case 2:
+ _hint2Spot.setActive();
+ // fall through
+ case 1:
+ _hint1Spot.setActive();
+ break;
+ }
+
+ if (GameState.getWalkthroughMode() && vm->canSolve())
+ _solveSpot.setActive();
+}
+
+void AIChip::showBriefingClicked() {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ _playingMovie = true;
+
+ uint numSolves;
+ if (GameState.getWalkthroughMode()) {
+ if (vm->canSolve())
+ numSolves = 2;
+ else
+ numSolves = 1;
+ } else {
+ numSolves = 0;
+ }
+
+ ItemState newState = s_highlightState[vm->getNumHints()][numSolves][kAIBriefingSpotID - kAIHint1SpotID + 1];
+ if (newState != -1)
+ setItemState(newState);
+}
+
+void AIChip::showEnvScanClicked() {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ _playingMovie = true;
+
+ uint numSolves;
+ if (GameState.getWalkthroughMode()) {
+ if (vm->canSolve())
+ numSolves = 2;
+ else
+ numSolves = 1;
+ } else {
+ numSolves = 0;
+ }
+
+ ItemState newState = s_highlightState[vm->getNumHints()][numSolves][kAIScanSpotID - kAIHint1SpotID + 1];
+
+ if (newState != -1)
+ setItemState(newState);
+}
+
+void AIChip::clearClicked() {
+ _playingMovie = false;
+ setUpAIChip();
+}
+
+void AIChip::clickInAIHotspot(HotSpotID id) {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ Common::String movieName;
+
+ switch (id) {
+ case kAIBriefingSpotID:
+ movieName = vm->getBriefingMovie();
+ break;
+ case kAIScanSpotID:
+ movieName = vm->getEnvScanMovie();
+ break;
+ case kAIHint1SpotID:
+ movieName = vm->getHintMovie(1);
+ break;
+ case kAIHint2SpotID:
+ movieName = vm->getHintMovie(2);
+ break;
+ case kAIHint3SpotID:
+ movieName = vm->getHintMovie(3);
+ break;
+ case kAISolveSpotID:
+ g_neighborhood->doSolve();
+ break;
+ }
+
+ ItemState state = getItemState();
+
+ if (!movieName.empty()) {
+ _playingMovie = true;
+
+ uint numSolves;
+ if (GameState.getWalkthroughMode()) {
+ if (vm->canSolve())
+ numSolves = 2;
+ else
+ numSolves = 1;
+ } else {
+ numSolves = 0;
+ }
+
+ ItemState newState = s_highlightState[vm->getNumHints()][numSolves][id - kAIHint1SpotID + 1];
+
+ if (newState != -1)
+ setItemState(newState);
+
+ if (g_AIArea) {
+ vm->prepareForAIHint(movieName);
+ g_AIArea->playAIMovie(kRightAreaSignature, movieName, false, kHintInterruption);
+ vm->cleanUpAfterAIHint(movieName);
+ }
+
+ if (newState != -1)
+ setItemState(state);
+
+ _playingMovie = false;
+ }
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/items/biochips/aichip.h b/engines/pegasus/items/biochips/aichip.h
new file mode 100644
index 0000000000..7a33953612
--- /dev/null
+++ b/engines/pegasus/items/biochips/aichip.h
@@ -0,0 +1,69 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_ITEMS_BIOCHIPS_AICHIP_H
+#define PEGASUS_ITEMS_BIOCHIPS_AICHIP_H
+
+#include "pegasus/hotspot.h"
+#include "pegasus/items/biochips/biochipitem.h"
+
+namespace Pegasus {
+
+class AIChip : public BiochipItem {
+public:
+ AIChip(const ItemID, const NeighborhoodID, const RoomID, const DirectionConstant);
+ virtual ~AIChip();
+
+ void select();
+
+ void setUpAIChip();
+
+ // Called to set up the AI chip when the AI chip is the current chip but does not
+ // own the center area.
+ void setUpAIChipRude();
+ void activateAIHotspots();
+ void clickInAIHotspot(HotSpotID);
+
+ void takeSharedArea();
+
+ void showBriefingClicked();
+ void showEnvScanClicked();
+ void clearClicked();
+
+protected:
+ Hotspot _briefingSpot;
+ Hotspot _scanSpot;
+ Hotspot _hint1Spot;
+ Hotspot _hint2Spot;
+ Hotspot _hint3Spot;
+ Hotspot _solveSpot;
+ bool _playingMovie;
+};
+
+extern AIChip *g_AIChip;
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/items/biochips/biochipitem.cpp b/engines/pegasus/items/biochips/biochipitem.cpp
new file mode 100644
index 0000000000..5686948937
--- /dev/null
+++ b/engines/pegasus/items/biochips/biochipitem.cpp
@@ -0,0 +1,95 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#include "common/stream.h"
+
+#include "pegasus/pegasus.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/biochips/biochipitem.h"
+
+namespace Pegasus {
+
+BiochipItem::BiochipItem(const ItemID id, const NeighborhoodID neighborhood, const RoomID room, const DirectionConstant direction) :
+ Item(id, neighborhood, room, direction) {
+
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ Common::SeekableReadStream *biochipInfo = vm->_resFork->getResource(MKTAG('B', 'i', 'o', 'I'), kItemBaseResID + id);
+ if (biochipInfo) {
+ _biochipInfoPanelTime = biochipInfo->readUint32BE();
+ delete biochipInfo;
+ } else {
+ _biochipInfoPanelTime = 0;
+ }
+
+ Common::SeekableReadStream *rightInfo = vm->_resFork->getResource(MKTAG('R', 'g', 'h', 't'), kItemBaseResID + id);
+ if (!rightInfo)
+ error("Could not find right info for biochip %d", id);
+
+ _rightAreaInfo = readItemState(rightInfo);
+ delete rightInfo;
+
+ setItemState(kNormalItem);
+}
+
+BiochipItem::~BiochipItem() {
+ delete[] _rightAreaInfo.entries;
+}
+
+ItemType BiochipItem::getItemType() {
+ return kBiochipItemType;
+}
+
+TimeValue BiochipItem::getRightAreaTime() const {
+ if (!_rightAreaInfo.entries)
+ return 0xffffffff;
+
+ TimeValue time;
+ ItemState state;
+
+ findItemStateEntryByState(_rightAreaInfo, _itemState, time);
+ if (time == 0xffffffff)
+ getItemStateEntry(_rightAreaInfo, 0, state, time);
+
+ return time;
+}
+
+// Must affect images in right area.
+void BiochipItem::select() {
+ Item::select();
+
+ if (g_AIArea)
+ g_AIArea->setAIAreaToTime(kBiochipSignature, kRightAreaSignature, getRightAreaTime());
+}
+
+void BiochipItem::deselect() {
+ Item::deselect();
+
+ if (g_AIArea)
+ g_AIArea->setAIAreaToTime(kBiochipSignature, kRightAreaSignature, 0xffffffff);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/items/biochips/biochipitem.h b/engines/pegasus/items/biochips/biochipitem.h
new file mode 100644
index 0000000000..2039e80c6f
--- /dev/null
+++ b/engines/pegasus/items/biochips/biochipitem.h
@@ -0,0 +1,54 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_ITEMS_BIOCHIPS_BIOCHIPITEM_H
+#define PEGASUS_ITEMS_BIOCHIPS_BIOCHIPITEM_H
+
+#include "pegasus/items/item.h"
+
+namespace Pegasus {
+
+class BiochipItem : public Item {
+public:
+ BiochipItem(const ItemID, const NeighborhoodID, const RoomID, const DirectionConstant);
+ virtual ~BiochipItem();
+
+ virtual ItemType getItemType();
+
+ TimeValue getPanelTime() const { return _biochipInfoPanelTime; }
+ TimeValue getRightAreaTime() const;
+
+ // Must affect images in right area.
+ virtual void select();
+ virtual void deselect();
+
+protected:
+ TimeValue _biochipInfoPanelTime;
+ ItemStateInfo _rightAreaInfo;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/items/biochips/mapchip.cpp b/engines/pegasus/items/biochips/mapchip.cpp
new file mode 100644
index 0000000000..69050d5193
--- /dev/null
+++ b/engines/pegasus/items/biochips/mapchip.cpp
@@ -0,0 +1,106 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/gamestate.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/biochips/mapchip.h"
+#include "pegasus/neighborhood/neighborhood.h"
+
+namespace Pegasus {
+
+MapChip *g_map = 0;
+
+MapChip::MapChip(const ItemID id, const NeighborhoodID neighborhood, const RoomID room, const DirectionConstant direction) :
+ BiochipItem(id, neighborhood, room, direction) {
+ g_map = this;
+ setItemState(kMapUnavailable);
+}
+
+MapChip::~MapChip() {
+ g_map = 0;
+}
+
+void MapChip::writeToStream(Common::WriteStream *stream) {
+ return _image.writeToStream(stream);
+}
+
+void MapChip::readFromStream(Common::ReadStream *stream) {
+ return _image.readFromStream(stream);
+}
+
+void MapChip::select() {
+ BiochipItem::select();
+ moveToMapLocation(GameState.getCurrentNeighborhood(), GameState.getCurrentRoom(), GameState.getCurrentDirection());
+ _image.show();
+}
+
+void MapChip::takeSharedArea() {
+ _image.show();
+}
+
+void MapChip::giveUpSharedArea() {
+ _image.hide();
+}
+
+void MapChip::deselect() {
+ BiochipItem::deselect();
+ _image.unloadImage();
+}
+
+void MapChip::moveToMapLocation(const NeighborhoodID neighborhood, const RoomID room, const DirectionConstant dir) {
+ AirQuality airQuality;
+
+ if (g_neighborhood)
+ airQuality = g_neighborhood->getAirQuality(room);
+ else
+ airQuality = kAirQualityGood;
+
+ switch (neighborhood) {
+ case kMarsID:
+ if (airQuality == kAirQualityVacuum) {
+ if (room >= kMars35 && room <= kMars39) {
+ setItemState(kMapEngaged);
+ if (isSelected() && g_AIArea && g_AIArea->getMiddleAreaOwner() == kBiochipSignature)
+ _image.loadGearRoomIfNecessary();
+ } else {
+ setItemState(kMapEngaged);
+ if (isSelected() && g_AIArea && g_AIArea->getMiddleAreaOwner() == kBiochipSignature)
+ _image.loadMazeIfNecessary();
+ }
+
+ _image.moveToMapLocation(neighborhood, room, dir);
+ } else {
+ _image.unloadImage();
+ setItemState(kMapUnavailable);
+ }
+ break;
+ default:
+ _image.unloadImage();
+ setItemState(kMapUnavailable);
+ break;
+ }
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/items/biochips/mapchip.h b/engines/pegasus/items/biochips/mapchip.h
new file mode 100644
index 0000000000..6690090aa4
--- /dev/null
+++ b/engines/pegasus/items/biochips/mapchip.h
@@ -0,0 +1,64 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_ITEMS_BIOCHIPS_MAPCHIP_H
+#define PEGASUS_ITEMS_BIOCHIPS_MAPCHIP_H
+
+#include "pegasus/items/biochips/biochipitem.h"
+#include "pegasus/items/biochips/mapimage.h"
+
+namespace Common {
+ class ReadStream;
+ class WriteStream;
+}
+
+namespace Pegasus {
+
+class MapChip : public BiochipItem {
+public:
+ MapChip(const ItemID, const NeighborhoodID, const RoomID, const DirectionConstant);
+ virtual ~MapChip();
+
+ void select();
+ void deselect();
+ void takeSharedArea();
+ void giveUpSharedArea();
+
+ void moveToMapLocation(const NeighborhoodID, const RoomID, const DirectionConstant);
+
+ void writeToStream(Common::WriteStream *);
+ void readFromStream(Common::ReadStream *);
+
+ bool beenToMaze() { return _image.anyFlagSet(); }
+
+protected:
+ MapImage _image;
+};
+
+extern MapChip *g_map;
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/items/biochips/mapimage.cpp b/engines/pegasus/items/biochips/mapimage.cpp
new file mode 100644
index 0000000000..9f4170d063
--- /dev/null
+++ b/engines/pegasus/items/biochips/mapimage.cpp
@@ -0,0 +1,443 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/gamestate.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/items/biochips/mapimage.h"
+
+namespace Pegasus {
+
+#define FLAG_TO_INDEX(flag) ((flag) >> 2)
+#define INDEX_TO_FLAG(index) ((index) << 2)
+
+#define ROOM_TO_INDEX(room) \
+ (((room) >= kMars35 && (room) <= kMars39) ? ((room) - kMars35) : \
+ (((room) == kMars60) ? (kMars39 - kMars35 + 1) : \
+ ((room) - kMarsMaze004 + kMars39 - kMars35 + 2)))
+
+#define INDEX_TO_ROOM(index) \
+ (((index) <= ROOM_TO_INDEX(kMars39)) ? \
+ (((index) - ROOM_TO_INDEX(kMars35)) + kMars35) : \
+ ((index) <= ROOM_TO_INDEX(kMars60,)) ? kMars60 : \
+ ((((index) - ROOM_TO_INDEX(kMarsMaze004))) + kMarsMaze004))
+
+#define ROOM_TO_FLAG(room, dir) (INDEX_TO_FLAG(ROOM_TO_INDEX(room)) | (dir))
+
+#define FLAG_TO_ROOM(flag) (INDEX_TO_ROOM(FLAG_TO_INDEX(flag)))
+
+#define FLAG_TO_DIRECTION(flag) ((flag) & 3)
+
+static const int kGearRoomFlagLow = ROOM_TO_FLAG(kMars35, kNorth);
+static const int kGearRoomFlagHigh = ROOM_TO_FLAG(kMars39, kWest);
+
+static const int kMazeFlagLow = ROOM_TO_FLAG(kMars60, kNorth);
+static const int kMazeFlagHigh = ROOM_TO_FLAG(kMarsMaze200, kWest);
+
+static const CoordType kGearRoomScreenOffsetX = 49;
+static const CoordType kGearRoomScreenOffsetY = 47;
+
+static const CoordType kGearRoomGridOriginX = 1;
+static const CoordType kGearRoomGridOriginY = 4;
+
+static const CoordType kMazeScreenOffsetX = 16;
+static const CoordType kMazeScreenOffsetY = 20;
+
+static const CoordType kMazeGridOriginX = 6;
+static const CoordType kMazeGridOriginY = 1;
+
+static const CoordType kGridWidth = 4;
+static const CoordType kGridHeight = 4;
+
+static const uint16 kMapOfMazePICTID = 906;
+static const uint16 kMapOfGearRoomPICTID = 907;
+
+static const int s_mapCoords[MapImage::kNumMappingRooms][2] = {
+ /* kMars35 */ { 0, 0 },
+ /* kMars36 */ { 1, 0 },
+ /* kMars37 */ { 2, 0 },
+ /* kMars38 */ { 3, 0 },
+ /* kMars39 */ { 4, 0 },
+ /* kMars60 */ { 19, 9 },
+ /* kMarsMaze004 */ { 18, 9 },
+ /* kMarsMaze005 */ { 18, 10 },
+ /* kMarsMaze006 */ { 17, 10 },
+ /* kMarsMaze007 */ { 16, 10 },
+ /* kMarsMaze008 */ { 15, 10 },
+ /* kMarsMaze009 */ { 14, 10 },
+ /* kMarsMaze010 */ { 14, 9 },
+ /* kMarsMaze011 */ { 14, 8 },
+ /* kMarsMaze012 */ { 14, 7 },
+ /* kMarsMaze015 */ { 16, 7 },
+ /* kMarsMaze016 */ { 14, 11 },
+ /* kMarsMaze017 */ { 14, 12 },
+ /* kMarsMaze018 */ { 15, 12 },
+ /* kMarsMaze019 */ { 16, 12 },
+ /* kMarsMaze020 */ { 16, 13 },
+ /* kMarsMaze021 */ { 16, 14 },
+ /* kMarsMaze022 */ { 16, 15 },
+ /* kMarsMaze023 */ { 17, 15 },
+ /* kMarsMaze024 */ { 18, 15 },
+ /* kMarsMaze025 */ { 18, 14 },
+ /* kMarsMaze026 */ { 18, 13 },
+ /* kMarsMaze027 */ { 18, 12 },
+ /* kMarsMaze028 */ { 18, 11 },
+ /* kMarsMaze031 */ { 19, 14 },
+ /* kMarsMaze032 */ { 20, 14 },
+ /* kMarsMaze033 */ { 20, 13 },
+ /* kMarsMaze034 */ { 20, 12 },
+ /* kMarsMaze035 */ { 20, 11 },
+ /* kMarsMaze036 */ { 21, 11 },
+ /* kMarsMaze037 */ { 15, 15 },
+ /* kMarsMaze038 */ { 14, 15 },
+ /* kMarsMaze039 */ { 13, 15 },
+ /* kMarsMaze042 */ { 10, 15 },
+ /* kMarsMaze043 */ { 9, 15 },
+ /* kMarsMaze044 */ { 8, 15 },
+ /* kMarsMaze045 */ { 7, 15 },
+ /* kMarsMaze046 */ { 6, 15 },
+ /* kMarsMaze047 */ { 5, 15 },
+ /* kMarsMaze049 */ { 13, 14 },
+ /* kMarsMaze050 */ { 12, 14 },
+ /* kMarsMaze051 */ { 11, 14 },
+ /* kMarsMaze052 */ { 10, 14 },
+ /* kMarsMaze053 */ { 10, 13 },
+ /* kMarsMaze054 */ { 9, 13 },
+ /* kMarsMaze055 */ { 8, 13 },
+ /* kMarsMaze056 */ { 8, 12 },
+ /* kMarsMaze057 */ { 7, 12 },
+ /* kMarsMaze058 */ { 12, 13 },
+ /* kMarsMaze059 */ { 12, 12 },
+ /* kMarsMaze060 */ { 12, 11 },
+ /* kMarsMaze061 */ { 12, 10 },
+ /* kMarsMaze063 */ { 12, 9 },
+ /* kMarsMaze064 */ { 12, 8 },
+ /* kMarsMaze065 */ { 12, 7 },
+ /* kMarsMaze066 */ { 13, 7 },
+ /* kMarsMaze067 */ { 15, 7 },
+ /* kMarsMaze068 */ { 17, 7 },
+ /* kMarsMaze069 */ { 18, 7 },
+ /* kMarsMaze070 */ { 19, 7 },
+ /* kMarsMaze071 */ { 20, 7 },
+ /* kMarsMaze072 */ { 20, 6 },
+ /* kMarsMaze074 */ { 20, 5 },
+ /* kMarsMaze076 */ { 20, 4 },
+ /* kMarsMaze078 */ { 20, 3 },
+ /* kMarsMaze079 */ { 20, 2 },
+ /* kMarsMaze081 */ { 20, 2 },
+ /* kMarsMaze083 */ { 20, 0 },
+ /* kMarsMaze084 */ { 19, 0 },
+ /* kMarsMaze085 */ { 18, 0 },
+ /* kMarsMaze086 */ { 17, 0 },
+ /* kMarsMaze087 */ { 16, 0 },
+ /* kMarsMaze088 */ { 15, 0 },
+ /* kMarsMaze089 */ { 14, 0 },
+ /* kMarsMaze090 */ { 13, 0 },
+ /* kMarsMaze091 */ { 12, 0 },
+ /* kMarsMaze092 */ { 11, 0 },
+ /* kMarsMaze093 */ { 10, 0 },
+ /* kMarsMaze098 */ { 10, 1 },
+ /* kMarsMaze099 */ { 8, 2 },
+ /* kMarsMaze100 */ { 9, 2 },
+ /* kMarsMaze101 */ { 10, 2 },
+ /* kMarsMaze104 */ { 13, 2 },
+ /* kMarsMaze105 */ { 13, 3 },
+ /* kMarsMaze106 */ { 13, 4 },
+ /* kMarsMaze107 */ { 13, 5 },
+ /* kMarsMaze108 */ { 14, 5 },
+ /* kMarsMaze111 */ { 15, 5 },
+ /* kMarsMaze113 */ { 16, 5 },
+ /* kMarsMaze114 */ { 17, 5 },
+ /* kMarsMaze115 */ { 18, 5 },
+ /* kMarsMaze116 */ { 18, 4 },
+ /* kMarsMaze117 */ { 18, 3 },
+ /* kMarsMaze118 */ { 19, 3 },
+ /* kMarsMaze119 */ { 18, 2 },
+ /* kMarsMaze120 */ { 17, 2 },
+ /* kMarsMaze121 */ { 16, 2 },
+ /* kMarsMaze122 */ { 15, 2 },
+ /* kMarsMaze123 */ { 15, 1 },
+ /* kMarsMaze124 */ { 12, 4 },
+ /* kMarsMaze125 */ { 11, 4 },
+ /* kMarsMaze126 */ { 10, 4 },
+ /* kMarsMaze127 */ { 10, 5 },
+ /* kMarsMaze128 */ { 10, 6 },
+ /* kMarsMaze129 */ { 9, 6 },
+ /* kMarsMaze130 */ { 8, 6 },
+ /* kMarsMaze131 */ { 7, 6 },
+ /* kMarsMaze132 */ { 7, 7 },
+ /* kMarsMaze133 */ { 7, 8 },
+ /* kMarsMaze136 */ { 7, 11 },
+ /* kMarsMaze137 */ { 6, 11 },
+ /* kMarsMaze138 */ { 5, 11 },
+ /* kMarsMaze139 */ { 5, 12 },
+ /* kMarsMaze140 */ { 4, 12 },
+ /* kMarsMaze141 */ { 5, 13 },
+ /* kMarsMaze142 */ { 5, 14 },
+ /* kMarsMaze143 */ { 4, 14 },
+ /* kMarsMaze144 */ { 3, 14 },
+ /* kMarsMaze145 */ { 3, 13 },
+ /* kMarsMaze146 */ { 2, 13 },
+ /* kMarsMaze147 */ { 1, 13 },
+ /* kMarsMaze148 */ { 1, 14 },
+ /* kMarsMaze149 */ { 1, 15 },
+ /* kMarsMaze152 */ { 1, 12 },
+ /* kMarsMaze153 */ { 1, 11 },
+ /* kMarsMaze154 */ { 1, 10 },
+ /* kMarsMaze155 */ { 1, 9 },
+ /* kMarsMaze156 */ { 1, 8 },
+ /* kMarsMaze157 */ { 2, 10 },
+ /* kMarsMaze159 */ { 2, 8 },
+ /* kMarsMaze160 */ { 2, 7 },
+ /* kMarsMaze161 */ { 2, 6 },
+ /* kMarsMaze162 */ { 3, 10 },
+ /* kMarsMaze163 */ { 3, 9 },
+ /* kMarsMaze164 */ { 3, 8 },
+ /* kMarsMaze165 */ { 4, 8 },
+ /* kMarsMaze166 */ { 5, 8 },
+ /* kMarsMaze167 */ { 6, 8 },
+ /* kMarsMaze168 */ { 3, 6 },
+ /* kMarsMaze169 */ { 4, 6 },
+ /* kMarsMaze170 */ { 5, 6 },
+ /* kMarsMaze171 */ { 5, 5 },
+ /* kMarsMaze172 */ { 5, 4 },
+ /* kMarsMaze173 */ { 4, 4 },
+ /* kMarsMaze174 */ { 3, 4 },
+ /* kMarsMaze175 */ { 3, 5 },
+ /* kMarsMaze177 */ { 8, 4 },
+ /* kMarsMaze178 */ { 8, 3 },
+ /* kMarsMaze179 */ { 7, 4 },
+ /* kMarsMaze180 */ { 6, 4 },
+ /* kMarsMaze181 */ { 6, 3 },
+ /* kMarsMaze182 */ { 6, 2 },
+ /* kMarsMaze183 */ { 6, 1 },
+ /* kMarsMaze184 */ { 6, 0 },
+ /* kMarsMaze187 */ { 3, 0 },
+ /* kMarsMaze188 */ { 2, 0 },
+ /* kMarsMaze189 */ { 1, 0 },
+ /* kMarsMaze190 */ { 1, 1 },
+ /* kMarsMaze191 */ { 1, 2 },
+ /* kMarsMaze192 */ { 5, 2 },
+ /* kMarsMaze193 */ { 4, 2 },
+ /* kMarsMaze194 */ { 3, 2 },
+ /* kMarsMaze195 */ { 3, 1 },
+ /* kMarsMaze198 */ { 1, 3 },
+ /* kMarsMaze199 */ { 1, 4 },
+ /* kMarsMaze200 */ { 0, 4 }
+};
+
+MapImage::MapImage() : DisplayElement(kNoDisplayElement) {
+ _whichArea = kMapNoArea;
+ setBounds(kAIMiddleAreaLeft, kAIMiddleAreaTop, kAIMiddleAreaLeft + kAIMiddleAreaWidth, kAIMiddleAreaTop + kAIMiddleAreaHeight);
+ setDisplayOrder(kAIMiddleAreaOrder + 10);
+ startDisplaying();
+
+ _darkGreen = g_system->getScreenFormat().RGBToColor(64, 150, 10);
+ _lightGreen = g_system->getScreenFormat().RGBToColor(102, 239, 0);
+}
+
+void MapImage::writeToStream(Common::WriteStream *stream) {
+ _mappedRooms.writeToStream(stream);
+}
+
+void MapImage::readFromStream(Common::ReadStream *stream) {
+ _mappedRooms.readFromStream(stream);
+}
+
+void MapImage::loadGearRoomIfNecessary() {
+ if (_whichArea != kMapGearRoom) {
+ _mapImage.getImageFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kMapOfGearRoomPICTID);
+
+ Common::Rect bounds;
+ _mapImage.getSurfaceBounds(bounds);
+ _mapMask.allocateSurface(bounds);
+ _whichArea = kMapGearRoom;
+
+ GraphicsManager *gfx = ((PegasusEngine *)g_engine)->_gfx;
+ gfx->setCurSurface(_mapMask.getSurface());
+
+ gfx->getCurSurface()->fillRect(bounds, g_system->getScreenFormat().RGBToColor(0xff, 0xff, 0xff));
+
+ for (int i = kGearRoomFlagLow; i <= kGearRoomFlagHigh; i++)
+ if (_mappedRooms.getFlag(i))
+ addFlagToMask(i);
+
+ gfx->setCurSurface(gfx->getWorkArea());
+ show();
+ }
+}
+
+void MapImage::loadMazeIfNecessary() {
+ if (_whichArea != kMapMaze) {
+ _mapImage.getImageFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kMapOfMazePICTID);
+
+ Common::Rect bounds;
+ _mapImage.getSurfaceBounds(bounds);
+ _mapMask.allocateSurface(bounds);
+ _whichArea = kMapMaze;
+
+ GraphicsManager *gfx = ((PegasusEngine *)g_engine)->_gfx;
+ gfx->setCurSurface(_mapMask.getSurface());
+
+ gfx->getCurSurface()->fillRect(bounds, g_system->getScreenFormat().RGBToColor(0xff, 0xff, 0xff));
+
+ for (int i = kMazeFlagLow; i <= kMazeFlagHigh; i++)
+ if (_mappedRooms.getFlag(i))
+ addFlagToMask(i);
+
+ gfx->setCurSurface(gfx->getWorkArea());
+ show();
+ }
+}
+
+void MapImage::unloadImage() {
+ _mapImage.deallocateSurface();
+ _mapMask.deallocateSurface();
+ hide();
+ _whichArea = kMapNoArea;
+}
+
+void MapImage::moveToMapLocation(const NeighborhoodID, const RoomID room, const DirectionConstant dir) {
+ GraphicsManager *gfx = ((PegasusEngine *)g_engine)->_gfx;
+
+ int flag = ROOM_TO_FLAG(room, dir);
+
+ if (!_mappedRooms.getFlag(flag)) {
+ _mappedRooms.setFlag(flag, true);
+
+ if (_mapMask.isSurfaceValid()) {
+ gfx->setCurSurface(_mapMask.getSurface());
+ addFlagToMask(flag);
+ gfx->setCurSurface(gfx->getWorkArea());
+ }
+ }
+
+ if (isDisplaying())
+ triggerRedraw();
+}
+
+void MapImage::addFlagToMask(const int flag) {
+ Common::Rect r1;
+ getRevealedRects(flag, r1);
+ ((PegasusEngine *)g_engine)->_gfx->getCurSurface()->fillRect(r1, g_system->getScreenFormat().RGBToColor(0, 0, 0));
+}
+
+// This function can even be sensitive to open doors.
+// clone2727 notices that it's not, though
+void MapImage::getRevealedRects(const uint32 flag, Common::Rect &r1) {
+ CoordType gridX, gridY;
+
+ switch (_whichArea) {
+ case kMapMaze:
+ gridX = kMazeGridOriginX;
+ gridY = kMazeGridOriginY;
+ break;
+ case kMapGearRoom:
+ gridX = kGearRoomGridOriginX;
+ gridY = kGearRoomGridOriginY;
+ break;
+ default:
+ return;
+ }
+
+ int index = FLAG_TO_INDEX(flag);
+ gridX += s_mapCoords[index][0] * kGridWidth;
+ gridY += s_mapCoords[index][1] * kGridHeight;
+
+ r1 = Common::Rect(gridX - 1, gridY - 1, gridX + kGridWidth + 1, gridY + kGridHeight + 1);
+}
+
+void MapImage::drawPlayer() {
+ Graphics::Surface *screen = ((PegasusEngine *)g_engine)->_gfx->getCurSurface();
+
+ CoordType gridX, gridY;
+
+ switch (_whichArea) {
+ case kMapMaze:
+ gridX = _bounds.left + kMazeScreenOffsetX + kMazeGridOriginX;
+ gridY = _bounds.top + kMazeScreenOffsetY + kMazeGridOriginY;
+ break;
+ case kMapGearRoom:
+ gridX = _bounds.left + kGearRoomScreenOffsetX + kGearRoomGridOriginX;
+ gridY = _bounds.top + kGearRoomScreenOffsetY + kGearRoomGridOriginY;
+ break;
+ default:
+ return;
+ }
+
+ int index = ROOM_TO_INDEX(GameState.getCurrentRoom());
+ gridX += s_mapCoords[index][0] * kGridWidth;
+ gridY += s_mapCoords[index][1] * kGridHeight;
+
+ // This was intended to make little arrows
+ switch (GameState.getCurrentDirection()) {
+ case kNorth:
+ screen->drawLine(gridX + 1, gridY, gridX + 2, gridY, _darkGreen);
+ screen->drawLine(gridX, gridY + 1, gridX + 3, gridY + 1, _darkGreen);
+ screen->drawLine(gridX + 1, gridY + 1, gridX + 2, gridY + 1, _lightGreen);
+ screen->drawLine(gridX, gridY + 2, gridX + 3, gridY + 2, _lightGreen);
+ break;
+ case kSouth:
+ screen->drawLine(gridX + 1, gridY + 3, gridX + 2, gridY + 3, _darkGreen);
+ screen->drawLine(gridX, gridY + 2, gridX + 3, gridY + 2, _darkGreen);
+ screen->drawLine(gridX + 1, gridY + 2, gridX + 2, gridY + 2, _lightGreen);
+ screen->drawLine(gridX, gridY + 1, gridX + 3, gridY + 1, _lightGreen);
+ break;
+ case kEast:
+ screen->drawLine(gridX + 3, gridY + 1, gridX + 3, gridY + 2, _darkGreen);
+ screen->drawLine(gridX + 2, gridY, gridX + 2, gridY + 3, _darkGreen);
+ screen->drawLine(gridX + 2, gridY + 1, gridX + 2, gridY + 2, _lightGreen);
+ screen->drawLine(gridX + 1, gridY, gridX + 1, gridY + 3, _lightGreen);
+ break;
+ case kWest:
+ screen->drawLine(gridX, gridY + 1, gridX, gridY + 2, _darkGreen);
+ screen->drawLine(gridX + 1, gridY, gridX + 1, gridY + 3, _darkGreen);
+ screen->drawLine(gridX + 1, gridY + 1, gridX + 1, gridY + 2, _lightGreen);
+ screen->drawLine(gridX + 2, gridY, gridX + 2, gridY + 3, _lightGreen);
+ break;
+ }
+}
+
+void MapImage::draw(const Common::Rect &) {
+ Common::Rect r1;
+ _mapImage.getSurfaceBounds(r1);
+
+ Common::Rect r2 = r1;
+ switch (_whichArea) {
+ case kMapMaze:
+ r2.moveTo(_bounds.left + kMazeScreenOffsetX, _bounds.top + kMazeScreenOffsetY);
+ break;
+ case kMapGearRoom:
+ r2.moveTo(_bounds.left + kGearRoomScreenOffsetX, _bounds.top + kGearRoomScreenOffsetY);
+ break;
+ default:
+ return;
+ }
+
+ _mapImage.copyToCurrentPortMasked(r1, r2, &_mapMask);
+
+ drawPlayer();
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/items/biochips/mapimage.h b/engines/pegasus/items/biochips/mapimage.h
new file mode 100644
index 0000000000..49ad9945ee
--- /dev/null
+++ b/engines/pegasus/items/biochips/mapimage.h
@@ -0,0 +1,84 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_ITEMS_BIOCHIPS_MAPIMAGE_H
+#define PEGASUS_ITEMS_BIOCHIPS_MAPIMAGE_H
+
+#include "pegasus/elements.h"
+#include "pegasus/surface.h"
+#include "pegasus/util.h"
+#include "pegasus/neighborhood/mars/constants.h"
+
+namespace Common {
+ class ReadStream;
+ class WriteStream;
+}
+
+namespace Pegasus {
+
+class MapImage : public DisplayElement {
+public:
+ MapImage();
+ virtual ~MapImage() {}
+
+ void writeToStream(Common::WriteStream *);
+ void readFromStream(Common::ReadStream *);
+
+ void loadGearRoomIfNecessary();
+ void loadMazeIfNecessary();
+ void unloadImage();
+ void moveToMapLocation(const NeighborhoodID, const RoomID, const DirectionConstant);
+
+ void draw(const Common::Rect &);
+
+ bool anyFlagSet() { return _mappedRooms.anyFlagSet(); }
+
+ static const uint32 kNumMappingRooms = (kMars39 - kMars35 + 1) + (kMars60 - kMars60 + 1) +
+ (kMarsMaze200 - kMarsMaze004 + 1);
+ static const uint32 kNumMappingFlags = kNumMappingRooms * 4;
+
+protected:
+ enum MapArea {
+ kMapNoArea,
+ kMapMaze,
+ kMapGearRoom
+ };
+
+ void addFlagToMask(const int flag);
+ void getRevealedRects(const uint32, Common::Rect &);
+ void drawPlayer();
+
+ MapArea _whichArea;
+
+ FlagsArray<byte, kNumMappingFlags> _mappedRooms;
+
+ uint32 _darkGreen, _lightGreen;
+
+ Surface _mapImage, _mapMask;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/items/biochips/opticalchip.cpp b/engines/pegasus/items/biochips/opticalchip.cpp
new file mode 100644
index 0000000000..7b8858edae
--- /dev/null
+++ b/engines/pegasus/items/biochips/opticalchip.cpp
@@ -0,0 +1,190 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/pegasus.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/biochips/opticalchip.h"
+
+namespace Pegasus {
+
+OpticalChip *g_opticalChip = 0;
+
+OpticalChip::OpticalChip(const ItemID id, const NeighborhoodID neighborhood, const RoomID room, const DirectionConstant direction) :
+ BiochipItem(id, neighborhood, room, direction), _ariesHotspot(kAriesSpotID), _mercuryHotspot(kMercurySpotID),
+ _poseidonHotspot(kPoseidonSpotID) {
+ _ariesHotspot.setArea(Common::Rect(kAIMiddleAreaLeft + 60, kAIMiddleAreaTop + 27, kAIMiddleAreaLeft + 60 + 121, kAIMiddleAreaTop + 27 + 20));
+ _ariesHotspot.setHotspotFlags(kOpticalBiochipSpotFlag);
+ g_allHotspots.push_back(&_ariesHotspot);
+
+ _mercuryHotspot.setArea(Common::Rect(kAIMiddleAreaLeft + 60, kAIMiddleAreaTop + 47, kAIMiddleAreaLeft + 60 + 121, kAIMiddleAreaTop + 47 + 20));
+ _mercuryHotspot.setHotspotFlags(kOpticalBiochipSpotFlag);
+ g_allHotspots.push_back(&_mercuryHotspot);
+
+ _poseidonHotspot.setArea(Common::Rect(kAIMiddleAreaLeft + 60, kAIMiddleAreaTop + 67, kAIMiddleAreaLeft + 60 + 121, kAIMiddleAreaTop + 67 + 20));
+ _poseidonHotspot.setHotspotFlags(kOpticalBiochipSpotFlag);
+ g_allHotspots.push_back(&_poseidonHotspot);
+
+ setItemState(kOptical000);
+
+ g_opticalChip = this;
+}
+
+OpticalChip::~OpticalChip() {
+ g_allHotspots.removeOneHotspot(kAriesSpotID);
+ g_allHotspots.removeOneHotspot(kMercurySpotID);
+ g_allHotspots.removeOneHotspot(kPoseidonSpotID);
+}
+
+void OpticalChip::writeToStream(Common::WriteStream *stream) {
+ BiochipItem::writeToStream(stream);
+ _opticalFlags.writeToStream(stream);
+}
+
+void OpticalChip::readFromStream(Common::ReadStream *stream) {
+ BiochipItem::readFromStream(stream);
+ _opticalFlags.readFromStream(stream);
+}
+
+void OpticalChip::addAries() {
+ _opticalFlags.setFlag(kOpticalAriesExposed, true);
+ setUpOpticalChip();
+}
+
+void OpticalChip::addMercury() {
+ _opticalFlags.setFlag(kOpticalMercuryExposed, true);
+ setUpOpticalChip();
+}
+
+void OpticalChip::addPoseidon() {
+ _opticalFlags.setFlag(kOpticalPoseidonExposed, true);
+ setUpOpticalChip();
+}
+
+void OpticalChip::setUpOpticalChip() {
+ if (_opticalFlags.getFlag(kOpticalAriesExposed)) {
+ if (_opticalFlags.getFlag(kOpticalMercuryExposed)) {
+ if (_opticalFlags.getFlag(kOpticalPoseidonExposed))
+ setItemState(kOptical111);
+ else
+ setItemState(kOptical011);
+ } else {
+ if (_opticalFlags.getFlag(kOpticalPoseidonExposed))
+ setItemState(kOptical101);
+ else
+ setItemState(kOptical001);
+ }
+ } else {
+ if (_opticalFlags.getFlag(kOpticalMercuryExposed)) {
+ if (_opticalFlags.getFlag(kOpticalPoseidonExposed))
+ setItemState(kOptical110);
+ else
+ setItemState(kOptical010);
+ } else {
+ if (_opticalFlags.getFlag(kOpticalPoseidonExposed))
+ setItemState(kOptical100);
+ else
+ setItemState(kOptical000);
+ }
+ }
+}
+
+void OpticalChip::activateOpticalHotspots() {
+ if (_opticalFlags.getFlag(kOpticalAriesExposed))
+ _ariesHotspot.setActive();
+ if (_opticalFlags.getFlag(kOpticalMercuryExposed))
+ _mercuryHotspot.setActive();
+ if (_opticalFlags.getFlag(kOpticalPoseidonExposed))
+ _poseidonHotspot.setActive();
+}
+
+void OpticalChip::clickInOpticalHotspot(HotSpotID id) {
+ playOpMemMovie(id);
+}
+
+void OpticalChip::playOpMemMovie(HotSpotID id) {
+ Common::String movieName;
+ switch (id) {
+ case kAriesSpotID:
+ movieName = "Images/AI/Globals/OMAI";
+ break;
+ case kMercurySpotID:
+ movieName = "Images/AI/Globals/OMMI";
+ break;
+ case kPoseidonSpotID:
+ movieName = "Images/AI/Globals/OMPI";
+ break;
+ }
+
+ ItemState state = getItemState(), newState;
+ switch (state) {
+ case kOptical001:
+ newState = kOptical002;
+ break;
+ case kOptical010:
+ newState = kOptical020;
+ break;
+ case kOptical011:
+ if (id == kAriesSpotID)
+ newState = kOptical012;
+ else
+ newState = kOptical021;
+ break;
+ case kOptical100:
+ newState = kOptical200;
+ break;
+ case kOptical101:
+ if (id == kAriesSpotID)
+ newState = kOptical102;
+ else
+ newState = kOptical201;
+ break;
+ case kOptical110:
+ if (id == kMercurySpotID)
+ newState = kOptical120;
+ else
+ newState = kOptical210;
+ break;
+ case kOptical111:
+ if (id == kAriesSpotID)
+ newState = kOptical112;
+ else if (id == kMercurySpotID)
+ newState = kOptical121;
+ else
+ newState = kOptical211;
+ break;
+ case kOptical000: // Can never happen.
+ default:
+ error("Invalid optical chip state");
+ }
+
+ setItemState(newState);
+
+ if (g_AIArea)
+ g_AIArea->playAIMovie(kRightAreaSignature, movieName, false, kOpticalInterruption);
+
+ setItemState(state);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/items/biochips/opticalchip.h b/engines/pegasus/items/biochips/opticalchip.h
new file mode 100644
index 0000000000..2f66f73d3a
--- /dev/null
+++ b/engines/pegasus/items/biochips/opticalchip.h
@@ -0,0 +1,71 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_ITEMS_BIOCHIPS_OPTICALCHIP_H
+#define PEGASUS_ITEMS_BIOCHIPS_OPTICALCHIP_H
+
+#include "pegasus/hotspot.h"
+#include "pegasus/util.h"
+#include "pegasus/items/biochips/biochipitem.h"
+
+namespace Pegasus {
+
+class OpticalChip : public BiochipItem {
+public:
+ OpticalChip(const ItemID, const NeighborhoodID, const RoomID, const DirectionConstant);
+ virtual ~OpticalChip();
+
+ virtual void writeToStream(Common::WriteStream *);
+ virtual void readFromStream(Common::ReadStream *);
+
+ void addAries();
+ void addMercury();
+ void addPoseidon();
+
+ void activateOpticalHotspots();
+ void clickInOpticalHotspot(HotSpotID);
+ void playOpMemMovie(HotSpotID);
+
+protected:
+ enum {
+ kOpticalAriesExposed,
+ kOpticalMercuryExposed,
+ kOpticalPoseidonExposed,
+ kNumOpticalChipFlags
+ };
+
+ void setUpOpticalChip();
+
+ FlagsArray<byte, kNumOpticalChipFlags> _opticalFlags;
+ Hotspot _ariesHotspot;
+ Hotspot _mercuryHotspot;
+ Hotspot _poseidonHotspot;
+};
+
+extern OpticalChip *g_opticalChip;
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/items/biochips/pegasuschip.cpp b/engines/pegasus/items/biochips/pegasuschip.cpp
new file mode 100644
index 0000000000..fa551fce30
--- /dev/null
+++ b/engines/pegasus/items/biochips/pegasuschip.cpp
@@ -0,0 +1,198 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/energymonitor.h"
+#include "pegasus/gamestate.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/items/biochips/pegasuschip.h"
+#include "pegasus/neighborhood/tsa/fulltsa.h"
+#include "pegasus/neighborhood/tsa/tinytsa.h"
+
+namespace Pegasus {
+
+PegasusChip::PegasusChip(const ItemID id, const NeighborhoodID neighborhood, const RoomID room, const DirectionConstant direction) :
+ BiochipItem(id, neighborhood, room, direction), _recallSpot(kPegasusRecallSpotID) {
+ _recallSpot.setArea(Common::Rect(kAIMiddleAreaLeft + 116, kAIMiddleAreaTop + 63, kAIMiddleAreaLeft + 184, kAIMiddleAreaTop + 91));
+ _recallSpot.setHotspotFlags(kPegasusBiochipSpotFlag);
+ g_allHotspots.push_back(&_recallSpot);
+ setItemState(kPegasusTSA00);
+}
+
+PegasusChip::~PegasusChip() {
+ g_allHotspots.removeOneHotspot(kPegasusRecallSpotID);
+}
+
+void PegasusChip::select() {
+ BiochipItem::select();
+ setUpPegasusChip();
+}
+
+void PegasusChip::setUpPegasusChip() {
+ switch (GameState.getCurrentNeighborhood()) {
+ case kCaldoriaID:
+ setItemState(kPegasusCaldoria);
+ break;
+ case kFullTSAID:
+ case kFinalTSAID:
+ case kTinyTSAID:
+ setItemState(kPegasusTSA10);
+ break;
+ case kPrehistoricID:
+ if (((PegasusEngine *)g_engine)->playerHasItemID(kHistoricalLog))
+ setItemState(kPegasusPrehistoric00);
+ else
+ setItemState(kPegasusPrehistoric10);
+ break;
+ case kMarsID:
+ if (GameState.getMarsFinished())
+ setItemState(kPegasusMars00);
+ else
+ setItemState(kPegasusMars10);
+ break;
+ case kWSCID:
+ if (GameState.getWSCFinished())
+ setItemState(kPegasusWSC00);
+ else
+ setItemState(kPegasusWSC10);
+ break;
+ case kNoradAlphaID:
+ case kNoradDeltaID:
+ if (GameState.getNoradFinished())
+ setItemState(kPegasusNorad00);
+ else
+ setItemState(kPegasusNorad10);
+ break;
+ }
+}
+
+// Only does something if the chip should be announcing that the time zone is finished...
+void PegasusChip::setUpPegasusChipRude() {
+ switch (GameState.getCurrentNeighborhood()) {
+ case kPrehistoricID:
+ if (((PegasusEngine *)g_engine)->playerHasItemID(kHistoricalLog))
+ setItemState(kPegasusPrehistoric00);
+ break;
+ case kMarsID:
+ if (GameState.getMarsFinished())
+ setItemState(kPegasusMars00);
+ break;
+ case kWSCID:
+ if (GameState.getWSCFinished())
+ setItemState(kPegasusWSC00);
+ break;
+ case kNoradAlphaID:
+ case kNoradDeltaID:
+ if (GameState.getNoradFinished())
+ setItemState(kPegasusNorad00);
+ break;
+ }
+}
+
+void PegasusChip::activatePegasusHotspots() {
+ switch (GameState.getCurrentNeighborhood()) {
+ case kPrehistoricID:
+ // WORKAROUND: Don't allow the player to recall if they don't have
+ // the historical log. Otherwise, gameplay is broken when returning
+ // to the TSA.
+ if (!((PegasusEngine *)g_engine)->playerHasItemID(kHistoricalLog))
+ return;
+ // fall through
+ case kMarsID:
+ case kWSCID:
+ case kNoradAlphaID:
+ case kNoradDeltaID:
+ _recallSpot.setActive();
+ break;
+ }
+}
+
+void PegasusChip::clickInPegasusHotspot() {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ ItemState thisState = getItemState();
+ ItemState hiliteState;
+
+ switch (thisState) {
+ case kPegasusPrehistoric00:
+ hiliteState = kPegasusPrehistoric01;
+ break;
+ case kPegasusPrehistoric10:
+ hiliteState = kPegasusPrehistoric11;
+ break;
+ case kPegasusMars00:
+ hiliteState = kPegasusMars01;
+ break;
+ case kPegasusMars10:
+ hiliteState = kPegasusMars11;
+ break;
+ case kPegasusNorad00:
+ hiliteState = kPegasusNorad01;
+ break;
+ case kPegasusNorad10:
+ hiliteState = kPegasusNorad11;
+ break;
+ case kPegasusWSC00:
+ hiliteState = kPegasusWSC01;
+ break;
+ case kPegasusWSC10:
+ hiliteState = kPegasusWSC11;
+ break;
+ default:
+ error("Invalid pegasus chip state");
+ }
+
+ // WORKAROUND: The original called setItemState() here. However,
+ // since we're overriding select() to call setUpPegasusChip(),
+ // the highlighted frame is never displayed! So, we're manually
+ // setting the state and selecting the item. Also of note is that
+ // setItemState() for this class is effectively useless since it
+ // always gets overriden in the select() function. The only reason
+ // that this doesn't end in infinite recursion is because setItemState()
+ // has a check against the current state to make sure you don't call
+ // select() again. </rant>
+ _itemState = hiliteState;
+ BiochipItem::select();
+
+ uint32 time = g_system->getMillis();
+ while (g_system->getMillis() < time + 500) {
+ vm->refreshDisplay();
+ g_system->delayMillis(10);
+ }
+
+ setItemState(thisState);
+
+ if (!((Neighborhood *)g_neighborhood)->okayToJump())
+ return;
+
+ if (g_energyMonitor)
+ g_energyMonitor->stopEnergyDraining();
+
+ if (GameState.getTSAState() == kPlayerWentToPrehistoric || GameState.allTimeZonesFinished())
+ vm->jumpToNewEnvironment(kFullTSAID, kTSA37, kNorth);
+ else
+ vm->jumpToNewEnvironment(kTinyTSAID, kTinyTSA37, kNorth);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/items/biochips/pegasuschip.h b/engines/pegasus/items/biochips/pegasuschip.h
new file mode 100644
index 0000000000..7597424821
--- /dev/null
+++ b/engines/pegasus/items/biochips/pegasuschip.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.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_ITEMS_BIOCHIPS_PEGASUSCHIP_H
+#define PEGASUS_ITEMS_BIOCHIPS_PEGASUSCHIP_H
+
+#include "pegasus/hotspot.h"
+#include "pegasus/items/biochips/biochipitem.h"
+
+namespace Pegasus {
+
+class PegasusChip : public BiochipItem {
+public:
+ PegasusChip(const ItemID, const NeighborhoodID, const RoomID, const DirectionConstant);
+ virtual ~PegasusChip();
+
+ void select();
+
+ void setUpPegasusChip();
+
+ // Called to set up the Pegasus chip when the Pegasus chip is the current chip but does not
+ // own the center area.
+ void setUpPegasusChipRude();
+ void activatePegasusHotspots();
+ void clickInPegasusHotspot();
+
+protected:
+ Hotspot _recallSpot;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/items/biochips/retscanchip.cpp b/engines/pegasus/items/biochips/retscanchip.cpp
new file mode 100644
index 0000000000..84b74a63d2
--- /dev/null
+++ b/engines/pegasus/items/biochips/retscanchip.cpp
@@ -0,0 +1,49 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/biochips/retscanchip.h"
+
+namespace Pegasus {
+
+RetScanChip::RetScanChip(const ItemID id, const NeighborhoodID neighborhood, const RoomID room, const DirectionConstant direction) :
+ BiochipItem(id, neighborhood, room, direction) {
+}
+
+void RetScanChip::searchForLaser() {
+ ItemExtraEntry entry;
+ findItemExtra(kRetinalScanSearching, entry);
+
+ if (g_AIArea)
+ g_AIArea->playAIAreaSequence(kBiochipSignature, kMiddleAreaSignature, entry.extraStart, entry.extraStop);
+
+ findItemExtra(kRetinalScanActivated, entry);
+ if (g_AIArea)
+ g_AIArea->playAIAreaSequence(kBiochipSignature, kRightAreaSignature, entry.extraStart, entry.extraStop);
+
+ setItemState(kRetinalSimulating);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/items/biochips/retscanchip.h b/engines/pegasus/items/biochips/retscanchip.h
new file mode 100644
index 0000000000..153e6cd071
--- /dev/null
+++ b/engines/pegasus/items/biochips/retscanchip.h
@@ -0,0 +1,43 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_ITEMS_BIOCHIPS_RETSCANCHIP_H
+#define PEGASUS_ITEMS_BIOCHIPS_RETSCANCHIP_H
+
+#include "pegasus/items/biochips/biochipitem.h"
+
+namespace Pegasus {
+
+class RetScanChip : public BiochipItem {
+public:
+ RetScanChip(const ItemID, const NeighborhoodID, const RoomID, const DirectionConstant);
+ virtual ~RetScanChip() {}
+
+ void searchForLaser();
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/items/biochips/shieldchip.cpp b/engines/pegasus/items/biochips/shieldchip.cpp
new file mode 100644
index 0000000000..58cbfcc4ec
--- /dev/null
+++ b/engines/pegasus/items/biochips/shieldchip.cpp
@@ -0,0 +1,53 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/gamestate.h"
+#include "pegasus/items/biochips/shieldchip.h"
+#include "pegasus/neighborhood/neighborhood.h"
+
+namespace Pegasus {
+
+ShieldChip *g_shield = 0;
+
+ShieldChip::ShieldChip(const ItemID id, const NeighborhoodID neighborhood, const RoomID room, const DirectionConstant direction) :
+ BiochipItem(id, neighborhood, room, direction) {
+ g_shield = this;
+}
+
+void ShieldChip::select() {
+ BiochipItem::select();
+ GameState.setShieldOn(true);
+ if (g_neighborhood)
+ g_neighborhood->shieldOn();
+}
+
+void ShieldChip::deselect() {
+ BiochipItem::deselect();
+ GameState.setShieldOn(false);
+ if (g_neighborhood)
+ g_neighborhood->shieldOff();
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/items/biochips/shieldchip.h b/engines/pegasus/items/biochips/shieldchip.h
new file mode 100644
index 0000000000..69c6369236
--- /dev/null
+++ b/engines/pegasus/items/biochips/shieldchip.h
@@ -0,0 +1,46 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_ITEMS_BIOCHIPS_SHIELDCHIP_H
+#define PEGASUS_ITEMS_BIOCHIPS_SHIELDCHIP_H
+
+#include "pegasus/items/biochips/biochipitem.h"
+
+namespace Pegasus {
+
+class ShieldChip : public BiochipItem {
+public:
+ ShieldChip(const ItemID, const NeighborhoodID, const RoomID, const DirectionConstant);
+ virtual ~ShieldChip() {}
+
+ void select();
+ void deselect();
+};
+
+extern ShieldChip *g_shield;
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/items/inventory.cpp b/engines/pegasus/items/inventory.cpp
new file mode 100644
index 0000000000..57923b105d
--- /dev/null
+++ b/engines/pegasus/items/inventory.cpp
@@ -0,0 +1,175 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/constants.h"
+#include "pegasus/items/item.h"
+#include "pegasus/items/inventory.h"
+
+namespace Pegasus {
+
+Inventory::Inventory() {
+ _weightLimit = 100;
+ _ownerID = kNoActorID;
+ _referenceCount = 0;
+}
+
+Inventory::~Inventory() {
+}
+
+void Inventory::setWeightLimit(WeightType limit) {
+ _weightLimit = limit;
+ // *** What to do if the new weight limit is greater than the current weight?
+}
+
+WeightType Inventory::getWeight() {
+ WeightType result = 0;
+
+ for (ItemIterator it = _inventoryList.begin(); it != _inventoryList.end(); it++)
+ result += (*it)->getItemWeight();
+
+ return result;
+}
+
+// If the item already belongs, just return kInventoryOK.
+InventoryResult Inventory::addItem(Item *item) {
+ if (itemInInventory(item))
+ return kInventoryOK;
+
+ if (getWeight() + item->getItemWeight() > _weightLimit)
+ return kTooMuchWeight;
+
+ _inventoryList.push_back(item);
+ item->setItemOwner(_ownerID);
+
+ ++_referenceCount;
+ return kInventoryOK;
+}
+
+InventoryResult Inventory::removeItem(Item *item) {
+ for (ItemIterator it = _inventoryList.begin(); it != _inventoryList.end(); it++) {
+ if (*it == item) {
+ _inventoryList.erase(it);
+ item->setItemOwner(kNoActorID);
+
+ ++_referenceCount;
+ return kInventoryOK;
+ }
+ }
+
+ return kItemNotInInventory;
+}
+
+InventoryResult Inventory::removeItem(ItemID id) {
+ Item *item = findItemByID(id);
+
+ if (item) {
+ _inventoryList.remove(item);
+ item->setItemOwner(kNoActorID);
+
+ ++_referenceCount;
+ return kInventoryOK;
+ }
+
+ return kItemNotInInventory;
+}
+
+void Inventory::removeAllItems() {
+ _inventoryList.clear();
+ ++_referenceCount;
+}
+
+bool Inventory::itemInInventory(Item *item) {
+ for (ItemIterator it = _inventoryList.begin(); it != _inventoryList.end(); it++)
+ if (*it == item)
+ return true;
+
+ return false;
+}
+
+bool Inventory::itemInInventory(ItemID id) {
+ return findItemByID(id) != NULL;
+}
+
+Item *Inventory::getItemAt(int32 index) {
+ int32 i = 0;
+ for (ItemIterator it = _inventoryList.begin(); it != _inventoryList.end(); it++, i++)
+ if (i == index)
+ return *it;
+
+ return 0;
+}
+
+ItemID Inventory::getItemIDAt(int32 index) {
+ Item *item = getItemAt(index);
+
+ if (item)
+ return item->getObjectID();
+
+ return kNoItemID;
+}
+
+Item *Inventory::findItemByID(ItemID id) {
+ return _inventoryList.findItemByID(id);
+}
+
+// Return -1 if not found.
+
+int32 Inventory::findIndexOf(Item *item) {
+ uint32 i = 0;
+ for (ItemIterator it = _inventoryList.begin(); it != _inventoryList.end(); it++, i++)
+ if (*it == item)
+ return i;
+
+ return -1;
+}
+
+// Return -1 if not found.
+
+int32 Inventory::findIndexOf(ItemID id) {
+ uint32 i = 0;
+ for (ItemIterator it = _inventoryList.begin(); it != _inventoryList.end(); it++, i++)
+ if ((*it)->getObjectID() == id)
+ return i;
+
+ return -1;
+}
+
+WeightType Inventory::getWeightLimit() {
+ return _weightLimit;
+}
+
+int32 Inventory::getNumItems() {
+ return _inventoryList.size();
+}
+
+void Inventory::setOwnerID(const ActorID id) {
+ _ownerID = id;
+}
+
+ActorID Inventory::getOwnerID() const {
+ return _ownerID;
+}
+
+} // End of namespae Pegasus
diff --git a/engines/pegasus/items/inventory.h b/engines/pegasus/items/inventory.h
new file mode 100644
index 0000000000..796ec49556
--- /dev/null
+++ b/engines/pegasus/items/inventory.h
@@ -0,0 +1,80 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_ITEMS_INVENTORY_H
+#define PEGASUS_ITEMS_INVENTORY_H
+
+#include "pegasus/types.h"
+#include "pegasus/items/itemlist.h"
+
+namespace Pegasus {
+
+class Item;
+
+// Inventories have a "current item". This item is the default item the player can
+// use. In a text adventure system, the current item would be "it", as in
+// "Hit the troll with it," where "it" would refer to some weapon which is the current
+// item. In a graphic adventure, the current item would be the item the user selects
+// to use with the mouse or other pointing device.
+
+class Inventory {
+public:
+ Inventory();
+ virtual ~Inventory();
+
+ WeightType getWeightLimit();
+ void setWeightLimit(WeightType limit);
+ WeightType getWeight();
+
+ virtual InventoryResult addItem(Item *item);
+ virtual InventoryResult removeItem(Item *item);
+ virtual InventoryResult removeItem(ItemID id);
+ virtual bool itemInInventory(Item *item);
+ virtual bool itemInInventory(ItemID id);
+ virtual Item *getItemAt(int32 index);
+ virtual ItemID getItemIDAt(int32 index);
+ virtual Item *findItemByID(ItemID id);
+ virtual int32 findIndexOf(Item *item);
+ virtual int32 findIndexOf(ItemID id);
+ int32 getNumItems();
+ virtual void removeAllItems();
+
+ void setOwnerID(const ActorID id);
+ ActorID getOwnerID() const;
+
+ uint32 getReferenceCount() { return _referenceCount; }
+
+protected:
+ WeightType _weightLimit;
+ ActorID _ownerID;
+ ItemList _inventoryList;
+
+private:
+ uint32 _referenceCount;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/items/inventory/airmask.cpp b/engines/pegasus/items/inventory/airmask.cpp
new file mode 100644
index 0000000000..c65dd36102
--- /dev/null
+++ b/engines/pegasus/items/inventory/airmask.cpp
@@ -0,0 +1,249 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/gamestate.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/inventory/airmask.h"
+#include "pegasus/neighborhood/neighborhood.h"
+
+namespace Pegasus {
+
+AirMask *g_airMask = 0;
+
+// Based on full == 100, which is scale used by GetAirLeft().
+static const TimeValue kOxygenLowThreshold = 25;
+
+void AirMask::airMaskTimerExpired() {
+ if (g_neighborhood)
+ g_neighborhood->checkAirMask();
+}
+
+AirMask::AirMask(const ItemID id, const NeighborhoodID neighborhood, const RoomID room, const DirectionConstant direction) :
+ InventoryItem(id, neighborhood, room, direction), _toggleSpot(kAirMaskToggleSpotID) {
+ g_airMask = this;
+ _toggleSpot.setArea(Common::Rect(kAIMiddleAreaLeft + 10, kAIMiddleAreaTop + 17, kAIMiddleAreaLeft + 110, kAIMiddleAreaTop + 57));
+ _toggleSpot.setHotspotFlags(kAirMaskSpotFlag);
+ g_allHotspots.push_back(&_toggleSpot);
+ setItemState(kAirMaskEmptyOff);
+ _oxygenTimer.primeFuse(0);
+ _oxygenTimer.setFunctor(new Common::Functor0Mem<void, AirMask>(this, &AirMask::airMaskTimerExpired));
+}
+
+AirMask::~AirMask() {
+ g_allHotspots.removeOneHotspot(kAirMaskToggleSpotID);
+ g_airMask = 0;
+}
+
+void AirMask::writeToStream(Common::WriteStream *stream) {
+ InventoryItem::writeToStream(stream);
+ stream->writeUint32BE(_oxygenTimer.getTimeRemaining());
+}
+
+void AirMask::readFromStream(Common::ReadStream *stream) {
+ _oxygenTimer.stopFuse();
+ InventoryItem::readFromStream(stream);
+ _oxygenTimer.primeFuse(stream->readUint32BE());
+}
+
+void AirMask::putMaskOn() {
+ AirQuality airQuality;
+
+ if (g_neighborhood)
+ airQuality = g_neighborhood->getAirQuality(GameState.getCurrentRoom());
+ else
+ airQuality = kAirQualityGood;
+
+ uint airLevel = getAirLeft();
+ ItemState newState = getItemState();
+ ItemState oldState = newState;
+
+ if (airLevel == 0) {
+ newState = kAirMaskEmptyFilter;
+ } else if (airLevel <= kOxygenLowThreshold) {
+ if (airQuality == kAirQualityVacuum)
+ newState = kAirMaskLowOn;
+ else
+ newState = kAirMaskLowFilter;
+ } else {
+ if (airQuality == kAirQualityVacuum)
+ newState = kAirMaskFullOn;
+ else
+ newState = kAirMaskFullFilter;
+ }
+
+ if (newState != oldState)
+ setItemState(newState);
+}
+
+void AirMask::takeMaskOff() {
+ uint airLevel = getAirLeft();
+ ItemState newState = getItemState();
+ ItemState oldState = newState;
+
+ if (airLevel == 0)
+ newState = kAirMaskEmptyOff;
+ else if (airLevel <= kOxygenLowThreshold)
+ newState = kAirMaskLowOff;
+ else
+ newState = kAirMaskFullOff;
+
+ if (newState != oldState)
+ setItemState(newState);
+}
+
+void AirMask::toggleItemState() {
+ if (isAirMaskInUse())
+ takeMaskOff();
+ else
+ putMaskOn();
+}
+
+void AirMask::airQualityChanged() {
+ if (isAirMaskInUse())
+ putMaskOn();
+ else
+ takeMaskOff();
+}
+
+void AirMask::setItemState(const ItemState newState) {
+ if (newState != getItemState()) {
+ InventoryItem::setItemState(newState);
+
+ switch (newState) {
+ case kAirMaskFullOn:
+ case kAirMaskLowOn:
+ if (!_oxygenTimer.isFuseLit()) {
+ _oxygenTimer.lightFuse();
+ startIdling();
+ }
+ break;
+ default:
+ if (_oxygenTimer.isFuseLit()) {
+ _oxygenTimer.stopFuse();
+ stopIdling();
+ }
+ break;
+ }
+
+ if (g_neighborhood)
+ g_neighborhood->checkAirMask();
+
+ g_AIArea->checkMiddleArea();
+ }
+}
+
+void AirMask::useIdleTime() {
+ if (getAirLeft() == 0)
+ setItemState(kAirMaskEmptyOff);
+ else if (getAirLeft() <= kOxygenLowThreshold)
+ setItemState(kAirMaskLowOn);
+}
+
+void AirMask::refillAirMask() {
+ switch (getItemState()) {
+ case kAirMaskEmptyOff:
+ case kAirMaskLowOff:
+ setItemState(kAirMaskFullOff);
+ break;
+ case kAirMaskEmptyFilter:
+ case kAirMaskLowFilter:
+ setItemState(kAirMaskFullFilter);
+ break;
+ case kAirMaskLowOn:
+ setItemState(kAirMaskFullOn);
+ break;
+ }
+
+ if (_oxygenTimer.isFuseLit()) {
+ _oxygenTimer.stopFuse();
+ _oxygenTimer.primeFuse(kOxyMaskFullTime);
+ _oxygenTimer.lightFuse();
+ } else {
+ _oxygenTimer.primeFuse(kOxyMaskFullTime);
+ }
+}
+
+// Doesn't return 0 until the timer is actually at 0.
+uint AirMask::getAirLeft() {
+ return CLIP<int>(((_oxygenTimer.getTimeRemaining() * 100) + kOxyMaskFullTime - 1) / kOxyMaskFullTime, 0, 100);
+}
+
+bool AirMask::isAirMaskInUse() {
+ switch (getItemState()) {
+ case kAirMaskEmptyOff:
+ case kAirMaskLowOff:
+ case kAirMaskFullOff:
+ return false;
+ break;
+ default:
+ return true;
+ break;
+ }
+}
+
+bool AirMask::isAirMaskOn() {
+ switch (getItemState()) {
+ case kAirMaskLowOn:
+ case kAirMaskFullOn:
+ return true;
+ break;
+ default:
+ return false;
+ break;
+ }
+}
+
+bool AirMask::isAirFilterOn() {
+ switch (getItemState()) {
+ case kAirMaskEmptyFilter:
+ case kAirMaskLowFilter:
+ case kAirMaskFullFilter:
+ return true;
+ break;
+ default:
+ return false;
+ break;
+ }
+}
+
+void AirMask::addedToInventory() {
+ GameState.setMarsMaskOnFiller(false);
+}
+
+void AirMask::removedFromInventory() {
+ if (isAirMaskInUse())
+ toggleItemState();
+}
+
+void AirMask::activateAirMaskHotspots() {
+ _toggleSpot.setActive();
+}
+
+void AirMask::clickInAirMaskHotspot() {
+ toggleItemState();
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/items/inventory/airmask.h b/engines/pegasus/items/inventory/airmask.h
new file mode 100644
index 0000000000..6a2d708a6c
--- /dev/null
+++ b/engines/pegasus/items/inventory/airmask.h
@@ -0,0 +1,76 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_ITEMS_INVENTORY_AIRMASK_H
+#define PEGASUS_ITEMS_INVENTORY_AIRMASK_H
+
+#include "pegasus/hotspot.h"
+#include "pegasus/timers.h"
+#include "pegasus/items/inventory/inventoryitem.h"
+
+namespace Pegasus {
+
+class AirMask : public InventoryItem, private Idler {
+public:
+ AirMask(const ItemID, const NeighborhoodID, const RoomID, const DirectionConstant);
+ virtual ~AirMask();
+
+ virtual void writeToStream(Common::WriteStream *);
+ virtual void readFromStream(Common::ReadStream *);
+
+ virtual void setItemState(const ItemState);
+ void putMaskOn();
+ void takeMaskOff();
+ void toggleItemState();
+ void airQualityChanged();
+
+ bool isAirMaskInUse();
+ bool isAirMaskOn();
+ bool isAirFilterOn();
+
+ void refillAirMask();
+
+ // Returns a percentage
+ uint getAirLeft();
+
+ void activateAirMaskHotspots();
+ void clickInAirMaskHotspot();
+
+protected:
+ void airMaskTimerExpired();
+
+ virtual void removedFromInventory();
+ virtual void addedToInventory();
+ void useIdleTime();
+
+ Hotspot _toggleSpot;
+ FuseFunction _oxygenTimer;
+};
+
+extern AirMask *g_airMask;
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/items/inventory/gascanister.cpp b/engines/pegasus/items/inventory/gascanister.cpp
new file mode 100644
index 0000000000..bf63cc6542
--- /dev/null
+++ b/engines/pegasus/items/inventory/gascanister.cpp
@@ -0,0 +1,46 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/inventory/gascanister.h"
+
+namespace Pegasus {
+
+GasCanister::GasCanister(const ItemID id, const NeighborhoodID neighborhood, const RoomID room, const DirectionConstant direction) :
+ InventoryItem(id, neighborhood, room, direction) {
+}
+
+void GasCanister::select() {
+ InventoryItem::select();
+ takeSharedArea();
+}
+
+void GasCanister::takeSharedArea() {
+ ItemExtraEntry entry;
+ findItemExtra(kGasCanLoop, entry);
+ g_AIArea->loopAIAreaSequence(kInventorySignature, kMiddleAreaSignature, entry.extraStart, entry.extraStop);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/items/inventory/gascanister.h b/engines/pegasus/items/inventory/gascanister.h
new file mode 100644
index 0000000000..7d4d8193f5
--- /dev/null
+++ b/engines/pegasus/items/inventory/gascanister.h
@@ -0,0 +1,44 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_ITEMS_INVENTORY_GASCANISTER_H
+#define PEGASUS_ITEMS_INVENTORY_GASCANISTER_H
+
+#include "pegasus/items/inventory/inventoryitem.h"
+
+namespace Pegasus {
+
+class GasCanister : public InventoryItem {
+public:
+ GasCanister(const ItemID, const NeighborhoodID, const RoomID, const DirectionConstant);
+ virtual ~GasCanister() {}
+
+ void select();
+ void takeSharedArea();
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/items/inventory/inventoryitem.cpp b/engines/pegasus/items/inventory/inventoryitem.cpp
new file mode 100644
index 0000000000..4399708879
--- /dev/null
+++ b/engines/pegasus/items/inventory/inventoryitem.cpp
@@ -0,0 +1,110 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/stream.h"
+
+#include "pegasus/pegasus.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/inventory/inventoryitem.h"
+
+namespace Pegasus {
+
+InventoryItem::InventoryItem(const ItemID id, const NeighborhoodID neighborhood, const RoomID room, const DirectionConstant direction) :
+ Item(id, neighborhood, room, direction) {
+
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ Common::SeekableReadStream *leftInfo = vm->_resFork->getResource(MKTAG('L', 'e', 'f', 't'), kItemBaseResID + id);
+ if (leftInfo) {
+ _leftAreaInfo = readItemState(leftInfo);
+ delete leftInfo;
+ } else {
+ _leftAreaInfo.numEntries = 0;
+ _leftAreaInfo.entries = 0;
+ }
+
+ Common::SeekableReadStream *inventoryInfo = vm->_resFork->getResource(MKTAG('I', 'n', 'v', 'I'), kItemBaseResID + id);
+ if (inventoryInfo) {
+ _inventoryInfo.panelStart = inventoryInfo->readUint32BE();
+ _inventoryInfo.panelStop = inventoryInfo->readUint32BE();
+ delete inventoryInfo;
+ } else {
+ _inventoryInfo.panelStart = _inventoryInfo.panelStop = 0;
+ }
+
+ _itemAnimationTime = 0;
+}
+
+InventoryItem::~InventoryItem() {
+ delete[] _leftAreaInfo.entries;
+}
+
+ItemType InventoryItem::getItemType() {
+ return kInventoryItemType;
+}
+
+TimeValue InventoryItem::getLeftAreaTime() const {
+ if (!_leftAreaInfo.entries)
+ return 0xffffffff;
+
+ TimeValue time;
+ ItemState state;
+
+ findItemStateEntryByState(_leftAreaInfo, _itemState, time);
+ if (time == 0xffffffff)
+ getItemStateEntry(_leftAreaInfo, 0, state, time);
+
+ return time;
+}
+
+void InventoryItem::setAnimationTime(const TimeValue time) {
+ _itemAnimationTime = time;
+}
+
+TimeValue InventoryItem::getAnimationTime() const {
+ return _itemAnimationTime;
+}
+
+// Must affect images in left area.
+void InventoryItem::select() {
+ Item::select();
+
+ if (g_AIArea)
+ g_AIArea->setAIAreaToTime(kInventorySignature, kLeftAreaSignature, getLeftAreaTime());
+}
+
+void InventoryItem::deselect() {
+ Item::deselect();
+
+ if (g_AIArea)
+ g_AIArea->setAIAreaToTime(kInventorySignature, kLeftAreaSignature, 0xffffffff);
+}
+
+void InventoryItem::getPanelTimes(TimeValue &start, TimeValue &stop) const {
+ start = _inventoryInfo.panelStart;
+ stop = _inventoryInfo.panelStop;
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/items/inventory/inventoryitem.h b/engines/pegasus/items/inventory/inventoryitem.h
new file mode 100644
index 0000000000..9d78113014
--- /dev/null
+++ b/engines/pegasus/items/inventory/inventoryitem.h
@@ -0,0 +1,67 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_ITEMS_INVENTORY_INVENTORYITEM_H
+#define PEGASUS_ITEMS_INVENTORY_INVENTORYITEM_H
+
+#include "pegasus/items/item.h"
+
+namespace Pegasus {
+
+// JMPInventoryInfo contains the resource data used by InventoryItems.
+
+struct JMPInventoryInfo {
+ TimeValue panelStart;
+ TimeValue panelStop;
+};
+
+class InventoryItem : public Item {
+public:
+ InventoryItem(const ItemID, const NeighborhoodID, const RoomID, const DirectionConstant);
+ virtual ~InventoryItem();
+
+ virtual ItemType getItemType();
+
+ void getPanelTimes(TimeValue &, TimeValue &) const;
+ TimeValue getLeftAreaTime() const;
+
+ void setAnimationTime(const TimeValue);
+ TimeValue getAnimationTime() const;
+
+ virtual void toggleItemState() {}
+
+ // Must affect images in left area.
+ virtual void select();
+ virtual void deselect();
+
+protected:
+ JMPInventoryInfo _inventoryInfo;
+ ItemStateInfo _leftAreaInfo;
+ TimeValue _itemAnimationTime;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/items/inventory/keycard.cpp b/engines/pegasus/items/inventory/keycard.cpp
new file mode 100644
index 0000000000..c818b6675b
--- /dev/null
+++ b/engines/pegasus/items/inventory/keycard.cpp
@@ -0,0 +1,59 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/pegasus.h"
+#include "pegasus/items/inventory/keycard.h"
+
+namespace Pegasus {
+
+KeyCard::KeyCard(const ItemID id, const NeighborhoodID neighborhood, const RoomID room, const DirectionConstant direction) :
+ InventoryItem(id, neighborhood, room, direction) {
+ setItemState(kFlashlightOff);
+}
+
+void KeyCard::toggleItemState() {
+ if (getItemState() == kFlashlightOff)
+ setItemState(kFlashlightOn);
+ else
+ setItemState(kFlashlightOff);
+}
+
+void KeyCard::setItemState(const ItemState newState) {
+ if (newState != getItemState()) {
+ InventoryItem::setItemState(newState);
+ ((PegasusEngine *)g_engine)->checkFlashlight();
+ }
+}
+
+bool KeyCard::isFlashlightOn() {
+ return getItemState() == kFlashlightOn;
+}
+
+void KeyCard::removedFromInventory() {
+ if (isFlashlightOn())
+ setItemState(kFlashlightOff);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/items/inventory/keycard.h b/engines/pegasus/items/inventory/keycard.h
new file mode 100644
index 0000000000..846f40e6e5
--- /dev/null
+++ b/engines/pegasus/items/inventory/keycard.h
@@ -0,0 +1,48 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_ITEMS_INVENTORY_KEYCARD_H
+#define PEGASUS_ITEMS_INVENTORY_KEYCARD_H
+
+#include "pegasus/items/inventory/inventoryitem.h"
+
+namespace Pegasus {
+
+class KeyCard : public InventoryItem {
+public:
+ KeyCard(const ItemID, const NeighborhoodID, const RoomID, const DirectionConstant);
+ virtual ~KeyCard() {}
+
+ virtual void toggleItemState();
+ virtual void setItemState(const ItemState);
+ bool isFlashlightOn();
+
+protected:
+ virtual void removedFromInventory();
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/items/inventorypicture.cpp b/engines/pegasus/items/inventorypicture.cpp
new file mode 100644
index 0000000000..fc812faae2
--- /dev/null
+++ b/engines/pegasus/items/inventorypicture.cpp
@@ -0,0 +1,370 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/pegasus.h"
+#include "pegasus/transition.h"
+#include "pegasus/items/inventorypicture.h"
+#include "pegasus/items/biochips/biochipitem.h"
+#include "pegasus/items/inventory/inventoryitem.h"
+
+namespace Pegasus {
+
+InventoryPicture::InventoryPicture(const DisplayElementID id, InputHandler *nextHandler, Inventory *inventory) :
+ InputHandler(nextHandler), Picture(id), _panelMovie(kNoDisplayElement){
+ _inventory = inventory;
+ _lastReferenceCount = 0xffffffff;
+
+ if (_inventory->getNumItems() > 0) {
+ _currentItemIndex = 0;
+ _currentItem = (Item *)_inventory->getItemAt(0);
+ } else {
+ _currentItemIndex = -1;
+ _currentItem = 0;
+ }
+
+ _active = false;
+ _shouldDrawHighlight = true;
+ _itemsPerRow = 1;
+ _numberOfRows = 1;
+ _itemWidth = 0;
+ _itemHeight = 0;
+ _itemX = 0;
+ _itemY = 0;
+}
+
+void InventoryPicture::initInventoryImage(Transition *transition) {
+ initFromPICTFile(_pictName, true);
+ _panelMovie.shareSurface(this);
+ _panelMovie.initFromMovieFile(_movieName);
+ _panelMovie.getBounds(_highlightBounds);
+ _panelMovie.setTriggeredElement(transition);
+ _highlightImage.initFromPICTFile(_highlightName, true);
+}
+
+void InventoryPicture::throwAwayInventoryImage() {
+ if (isSurfaceValid()) {
+ _panelMovie.releaseMovie();
+ _highlightImage.deallocateSurface();
+ deallocateSurface();
+ }
+}
+
+void InventoryPicture::getItemXY(uint32 index, CoordType &x, CoordType &y) {
+ x = (index % _itemsPerRow) * _itemWidth + _itemX;
+ y = (index / _itemsPerRow) * _itemHeight + _itemY;
+}
+
+void InventoryPicture::drawItemHighlight(const Common::Rect &r) {
+ if (_highlightImage.isSurfaceValid()) {
+ Common::Rect r2 = _highlightBounds;
+ Common::Rect bounds;
+ getBounds(bounds);
+
+ r2.translate(bounds.left, bounds.top);
+ r2 = r2.findIntersectingRect(r);
+ if (!r2.isEmpty()) {
+ Common::Rect r1 = r2;
+ r1.translate(-bounds.left - _highlightBounds.left, -bounds.top - _highlightBounds.top);
+ _highlightImage.drawImage(r1, r2);
+ }
+ }
+}
+
+void InventoryPicture::draw(const Common::Rect &r) {
+ Picture::draw(r);
+ if (_inventory->getNumItems() != 0 && _shouldDrawHighlight)
+ drawItemHighlight(r);
+}
+
+// Assumes index >= 0.
+void InventoryPicture::setCurrentItemIndex(int32 index) {
+ if (index >= _inventory->getNumItems())
+ index = _inventory->getNumItems() - 1;
+
+ Item *currentItem = 0;
+ if (index >= 0)
+ currentItem = (Item *)_inventory->getItemAt(index);
+
+ if (currentItem != _currentItem) {
+ if (_currentItem) {
+ if (_currentItem->isSelected())
+ _currentItem->deselect();
+
+ if (_active)
+ unhighlightCurrentItem();
+ }
+
+ _currentItemIndex = index;
+ _currentItem = currentItem;
+ if (_currentItem) {
+ _currentItem->select();
+
+ if (_active)
+ highlightCurrentItem();
+ }
+
+ if (_active)
+ triggerRedraw();
+ }
+}
+
+void InventoryPicture::setCurrentItemID(ItemID id) {
+ int32 index = _inventory->findIndexOf(id);
+ if (index >= 0)
+ setCurrentItemIndex(index);
+}
+
+InventoryResult InventoryPicture::addInventoryItem(Item *item) {
+ InventoryResult result = _inventory->addItem(item);
+
+ if (result == kInventoryOK)
+ setCurrentItemIndex(_inventory->findIndexOf(item));
+
+ return result;
+}
+
+InventoryResult InventoryPicture::removeInventoryItem(Item *item) {
+ InventoryResult result = _inventory->removeItem(item);
+
+ if (result == kInventoryOK)
+ setCurrentItemIndex(getCurrentItemIndex());
+
+ return result;
+}
+
+void InventoryPicture::removeAllItems() {
+ _inventory->removeAllItems();
+ setCurrentItemIndex(0);
+}
+
+bool InventoryPicture::itemInInventory(Item *item) {
+ return _inventory->itemInInventory(item);
+}
+
+bool InventoryPicture::itemInInventory(const ItemID id) {
+ return _inventory->itemInInventory(id);
+}
+
+void InventoryPicture::panelUp() {
+ allowInput(true);
+}
+
+// Must ensure that the picture matches the _inventory member variable.
+void InventoryPicture::activateInventoryPicture() {
+ if (_active)
+ return;
+
+ allowInput(false);
+
+ if (_lastReferenceCount != _inventory->getReferenceCount()) {
+ uint32 numItems = _inventory->getNumItems();
+
+ CoordType x, y;
+ getItemXY(0, x, y);
+ _panelMovie.moveMovieBoxTo(x, y);
+ _panelMovie.show();
+
+ for (uint32 i = 0; i < numItems; i++) {
+ Item *item = (Item *)_inventory->getItemAt(i);
+ if (item == _currentItem)
+ item->select();
+
+ getItemXY(i, x, y);
+ _panelMovie.moveMovieBoxTo(x, y);
+ _panelMovie.setTime(getItemPanelTime(item));
+ _panelMovie.redrawMovieWorld();
+ }
+
+ uint32 numSlots = _itemsPerRow * _numberOfRows;
+
+ for (uint32 i = numItems; i < numSlots; i++) {
+ getItemXY(i, x, y);
+ _panelMovie.moveMovieBoxTo(x, y);
+ _panelMovie.setTime(0);
+ _panelMovie.redrawMovieWorld();
+ }
+
+ _lastReferenceCount = _inventory->getReferenceCount();
+ }
+
+ show(); // *** Do we really need this?
+ if (_currentItem)
+ highlightCurrentItem();
+
+ _active = true;
+}
+
+void InventoryPicture::deactivateInventoryPicture() {
+ if (!_active)
+ return;
+
+ _active = false;
+ allowInput(false);
+ _panelMovie.hide();
+ hide();
+
+ if (_inventory->getNumItems() != 0)
+ if (!_currentItem->isActive())
+ _currentItem->activate();
+}
+
+void InventoryPicture::handleInput(const Input &input, const Hotspot *cursorSpot) {
+ if (_active) {
+ if (input.upButtonDown()) {
+ if (_currentItemIndex - _itemsPerRow >= 0)
+ setCurrentItemIndex(_currentItemIndex - _itemsPerRow);
+ } else if (input.downButtonDown()) {
+ if (_currentItemIndex + _itemsPerRow < _inventory->getNumItems())
+ setCurrentItemIndex(_currentItemIndex + _itemsPerRow);
+ } else if (input.leftButtonDown()) {
+ if ((_currentItemIndex % _itemsPerRow) != 0)
+ setCurrentItemIndex(_currentItemIndex - 1);
+ } else if (input.rightButtonDown()) {
+ if (((_currentItemIndex + 1) % _itemsPerRow) != 0 && _currentItemIndex + 1 < _inventory->getNumItems())
+ setCurrentItemIndex(_currentItemIndex + 1);
+ }
+ }
+
+ InputHandler::handleInput(input, cursorSpot);
+}
+
+void InventoryPicture::highlightCurrentItem() {
+ CoordType x, y;
+ getItemXY(_currentItemIndex, x, y);
+ _highlightBounds.moveTo(x, y);
+}
+
+InventoryItemsPicture::InventoryItemsPicture(const DisplayElementID id, InputHandler *nextHandler, Inventory *inventory) :
+ InventoryPicture(id, nextHandler, inventory) {
+ _pictName = "Images/Items/Inventory/Inventory Panel";
+ _movieName = "Images/Items/Inventory/Inventory Panel Movie";
+ _highlightName = "Images/Items/Inventory/Inventory Hilite";
+
+ _itemsPerRow = 3;
+ _numberOfRows = 3;
+ _itemWidth = 88;
+ _itemHeight = 64;
+ _itemX = 8;
+ _itemY = 26;
+ _isLooping = true;
+}
+
+void InventoryItemsPicture::loopCurrentItem() {
+ if (_isLooping) {
+ CoordType x, y;
+ getItemXY(_currentItemIndex, x, y);
+ _panelMovie.moveMovieBoxTo(x, y);
+ _highlightBounds.moveTo(x, y);
+
+ TimeValue start, stop;
+ ((InventoryItem *)_currentItem)->getPanelTimes(start, stop);
+ _panelMovie.stop();
+ _panelMovie.setFlags(0);
+ _panelMovie.setSegment(start, stop);
+ _panelMovie.setFlags(kLoopTimeBase);
+ _panelMovie.setTime(((InventoryItem *)_currentItem)->getAnimationTime());
+ _panelMovie.start();
+ }
+}
+
+void InventoryItemsPicture::highlightCurrentItem() {
+ InventoryPicture::highlightCurrentItem();
+ loopCurrentItem();
+}
+
+void InventoryItemsPicture::unhighlightCurrentItem() {
+ InventoryPicture::unhighlightCurrentItem();
+ _panelMovie.stop();
+ _panelMovie.setFlags(0);
+ ((InventoryItem *)_currentItem)->setAnimationTime(_panelMovie.getTime());
+}
+
+TimeValue InventoryItemsPicture::getItemPanelTime(Item *item) {
+ TimeValue start, stop;
+ ((InventoryItem *)item)->getPanelTimes(start, stop);
+ ((InventoryItem *)item)->setAnimationTime(start);
+ return start;
+}
+
+void InventoryItemsPicture::deactivateInventoryPicture() {
+ if (_active) {
+ InventoryPicture::deactivateInventoryPicture();
+ _panelMovie.stop();
+ _panelMovie.setFlags(0);
+ _panelMovie.setSegment(0, _panelMovie.getDuration());
+ _isLooping = true;
+ }
+}
+
+void InventoryItemsPicture::playEndMessage(DisplayElement *pushElement) {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ Movie endMessage(0);
+
+ _shouldDrawHighlight = false;
+ endMessage.shareSurface(this);
+ endMessage.initFromMovieFile("Images/Caldoria/A56 Congrats");
+ endMessage.moveMovieBoxTo(kFinalMessageLeft - kInventoryPushLeft, kFinalMessageTop - kInventoryPushTop);
+ endMessage.setTriggeredElement(pushElement);
+ endMessage.start();
+
+ while (endMessage.isRunning()) {
+ vm->checkCallBacks();
+ vm->refreshDisplay();
+ g_system->delayMillis(10);
+ }
+
+ endMessage.stop();
+}
+
+BiochipPicture::BiochipPicture(const DisplayElementID id, InputHandler *nextHandler, Inventory *inventory) :
+ InventoryPicture(id, nextHandler, inventory) {
+ _pictName = "Images/Items/Biochips/Biochip Panel";
+ _movieName = "Images/Items/Biochips/Biochip Panel Movie";
+ _highlightName = "Images/Items/Biochips/BioChip Hilite";
+
+ _itemsPerRow = 4;
+ _numberOfRows = 2;
+ _itemWidth = 46;
+ _itemHeight = 46;
+ _itemX = 4;
+ _itemY = 24;
+}
+
+void BiochipPicture::unhighlightCurrentItem() {
+ InventoryPicture::unhighlightCurrentItem();
+ CoordType x, y;
+ getItemXY(_currentItemIndex, x, y);
+ _panelMovie.show();
+ _panelMovie.moveMovieBoxTo(x, y);
+ _panelMovie.setTime(getItemPanelTime(_currentItem));
+ _panelMovie.redrawMovieWorld();
+}
+
+TimeValue BiochipPicture::getItemPanelTime(Item *item) {
+ return ((BiochipItem *)item)->getPanelTime();
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/items/inventorypicture.h b/engines/pegasus/items/inventorypicture.h
new file mode 100644
index 0000000000..88a4a4ba75
--- /dev/null
+++ b/engines/pegasus/items/inventorypicture.h
@@ -0,0 +1,125 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_ITEMS_INVENTORYPICTURE_H
+#define PEGASUS_ITEMS_INVENTORYPICTURE_H
+
+#include "pegasus/input.h"
+#include "pegasus/movie.h"
+#include "pegasus/surface.h"
+
+namespace Pegasus {
+
+class Inventory;
+class Item;
+class Input;
+class Transition;
+
+class InventoryPicture : public InputHandler, public Picture {
+public:
+ InventoryPicture(const DisplayElementID, InputHandler *, Inventory *);
+ virtual ~InventoryPicture() {}
+
+ void initInventoryImage(Transition *);
+ void throwAwayInventoryImage();
+
+ void panelUp();
+ void activateInventoryPicture();
+ void deactivateInventoryPicture();
+ void handleInput(const Input &, const Hotspot *);
+ bool wantsCursor() { return false; }
+
+ InventoryResult addInventoryItem(Item *);
+ InventoryResult removeInventoryItem(Item *);
+ void removeAllItems();
+ Item *getCurrentItem() { return _currentItem; }
+ void setCurrentItemIndex(int32);
+ void setCurrentItemID(ItemID);
+ int32 getCurrentItemIndex() { return _currentItemIndex; }
+ bool itemInInventory(Item *);
+ bool itemInInventory(const ItemID);
+
+protected:
+ void getItemXY(uint32, CoordType &, CoordType &);
+ void draw(const Common::Rect &);
+ void drawItemHighlight(const Common::Rect &);
+ virtual void highlightCurrentItem();
+ virtual void unhighlightCurrentItem() {}
+ virtual TimeValue getItemPanelTime(Item *) = 0;
+
+ Inventory *_inventory;
+ uint32 _lastReferenceCount;
+ Frame _highlightImage;
+ Movie _panelMovie;
+ int32 _currentItemIndex;
+ Item *_currentItem;
+ Common::Rect _highlightBounds;
+ bool _active, _shouldDrawHighlight;
+
+ Common::String _pictName;
+ Common::String _movieName;
+ Common::String _highlightName;
+ uint16 _itemsPerRow;
+ uint16 _numberOfRows;
+ uint16 _itemWidth;
+ uint16 _itemHeight;
+ uint16 _itemX;
+ uint16 _itemY;
+};
+
+class InventoryItemsPicture : public InventoryPicture {
+public:
+ InventoryItemsPicture(const DisplayElementID, InputHandler *, Inventory *);
+ virtual ~InventoryItemsPicture() {}
+
+ void deactivateInventoryPicture();
+
+ void disableLooping() { _isLooping = false; }
+
+ void playEndMessage(DisplayElement *);
+
+protected:
+ virtual void highlightCurrentItem();
+ virtual void unhighlightCurrentItem();
+ virtual TimeValue getItemPanelTime(Item *);
+ void loopCurrentItem();
+
+ InputHandler *_previousHandler;
+ bool _isLooping;
+};
+
+class BiochipPicture : public InventoryPicture {
+public:
+ BiochipPicture(const DisplayElementID, InputHandler *, Inventory *);
+ virtual ~BiochipPicture() {}
+
+protected:
+ virtual void unhighlightCurrentItem();
+ virtual TimeValue getItemPanelTime(Item *);
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/items/item.cpp b/engines/pegasus/items/item.cpp
new file mode 100644
index 0000000000..8089f2b93d
--- /dev/null
+++ b/engines/pegasus/items/item.cpp
@@ -0,0 +1,314 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/error.h"
+#include "common/stream.h"
+
+#include "pegasus/constants.h"
+#include "pegasus/elements.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/surface.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/item.h"
+#include "pegasus/items/itemlist.h"
+#include "pegasus/items/biochips/biochipitem.h"
+#include "pegasus/items/inventory/inventoryitem.h"
+
+namespace Pegasus {
+
+Item::Item(const ItemID id, const NeighborhoodID neighborhood, const RoomID room, const DirectionConstant direction) : IDObject(id) {
+ _itemNeighborhood = neighborhood;
+ _itemRoom = room;
+ _itemDirection = direction;
+ _itemWeight = 1;
+ _itemOwnerID = kNoActorID;
+ _itemState = 0;
+
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ Common::SeekableReadStream *info = vm->_resFork->getResource(kItemInfoResType, kItemBaseResID + id);
+ if (info) {
+ _itemInfo.infoLeftTime = info->readUint32BE();
+ _itemInfo.infoRightStart = info->readUint32BE();
+ _itemInfo.infoRightStop = info->readUint32BE();
+ _itemInfo.dragSpriteNormalID = info->readUint16BE();
+ _itemInfo.dragSpriteUsedID = info->readUint16BE();
+
+ if (vm->isDemo()) {
+ // Adjust info right times to account for the stuff that was chopped out of the
+ // info right movies.
+ // Assumes time scale of 600.
+
+ // Gap times in seconds
+ static const TimeValue kGap1 = 24;
+ static const TimeValue kGap2 = 34;
+ static const TimeValue kGap3 = 4;
+ static const TimeValue kGap4 = 4;
+
+ static const TimeValue kGapForGroup1 = kGap1;
+ static const TimeValue kGapForGroup2 = kGapForGroup1 + kGap2;
+ static const TimeValue kGapForGroup3 = kGapForGroup2 + kGap3;
+ static const TimeValue kGapForGroup4 = kGapForGroup3 + kGap4;
+
+ switch (id) {
+ case kHistoricalLog:
+ case kJourneymanKey:
+ case kKeyCard:
+ _itemInfo.infoRightStart -= 600 * kGapForGroup1;
+ _itemInfo.infoRightStop -= 600 * kGapForGroup1;
+ break;
+ case kAIBiochip:
+ _itemInfo.infoRightStart -= 600 * kGapForGroup2;
+ _itemInfo.infoRightStop -= 600 * kGapForGroup2;
+ break;
+ case kMapBiochip:
+ _itemInfo.infoRightStart -= 600 * kGapForGroup3;
+ _itemInfo.infoRightStop -= 600 * kGapForGroup3;
+ break;
+ case kPegasusBiochip:
+ _itemInfo.infoRightStart -= 600 * kGapForGroup4;
+ _itemInfo.infoRightStop -= 600 * kGapForGroup4;
+ break;
+ }
+ }
+
+ delete info;
+ } else {
+ memset(&_itemInfo, 0, sizeof(_itemInfo));
+ }
+
+ Common::SeekableReadStream *middleAreaInfo = vm->_resFork->getResource(kMiddleAreaInfoResType, kItemBaseResID + id);
+ if (middleAreaInfo) {
+ _sharedAreaInfo = readItemState(middleAreaInfo);
+ delete middleAreaInfo;
+ } else {
+ // Only kArgonPickup does not have this
+ memset(&_sharedAreaInfo, 0, sizeof(_sharedAreaInfo));
+ }
+
+ Common::SeekableReadStream *extraInfo = vm->_resFork->getResource(kItemExtraInfoResType, kItemBaseResID + id);
+ if (!extraInfo)
+ error("Extra info not found for item %d", id);
+
+ _itemExtras.numEntries = extraInfo->readUint16BE();
+ _itemExtras.entries = new ItemExtraEntry[_itemExtras.numEntries];
+ for (uint16 i = 0; i < _itemExtras.numEntries; i++) {
+ _itemExtras.entries[i].extraID = extraInfo->readUint32BE();
+ _itemExtras.entries[i].extraArea = extraInfo->readUint16BE();
+ _itemExtras.entries[i].extraStart = extraInfo->readUint32BE();
+ _itemExtras.entries[i].extraStop = extraInfo->readUint32BE();
+ }
+
+ delete extraInfo;
+
+ g_allItems.push_back(this);
+}
+
+Item::~Item() {
+ delete[] _sharedAreaInfo.entries;
+ delete[] _itemExtras.entries;
+}
+
+void Item::writeToStream(Common::WriteStream *stream) {
+ stream->writeUint16BE(_itemNeighborhood);
+ stream->writeUint16BE(_itemRoom);
+ stream->writeByte(_itemDirection);
+ stream->writeUint16BE(_itemOwnerID);
+ stream->writeUint16BE(_itemState);
+}
+
+void Item::readFromStream(Common::ReadStream *stream) {
+ _itemNeighborhood = stream->readUint16BE();
+ _itemRoom = stream->readUint16BE();
+ _itemDirection = stream->readByte();
+ _itemOwnerID = stream->readUint16BE();
+ _itemState = stream->readUint16BE();
+}
+
+ActorID Item::getItemOwner() const {
+ return _itemOwnerID;
+}
+
+void Item::setItemOwner(const ActorID owner) {
+ _itemOwnerID = owner;
+
+ if (owner == kNoActorID) {
+ if (isSelected())
+ deselect();
+ removedFromInventory();
+ } else {
+ addedToInventory();
+ }
+}
+
+WeightType Item::getItemWeight() {
+ return _itemWeight;
+}
+
+ItemState Item::getItemState() const {
+ return _itemState;
+}
+
+void Item::setItemState(const ItemState state) {
+ if (state != _itemState) {
+ _itemState = state;
+
+ if (getItemType() == kInventoryItemType && ((PegasusEngine *)g_engine)->getCurrentInventoryItem() == (InventoryItem *)this)
+ select();
+ else if (getItemType() == kBiochipItemType && ((PegasusEngine *)g_engine)->getCurrentBiochip() == (BiochipItem *)this)
+ select();
+ }
+}
+
+void Item::getItemRoom(NeighborhoodID &neighborhood, RoomID &room, DirectionConstant &direction) const {
+ neighborhood = _itemNeighborhood;
+ room = _itemRoom;
+ direction = _itemDirection;
+}
+
+void Item::setItemRoom(const NeighborhoodID neighborhood, const RoomID room, const DirectionConstant direction) {
+ _itemNeighborhood = neighborhood;
+ _itemRoom = room;
+ _itemDirection = direction;
+
+ if (neighborhood == kNoNeighborhoodID)
+ pickedUp();
+ else
+ dropped();
+}
+
+NeighborhoodID Item::getItemNeighborhood() const {
+ return _itemNeighborhood;
+}
+
+TimeValue Item::getSharedAreaTime() const {
+ if (!_sharedAreaInfo.entries)
+ return 0xffffffff;
+
+ TimeValue time;
+ ItemState state;
+
+ findItemStateEntryByState(_sharedAreaInfo, _itemState, time);
+ if (time == 0xffffffff)
+ getItemStateEntry(_sharedAreaInfo, 0, state, time);
+
+ return time;
+}
+
+// Must affect images in shared area.
+void Item::select() {
+ _isSelected = true;
+
+ if (g_AIArea) {
+ if (getItemType() == kInventoryItemType)
+ g_AIArea->setAIAreaToTime(kInventorySignature, kMiddleAreaSignature, getSharedAreaTime());
+ else
+ g_AIArea->setAIAreaToTime(kBiochipSignature, kMiddleAreaSignature, getSharedAreaTime());
+ }
+}
+
+void Item::deselect() {
+ _isActive = false;
+ _isSelected = false;
+
+ if (g_AIArea) {
+ if (getItemType() == kInventoryItemType)
+ g_AIArea->setAIAreaToTime(kInventorySignature, kMiddleAreaSignature, 0xffffffff);
+ else
+ g_AIArea->setAIAreaToTime(kBiochipSignature, kMiddleAreaSignature, 0xffffffff);
+ }
+}
+
+void Item::getItemStateEntry(ItemStateInfo info, uint32 index, ItemState &state, TimeValue &time) {
+ if (index < info.numEntries) {
+ state = info.entries[index].itemState;
+ time = info.entries[index].itemTime;
+ } else {
+ state = kNoItemState;
+ time = 0xffffffff;
+ }
+}
+
+void Item::findItemStateEntryByState(ItemStateInfo info, ItemState state, TimeValue &time) {
+ for (uint16 i = 0; i < info.numEntries; i++) {
+ if (info.entries[i].itemState == state) {
+ time = info.entries[i].itemTime;
+ return;
+ }
+ }
+
+ time = 0xffffffff;
+}
+
+ItemStateInfo Item::readItemState(Common::SeekableReadStream *stream) {
+ ItemStateInfo info;
+
+ info.numEntries = stream->readUint16BE();
+ info.entries = new ItemStateEntry[info.numEntries];
+ for (uint16 i = 0; i < info.numEntries; i++) {
+ info.entries[i].itemState = stream->readSint16BE();
+ info.entries[i].itemTime = stream->readUint32BE();
+ }
+
+ return info;
+}
+
+Sprite *Item::getDragSprite(const DisplayElementID id) const {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+ Sprite *result = new Sprite(id);
+ SpriteFrame *frame = new SpriteFrame();
+
+ frame->initFromPICTResource(vm->_resFork, _itemInfo.dragSpriteNormalID, true);
+ result->addFrame(frame, 0, 0);
+
+ if (_itemInfo.dragSpriteNormalID != _itemInfo.dragSpriteUsedID) {
+ frame = new SpriteFrame();
+ frame->initFromPICTResource(vm->_resFork, _itemInfo.dragSpriteUsedID, true);
+ }
+
+ result->addFrame(frame, 0, 0);
+ result->setCurrentFrameIndex(0);
+ return result;
+}
+
+TimeValue Item::getInfoLeftTime() const {
+ return _itemInfo.infoLeftTime;
+}
+
+void Item::getInfoRightTimes(TimeValue &start, TimeValue &stop) const {
+ start = _itemInfo.infoRightStart;
+ stop = _itemInfo.infoRightStop;
+}
+
+void Item::findItemExtra(const uint32 extraID, ItemExtraEntry &entry) {
+ for (uint32 i = 0; i < _itemExtras.numEntries; i++) {
+ if (_itemExtras.entries[i].extraID == extraID) {
+ entry = _itemExtras.entries[i];
+ return;
+ }
+ }
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/items/item.h b/engines/pegasus/items/item.h
new file mode 100644
index 0000000000..a1451b2a58
--- /dev/null
+++ b/engines/pegasus/items/item.h
@@ -0,0 +1,363 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_ITEMS_ITEM_H
+#define PEGASUS_ITEMS_ITEM_H
+
+#include "common/endian.h"
+
+#include "pegasus/types.h"
+#include "pegasus/util.h"
+
+namespace Common {
+ class Error;
+ class ReadStream;
+ class WriteStream;
+ class SeekableReadStream;
+}
+
+namespace Pegasus {
+
+// JMPItemInfo contains resource data used by all Items.
+
+struct JMPItemInfo {
+ TimeValue infoLeftTime;
+ TimeValue infoRightStart;
+ TimeValue infoRightStop;
+ uint32 dragSpriteNormalID;
+ uint32 dragSpriteUsedID;
+};
+
+// ItemStateEntry contains a single state/TimeValue pair. The TimeValue is
+// the time value to set the shared area movie that corresponds with the given
+// state of an inventory item.
+
+struct ItemStateEntry {
+ ItemState itemState;
+ TimeValue itemTime;
+};
+
+struct ItemStateInfo {
+ uint16 numEntries; // For easy ResEdit access
+ ItemStateEntry *entries;
+};
+
+// ItemExtraEntry
+
+static const short kLeftAreaExtra = 0;
+static const short kMiddleAreaExtra = 1;
+static const short kRightAreaExtra = 2;
+
+struct ItemExtraEntry {
+ uint32 extraID;
+ uint16 extraArea;
+ TimeValue extraStart;
+ TimeValue extraStop;
+};
+
+struct ItemExtraInfo {
+ uint16 numEntries; // For easy ResEdit access
+ ItemExtraEntry *entries;
+};
+
+// Inventory info resource type and ID:
+// Individual inventory items are stored in these resource types.
+// Resource ID is item ID + kItemBaseResID.
+
+static const uint32 kItemInfoResType = MKTAG('I', 't', 'e', 'm'); // JMPItemInfoHandle
+static const uint32 kLeftAreaInfoResType = MKTAG('L', 'e', 'f', 't'); // ItemStateInfoHandle
+static const uint32 kMiddleAreaInfoResType = MKTAG('M', 'i', 'd', 'l'); // ItemStateInfoHandle
+static const uint32 kRightAreaInfoResType = MKTAG('R', 'g', 'h', 't'); // ItemStateInfoHandle
+static const uint32 kItemExtraInfoResType = MKTAG('I', 'X', 't', 'r'); // ItemExtraInfoHandle
+
+static const uint16 kItemBaseResID = 128;
+
+// Item IDs.
+
+static const ItemID kAirMask = 7;
+static const ItemID kAntidote = 8;
+static const ItemID kArgonCanister = 9;
+static const ItemID kCardBomb = 10;
+static const ItemID kCrowbar = 11;
+static const ItemID kGasCanister = 12;
+static const ItemID kHistoricalLog = 13;
+static const ItemID kJourneymanKey = 14;
+static const ItemID kKeyCard = 15;
+static const ItemID kMachineGun = 16;
+static const ItemID kMarsCard = 17;
+static const ItemID kNitrogenCanister = 18;
+static const ItemID kOrangeJuiceGlassFull = 19;
+static const ItemID kOrangeJuiceGlassEmpty = 20;
+static const ItemID kPoisonDart = 21;
+static const ItemID kSinclairKey = 22;
+static const ItemID kStunGun = 23;
+static const ItemID kArgonPickup = 24;
+
+// Biochips.
+
+static const ItemID kAIBiochip = 0;
+static const ItemID kInterfaceBiochip = 1;
+static const ItemID kMapBiochip = 2;
+static const ItemID kOpticalBiochip = 3;
+static const ItemID kPegasusBiochip = 4;
+static const ItemID kRetinalScanBiochip = 5;
+static const ItemID kShieldBiochip = 6;
+
+static const ItemID kNumItems = 25;
+
+// Item States.
+
+static const ItemState kAI000 = 0;
+static const ItemState kAI005 = 1;
+static const ItemState kAI006 = 2;
+static const ItemState kAI010 = 3;
+static const ItemState kAI015 = 4;
+static const ItemState kAI016 = 5;
+static const ItemState kAI020 = 6;
+static const ItemState kAI024 = 7;
+static const ItemState kAI100 = 8;
+static const ItemState kAI101 = 9;
+static const ItemState kAI105 = 10;
+static const ItemState kAI106 = 11;
+static const ItemState kAI110 = 12;
+static const ItemState kAI111 = 13;
+static const ItemState kAI115 = 14;
+static const ItemState kAI116 = 15;
+static const ItemState kAI120 = 16;
+static const ItemState kAI121 = 17;
+static const ItemState kAI124 = 18;
+static const ItemState kAI125 = 19;
+static const ItemState kAI126 = 20;
+static const ItemState kAI200 = 21;
+static const ItemState kAI201 = 22;
+static const ItemState kAI202 = 23;
+static const ItemState kAI205 = 24;
+static const ItemState kAI206 = 25;
+static const ItemState kAI210 = 26;
+static const ItemState kAI211 = 27;
+static const ItemState kAI212 = 28;
+static const ItemState kAI215 = 29;
+static const ItemState kAI216 = 30;
+static const ItemState kAI220 = 31;
+static const ItemState kAI221 = 32;
+static const ItemState kAI222 = 33;
+static const ItemState kAI224 = 34;
+static const ItemState kAI225 = 35;
+static const ItemState kAI226 = 36;
+static const ItemState kAI300 = 37;
+static const ItemState kAI301 = 38;
+static const ItemState kAI302 = 39;
+static const ItemState kAI303 = 40;
+static const ItemState kAI305 = 41;
+static const ItemState kAI306 = 42;
+static const ItemState kAI310 = 43;
+static const ItemState kAI311 = 44;
+static const ItemState kAI312 = 45;
+static const ItemState kAI313 = 46;
+static const ItemState kAI315 = 47;
+static const ItemState kAI316 = 48;
+static const ItemState kAI320 = 49;
+static const ItemState kAI321 = 50;
+static const ItemState kAI322 = 51;
+static const ItemState kAI323 = 52;
+static const ItemState kAI324 = 53;
+static const ItemState kAI325 = 54;
+static const ItemState kAI326 = 55;
+static const ItemState kNormalItem = 56;
+static const ItemState kMapUnavailable = 57;
+static const ItemState kMapEngaged = 58;
+static const ItemState kOptical000 = 59;
+static const ItemState kOptical001 = 60;
+static const ItemState kOptical002 = 61;
+static const ItemState kOptical010 = 62;
+static const ItemState kOptical011 = 63;
+static const ItemState kOptical012 = 64;
+static const ItemState kOptical020 = 65;
+static const ItemState kOptical021 = 66;
+static const ItemState kOptical100 = 67;
+static const ItemState kOptical101 = 68;
+static const ItemState kOptical102 = 69;
+static const ItemState kOptical110 = 70;
+static const ItemState kOptical111 = 71;
+static const ItemState kOptical112 = 72;
+static const ItemState kOptical120 = 73;
+static const ItemState kOptical121 = 74;
+static const ItemState kOptical200 = 75;
+static const ItemState kOptical201 = 76;
+static const ItemState kOptical210 = 77;
+static const ItemState kOptical211 = 78;
+static const ItemState kPegasusTSA00 = 79;
+static const ItemState kPegasusTSA10 = 80;
+static const ItemState kPegasusPrehistoric00 = 81;
+static const ItemState kPegasusPrehistoric01 = 82;
+static const ItemState kPegasusPrehistoric10 = 83;
+static const ItemState kPegasusPrehistoric11 = 84;
+static const ItemState kPegasusMars00 = 85;
+static const ItemState kPegasusMars01 = 86;
+static const ItemState kPegasusMars10 = 87;
+static const ItemState kPegasusMars11 = 88;
+static const ItemState kPegasusNorad00 = 89;
+static const ItemState kPegasusNorad01 = 90;
+static const ItemState kPegasusNorad10 = 91;
+static const ItemState kPegasusNorad11 = 92;
+static const ItemState kPegasusWSC00 = 93;
+static const ItemState kPegasusWSC01 = 94;
+static const ItemState kPegasusWSC10 = 95;
+static const ItemState kPegasusWSC11 = 96;
+static const ItemState kPegasusCaldoria = 97;
+static const ItemState kRetinalSimulating = 98;
+static const ItemState kShieldNormal = 99;
+static const ItemState kShieldRadiation = 100;
+static const ItemState kShieldPlasma = 101;
+static const ItemState kShieldCardBomb = 102;
+static const ItemState kShieldDraining = 103;
+static const ItemState kAirMaskEmptyOff = 104;
+static const ItemState kAirMaskEmptyFilter = 105;
+static const ItemState kAirMaskLowOff = 106;
+static const ItemState kAirMaskLowFilter = 107;
+static const ItemState kAirMaskLowOn = 108;
+static const ItemState kAirMaskFullOff = 109;
+static const ItemState kAirMaskFullFilter = 110;
+static const ItemState kAirMaskFullOn = 111;
+static const ItemState kArgonEmpty = 112;
+static const ItemState kArgonFull = 113;
+static const ItemState kFlashlightOff = 114;
+static const ItemState kFlashlightOn = 115;
+static const ItemState kNitrogenEmpty = 116;
+static const ItemState kNitrogenFull = 117;
+static const ItemState kFullGlass = 118;
+
+// Extra IDs.
+
+static const uint32 kRetinalScanSearching = 0;
+static const uint32 kRetinalScanActivated = 1;
+static const uint32 kShieldIntro = 2;
+static const uint32 kRemoveAirMask = 3;
+static const uint32 kRemoveArgon = 4;
+static const uint32 kRemoveCrowbar = 5;
+static const uint32 kGasCanLoop = 6;
+static const uint32 kRemoveJourneymanKey = 7;
+static const uint32 kRemoveMarsCard = 8;
+static const uint32 kRemoveNitrogen = 9;
+static const uint32 kRemoveGlass = 10;
+static const uint32 kRemoveDart = 11;
+static const uint32 kRemoveSinclairKey = 12;
+
+enum ItemType {
+ kInventoryItemType,
+ kBiochipItemType
+};
+
+class Sprite;
+
+/*
+
+ Item is an object which can be picked up and carried around.
+ Items have
+ a location
+ an ID.
+ weight
+ an owner (kNoActorID if no one is carrying the Item)
+
+*/
+
+class Item : public IDObject {
+public:
+ Item(const ItemID id, const NeighborhoodID neighborhood, const RoomID room, const DirectionConstant direction);
+ virtual ~Item();
+
+ // WriteToStream writes everything EXCEPT the item's ID.
+ // It is assumed that the calling function will write and read the ID.
+ virtual void writeToStream(Common::WriteStream *stream);
+ virtual void readFromStream(Common::ReadStream *stream);
+
+ virtual ActorID getItemOwner() const;
+ virtual void setItemOwner(const ActorID owner);
+
+ void getItemRoom(NeighborhoodID &neighborhood, RoomID &room, DirectionConstant &direction) const;
+ void setItemRoom(const NeighborhoodID neighborhood, const RoomID room, const DirectionConstant direction);
+ NeighborhoodID getItemNeighborhood() const;
+
+ virtual WeightType getItemWeight();
+
+ virtual void setItemState(const ItemState state);
+ virtual ItemState getItemState() const;
+
+ virtual ItemType getItemType() = 0;
+
+ TimeValue getInfoLeftTime() const;
+ void getInfoRightTimes(TimeValue &, TimeValue &) const;
+ TimeValue getSharedAreaTime() const;
+
+ Sprite *getDragSprite(const DisplayElementID) const;
+
+ /*
+ select -- called when this item becomes current. Also called when the inventory
+ panel holding this item is raised and this is the current item.
+ deselect -- called when this item is no longer current.
+ activate -- called on the current item when the panel is closed.
+ */
+ // In an override of these three member functions, you must call the inherited
+ // member functions.
+ virtual void select();
+ virtual void deselect();
+ virtual bool isSelected() { return _isSelected; }
+
+ virtual void activate() { _isActive = true; }
+ virtual bool isActive() { return _isActive; }
+ virtual void pickedUp() {}
+ virtual void addedToInventory() {}
+ virtual void removedFromInventory() {}
+ virtual void dropped() {}
+
+ // Called when the shared area is taken by another item, but this item is still
+ // selected.
+ virtual void giveUpSharedArea() {}
+ virtual void takeSharedArea() {}
+
+ void findItemExtra(const uint32 extraID, ItemExtraEntry &entry);
+
+protected:
+ NeighborhoodID _itemNeighborhood;
+ RoomID _itemRoom;
+ DirectionConstant _itemDirection;
+ ActorID _itemOwnerID;
+ WeightType _itemWeight;
+ ItemState _itemState;
+
+ JMPItemInfo _itemInfo;
+ ItemStateInfo _sharedAreaInfo;
+ ItemExtraInfo _itemExtras;
+ bool _isActive;
+ bool _isSelected;
+
+ static void getItemStateEntry(ItemStateInfo, uint32, ItemState &, TimeValue &);
+ static void findItemStateEntryByState(ItemStateInfo, ItemState, TimeValue &);
+ static ItemStateInfo readItemState(Common::SeekableReadStream *stream);
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/items/itemdragger.cpp b/engines/pegasus/items/itemdragger.cpp
new file mode 100644
index 0000000000..97fc5a97ac
--- /dev/null
+++ b/engines/pegasus/items/itemdragger.cpp
@@ -0,0 +1,193 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/elements.h"
+#include "pegasus/hotspot.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/items/itemdragger.h"
+
+namespace Pegasus {
+
+SpriteDragger::SpriteDragger() {
+ _draggingSprite = 0;
+ _limitRect = Common::Rect(-30000, -30000, 30000, 30000);
+ _slopRect = Common::Rect(-30000, -30000, 30000, 30000);
+ _dragOffset.x = 0;
+ _dragOffset.y = 0;
+ _lastHotspot = 0;
+}
+
+void SpriteDragger::setDragSprite(Sprite *newSprite) {
+ if (!isTracking())
+ _draggingSprite = newSprite;
+}
+
+void SpriteDragger::setDragConstraints(const Common::Rect &limitRect, const Common::Rect &slopRect) {
+ if (!isTracking()) {
+ _rawLimitRect = limitRect;
+ _slopRect = slopRect;
+ }
+}
+
+void SpriteDragger::getDragConstraints(Common::Rect &limitRect, Common::Rect &slopRect) const {
+ limitRect = _rawLimitRect;
+ slopRect = _slopRect;
+}
+
+void SpriteDragger::startTracking(const Input &input) {
+ if (_draggingSprite) {
+ Tracker::startTracking(input);
+
+ if (isTracking()) {
+ input.getInputLocation(_startPoint);
+ _lastRawPoint = _startRawPoint = _startPoint;
+
+ Common::Rect r;
+ _draggingSprite->getBounds(r);
+ _dragOffset.x = _startPoint.x - r.left;
+ _dragOffset.y = _startPoint.y - r.top;
+
+ _limitRect = _rawLimitRect;
+ _limitRect.left += _dragOffset.x;
+ _limitRect.top += _dragOffset.y;
+ _limitRect.right -= r.width() - _dragOffset.x;
+ _limitRect.bottom -= r.height() - _dragOffset.y;
+ pinPointInRect(_limitRect, _startPoint);
+
+ _lastPoint = _startPoint;
+ if (_startPoint != _startRawPoint) {
+ Common::Point pt = _startPoint - _dragOffset;
+ _draggingSprite->moveElementTo(pt.x, pt.y);
+ }
+
+ _lastHotspot = g_allHotspots.findHotspot(_lastRawPoint);
+ if (_lastHotspot)
+ enterHotspot(_lastHotspot);
+ }
+ }
+}
+
+void SpriteDragger::continueTracking(const Input &input) {
+ if (_draggingSprite) {
+ Common::Point rawPoint;
+ input.getInputLocation(rawPoint);
+
+ if (!_slopRect.contains(rawPoint))
+ rawPoint = _startRawPoint;
+
+ if (rawPoint != _lastRawPoint) {
+ Common::Point newPoint = rawPoint;
+ pinPointInRect(_limitRect, newPoint);
+ newPoint -= _dragOffset;
+
+ if (newPoint != _lastPoint) {
+ _draggingSprite->moveElementTo(newPoint.x, newPoint.y);
+ _lastPoint = newPoint;
+ }
+
+ Hotspot *newHotspot = g_allHotspots.findHotspot(rawPoint);
+ if (newHotspot != _lastHotspot) {
+ if (_lastHotspot)
+ exitHotspot(_lastHotspot);
+ if (newHotspot)
+ enterHotspot(newHotspot);
+ _lastHotspot = newHotspot;
+ }
+
+ _lastRawPoint = rawPoint;
+ }
+ }
+}
+
+void SpriteDragger::pinPointInRect(const Common::Rect &r, Common::Point &pt) {
+ pt.x = CLIP<int>(pt.x, r.left, r.right - 1);
+ pt.y = CLIP<int>(pt.y, r.top, r.bottom - 1);
+}
+
+ItemDragger::ItemDragger(PegasusEngine *owner) : _inventoryDropSpot(kInventoryDropSpotID), _biochipDropSpot(kBiochipDropSpotID),
+ _inventoryHighlight(kInventoryDropHighlightID), _biochipHighlight(kBiochipDropHighlightID) {
+ _owner = owner;
+
+ Common::Rect r(kInventoryDropLeft, kInventoryDropTop, kInventoryDropRight, kInventoryDropBottom);
+ _inventoryDropSpot.setArea(r);
+ _inventoryDropSpot.setHotspotFlags(kDropItemSpotFlag);
+ g_allHotspots.push_back(&_inventoryDropSpot);
+
+ r = Common::Rect(kBiochipDropLeft, kBiochipDropTop, kBiochipDropRight, kBiochipDropBottom);
+ _biochipDropSpot.setArea(r);
+ _biochipDropSpot.setHotspotFlags(kDropBiochipSpotFlag);
+ g_allHotspots.push_back(&_biochipDropSpot);
+}
+
+void ItemDragger::startTracking(const Input &input) {
+ _inventoryHighlight.setDisplayOrder(kInventoryHiliteOrder);
+ _inventoryHighlight.startDisplaying();
+
+ _biochipHighlight.setDisplayOrder(kBiochipHiliteOrder);
+ _biochipHighlight.startDisplaying();
+
+ SpriteDragger::startTracking(input);
+}
+
+void ItemDragger::stopTracking(const Input &input) {
+ SpriteDragger::stopTracking(input);
+ _inventoryHighlight.hide();
+ _biochipHighlight.hide();
+ _inventoryHighlight.stopDisplaying();
+ _biochipHighlight.stopDisplaying();
+ _owner->dragTerminated(input);
+}
+
+bool ItemDragger::stopTrackingInput(const Input &input) {
+ return !JMPPPInput::isDraggingInput(input);
+}
+
+void ItemDragger::enterHotspot(Hotspot *spot) {
+ if (spot->getObjectID() == kInventoryDropSpotID)
+ _inventoryHighlight.show();
+ else if (spot->getObjectID() == kBiochipDropSpotID)
+ _biochipHighlight.show();
+ else if ((spot->getHotspotFlags() & kDropItemSpotFlag) != 0)
+ _draggingSprite->setCurrentFrameIndex(1);
+}
+
+void ItemDragger::exitHotspot(Hotspot *spot) {
+ if (spot->getObjectID() == kInventoryDropSpotID)
+ _inventoryHighlight.hide();
+ else if (spot->getObjectID() == kBiochipDropSpotID)
+ _biochipHighlight.hide();
+ else if ((spot->getHotspotFlags() & kDropItemSpotFlag) != 0)
+ _draggingSprite->setCurrentFrameIndex(0);
+}
+
+void ItemDragger::setHighlightBounds() {
+ uint32 color = g_system->getScreenFormat().RGBToColor(0x48, 0x80, 0xD8);
+ _inventoryHighlight.setBounds(Common::Rect(76, 334, 172, 430));
+ _inventoryHighlight.setHighlightColor(color);
+ _biochipHighlight.setBounds(Common::Rect(364, 334, 460, 430));
+ _biochipHighlight.setHighlightColor(color);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/items/itemdragger.h b/engines/pegasus/items/itemdragger.h
new file mode 100644
index 0000000000..fce953d695
--- /dev/null
+++ b/engines/pegasus/items/itemdragger.h
@@ -0,0 +1,96 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_ITEMS_ITEMDRAGGER_H
+#define PEGASUS_ITEMS_ITEMDRAGGER_H
+
+#include "pegasus/elements.h"
+#include "pegasus/input.h"
+
+namespace Pegasus {
+
+// TODO: Merge SpriteDragger and ItemDragger
+
+class Hotspot;
+class Sprite;
+
+class SpriteDragger : public Tracker {
+public:
+ SpriteDragger();
+ virtual ~SpriteDragger() {}
+
+ void setDragSprite(Sprite *);
+ Sprite *getDragSprite() { return _draggingSprite; }
+
+ void setDragConstraints(const Common::Rect &, const Common::Rect &);
+ void getDragConstraints(Common::Rect &, Common::Rect &) const;
+
+ void startTracking(const Input &);
+ void continueTracking(const Input&);
+
+ Hotspot *getLastHotspot() const { return _lastHotspot; }
+
+protected:
+ virtual void enterHotspot(Hotspot *) {}
+ virtual void exitHotspot(Hotspot *) {}
+
+ Sprite *_draggingSprite;
+ Common::Point _startPoint, _lastPoint, _dragOffset;
+ Common::Point _startRawPoint, _lastRawPoint;
+ Common::Rect _rawLimitRect;
+ Common::Rect _limitRect;
+ Common::Rect _slopRect;
+ Hotspot *_lastHotspot;
+
+ // This is a replica of QuickDraw's PinPointInRect function
+ void pinPointInRect(const Common::Rect &, Common::Point &);
+};
+
+class PegasusEngine;
+
+class ItemDragger : public SpriteDragger {
+public:
+ ItemDragger(PegasusEngine *);
+ virtual ~ItemDragger() {}
+
+ void setHighlightBounds();
+ void startTracking(const Input &);
+ void stopTracking(const Input &);
+ bool stopTrackingInput(const Input &);
+
+protected:
+ virtual void enterHotspot(Hotspot *);
+ virtual void exitHotspot(Hotspot *);
+
+ PegasusEngine *_owner;
+ DropHighlight _inventoryHighlight;
+ Hotspot _inventoryDropSpot;
+ DropHighlight _biochipHighlight;
+ Hotspot _biochipDropSpot;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/items/itemlist.cpp b/engines/pegasus/items/itemlist.cpp
new file mode 100644
index 0000000000..ff8cae546b
--- /dev/null
+++ b/engines/pegasus/items/itemlist.cpp
@@ -0,0 +1,67 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/error.h"
+#include "common/stream.h"
+
+#include "pegasus/pegasus.h"
+#include "pegasus/items/item.h"
+#include "pegasus/items/itemlist.h"
+
+namespace Pegasus {
+
+ItemList::ItemList() {
+}
+
+ItemList::~ItemList() {
+}
+
+void ItemList::writeToStream(Common::WriteStream *stream) {
+ stream->writeUint32BE(size());
+
+ for (ItemIterator it = begin(); it != end(); it++) {
+ stream->writeUint16BE((*it)->getObjectID());
+ (*it)->writeToStream(stream);
+ }
+}
+
+void ItemList::readFromStream(Common::ReadStream *stream) {
+ uint32 itemCount = stream->readUint32BE();
+
+ for (uint32 i = 0; i < itemCount; i++) {
+ ItemID itemID = stream->readUint16BE();
+ g_allItems.findItemByID(itemID)->readFromStream(stream);
+ }
+}
+
+Item *ItemList::findItemByID(const ItemID id) {
+ for (ItemIterator it = begin(); it != end(); it++)
+ if ((*it)->getObjectID() == id)
+ return *it;
+
+ return 0;
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/items/itemlist.h b/engines/pegasus/items/itemlist.h
new file mode 100644
index 0000000000..9b59206ab3
--- /dev/null
+++ b/engines/pegasus/items/itemlist.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.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_ITEMS_ITEMLIST_H
+#define PEGASUS_ITEMS_ITEMLIST_H
+
+#include "common/list.h"
+
+#include "pegasus/types.h"
+
+namespace Common {
+ class ReadStream;
+ class WriteStream;
+}
+
+namespace Pegasus {
+
+class Item;
+
+class ItemList : public Common::List<Item *> {
+public:
+ ItemList();
+ virtual ~ItemList();
+
+ virtual void writeToStream(Common::WriteStream *stream);
+ virtual void readFromStream(Common::ReadStream *stream);
+
+ Item *findItemByID(const ItemID id);
+};
+
+typedef ItemList::iterator ItemIterator;
+
+#define g_allItems (((PegasusEngine *)g_engine)->getAllItems())
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/menu.cpp b/engines/pegasus/menu.cpp
new file mode 100644
index 0000000000..deaa460188
--- /dev/null
+++ b/engines/pegasus/menu.cpp
@@ -0,0 +1,1219 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/gamestate.h"
+#include "pegasus/menu.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/scoring.h"
+
+namespace Pegasus {
+
+GameMenu::GameMenu(const uint32 id) : IDObject(id), InputHandler((InputHandler *)((PegasusEngine *)g_engine)) {
+ _previousHandler = 0;
+ _lastCommand = kMenuCmdNoCommand;
+}
+
+void GameMenu::becomeCurrentHandler() {
+ _previousHandler = InputHandler::setInputHandler(this);
+}
+
+void GameMenu::restorePreviousHandler() {
+ InputHandler::setInputHandler(_previousHandler);
+}
+
+void GameMenu::drawScore(GameScoreType score, GameScoreType total, const Common::Rect &scoreBounds, Surface *numbers) {
+ CoordType x = scoreBounds.right;
+ drawNumber(total, x, scoreBounds.top, numbers);
+
+ x -= 12;
+ Common::Rect r1(120, 0, 132, 12); // The slash.
+ Common::Rect r2 = r1;
+ r2.moveTo(x, scoreBounds.top);
+ numbers->copyToCurrentPort(r1, r2);
+ drawNumber(score, x, scoreBounds.top, numbers);
+}
+
+void GameMenu::drawNumber(GameScoreType number, CoordType &x, CoordType y, Surface *numbers) {
+ Common::Rect r1(0, 0, 12, 12); // Width, height of one digit
+ Common::Rect r2 = r1;
+ r2.moveTo(x - 12, y);
+
+ do {
+ uint16 digit = number % 10;
+ number /= 10;
+ r1.moveTo(digit * 12, 0);
+ numbers->copyToCurrentPort(r1, r2);
+ r2.translate(-12, 0);
+ } while (number != 0);
+
+ x = r2.right;
+}
+
+enum {
+ kMainMenuStartDemo = 0,
+ kMainMenuCreditsDemo,
+ kMainMenuQuitDemo,
+ kFirstSelectionDemo = kMainMenuStartDemo,
+ kLastSelectionDemo = kMainMenuQuitDemo,
+
+ kMainMenuOverview = 0,
+ kMainMenuStart,
+ kMainMenuRestore,
+ kMainMenuDifficulty,
+ kMainMenuCredits,
+ kMainMenuQuit,
+ kFirstSelection = kMainMenuOverview,
+ kLastSelection = kMainMenuQuit
+};
+
+static const CoordType kStartLeftDemo = 44;
+static const CoordType kStartTopDemo = 336;
+
+static const CoordType kStartSelectLeftDemo = 40;
+static const CoordType kStartSelectTopDemo = 331;
+
+static const CoordType kCreditsLeftDemo = 44;
+static const CoordType kCreditsTopDemo = 372;
+
+static const CoordType kCreditsSelectLeftDemo = 40;
+static const CoordType kCreditsSelectTopDemo = 367;
+
+static const CoordType kMainMenuQuitLeftDemo = 32;
+static const CoordType kMainMenuQuitTopDemo = 412;
+
+static const CoordType kMainMenuQuitSelectLeftDemo = 28;
+static const CoordType kMainMenuQuitSelectTopDemo = 408;
+
+static const CoordType kOverviewLeft = 200;
+static const CoordType kOverviewTop = 208;
+
+static const CoordType kOverviewSelectLeft = 152;
+static const CoordType kOverviewSelectTop = 204;
+
+static const CoordType kStartLeft = 212;
+static const CoordType kStartTop = 256;
+
+static const CoordType kStartSelectLeft = 152;
+static const CoordType kStartSelectTop = 252;
+
+static const CoordType kRestoreLeft = 212;
+static const CoordType kRestoreTop = 296;
+
+static const CoordType kRestoreSelectLeft = 152;
+static const CoordType kRestoreSelectTop = 292;
+
+static const CoordType kDifficultyLeft = 320;
+static const CoordType kDifficultyTop = 340;
+
+static const CoordType kDifficultySelectLeft = 152;
+static const CoordType kDifficultySelectTop = 336;
+
+static const CoordType kCreditsLeft = 212;
+static const CoordType kCreditsTop = 388;
+
+static const CoordType kCreditsSelectLeft = 152;
+static const CoordType kCreditsSelectTop = 384;
+
+static const CoordType kMainMenuQuitLeft = 212;
+static const CoordType kMainMenuQuitTop = 428;
+
+static const CoordType kMainMenuQuitSelectLeft = 152;
+static const CoordType kMainMenuQuitSelectTop = 424;
+
+// Never set the current input handler to the MainMenu.
+MainMenu::MainMenu() : GameMenu(kMainMenuID), _menuBackground(0), _overviewButton(0),
+ _restoreButton(0), _adventureButton(0), _walkthroughButton(0), _startButton(0),
+ _creditsButton(0), _quitButton(0), _largeSelect(0), _smallSelect(0) {
+
+ bool isDemo = ((PegasusEngine *)g_engine)->isDemo();
+
+ if (isDemo)
+ _menuBackground.initFromPICTFile("Images/Demo/DemoMenu.pict");
+ else
+ _menuBackground.initFromPICTFile("Images/Main Menu/MainMenu.mac");
+ _menuBackground.setDisplayOrder(0);
+ _menuBackground.startDisplaying();
+ _menuBackground.show();
+
+ if (!isDemo) {
+ _overviewButton.initFromPICTFile("Images/Main Menu/pbOvervi.pict");
+ _overviewButton.setDisplayOrder(1);
+ _overviewButton.moveElementTo(kOverviewLeft, kOverviewTop);
+ _overviewButton.startDisplaying();
+
+ _restoreButton.initFromPICTFile("Images/Main Menu/pbRestor.pict");
+ _restoreButton.setDisplayOrder(1);
+ _restoreButton.moveElementTo(kRestoreLeft, kRestoreTop);
+ _restoreButton.startDisplaying();
+
+ _adventureButton.initFromPICTFile("Images/Main Menu/BtnAdv.pict");
+ _adventureButton.setDisplayOrder(1);
+ _adventureButton.moveElementTo(kDifficultyLeft, kDifficultyTop);
+ _adventureButton.startDisplaying();
+
+ _walkthroughButton.initFromPICTFile("Images/Main Menu/BtnWlk.pict");
+ _walkthroughButton.setDisplayOrder(1);
+ _walkthroughButton.moveElementTo(kDifficultyLeft, kDifficultyTop);
+ _walkthroughButton.startDisplaying();
+ }
+
+ if (isDemo)
+ _startButton.initFromPICTFile("Images/Demo/Start.pict");
+ else
+ _startButton.initFromPICTFile("Images/Main Menu/pbStart.pict");
+ _startButton.setDisplayOrder(1);
+ _startButton.moveElementTo(isDemo ? kStartLeftDemo : kStartLeft, isDemo ? kStartTopDemo : kStartTop);
+ _startButton.startDisplaying();
+
+ if (isDemo)
+ _creditsButton.initFromPICTFile("Images/Demo/Credits.pict");
+ else
+ _creditsButton.initFromPICTFile("Images/Main Menu/pbCredit.pict");
+ _creditsButton.setDisplayOrder(1);
+ _creditsButton.moveElementTo(isDemo ? kCreditsLeftDemo : kCreditsLeft, isDemo ? kCreditsTopDemo : kCreditsTop);
+ _creditsButton.startDisplaying();
+
+ if (isDemo)
+ _quitButton.initFromPICTFile("Images/Demo/Quit.pict");
+ else
+ _quitButton.initFromPICTFile("Images/Main Menu/pbQuit.pict");
+ _quitButton.setDisplayOrder(1);
+ _quitButton.moveElementTo(isDemo ? kMainMenuQuitLeftDemo : kMainMenuQuitLeft, isDemo ? kMainMenuQuitTopDemo : kMainMenuQuitTop);
+ _quitButton.startDisplaying();
+
+ if (isDemo)
+ _largeSelect.initFromPICTFile("Images/Demo/SelectL.pict", true);
+ else
+ _largeSelect.initFromPICTFile("Images/Main Menu/SelectL.pict", true);
+ _largeSelect.setDisplayOrder(1);
+ _largeSelect.startDisplaying();
+
+ if (isDemo)
+ _smallSelect.initFromPICTFile("Images/Demo/SelectS.pict", true);
+ else
+ _smallSelect.initFromPICTFile("Images/Main Menu/SelectS.pict", true);
+ _smallSelect.setDisplayOrder(1);
+ _smallSelect.startDisplaying();
+
+ _menuSelection = isDemo ? kFirstSelectionDemo : kFirstSelection;
+
+ _adventureMode = true;
+
+ _menuLoop.attachFader(&_menuFader);
+ _menuLoop.initFromAIFFFile("Sounds/Main Menu.aiff");
+
+ updateDisplay();
+}
+
+MainMenu::~MainMenu() {
+ if (_menuLoop.isPlaying())
+ stopMainMenuLoop();
+}
+
+void MainMenu::startMainMenuLoop() {
+ FaderMoveSpec spec;
+
+ _menuLoop.loopSound();
+ spec.makeTwoKnotFaderSpec(30, 0, 0, 30, 255);
+ _menuFader.startFaderSync(spec);
+}
+
+void MainMenu::stopMainMenuLoop() {
+ FaderMoveSpec spec;
+
+ spec.makeTwoKnotFaderSpec(30, 0, 255, 30, 0);
+ _menuFader.startFaderSync(spec);
+ _menuLoop.stopSound();
+}
+
+void MainMenu::handleInput(const Input &input, const Hotspot *cursorSpot) {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+ bool isDemo = vm->isDemo();
+
+ if (input.upButtonDown()) {
+ if (_menuSelection > (isDemo ? kFirstSelectionDemo : kFirstSelection)) {
+ _menuSelection--;
+ updateDisplay();
+ }
+ } else if (input.downButtonDown()) {
+ if (_menuSelection < (isDemo ? kLastSelectionDemo : kLastSelection)) {
+ _menuSelection++;
+ updateDisplay();
+ }
+ } else if (!isDemo && (input.leftButtonDown() || input.rightButtonDown())) {
+ if (_menuSelection == kMainMenuDifficulty) {
+ _adventureMode = !_adventureMode;
+ updateDisplay();
+ }
+ } else if (JMPPPInput::isMenuButtonPressInput(input)) {
+ if (isDemo) {
+ switch (_menuSelection) {
+ case kMainMenuCreditsDemo:
+ _creditsButton.show();
+ vm->delayShell(kMenuButtonHiliteTime, kMenuButtonHiliteScale);
+ _creditsButton.hide();
+ setLastCommand(kMenuCmdCredits);
+ break;
+ case kMainMenuStartDemo:
+ _startButton.show();
+ vm->delayShell(kMenuButtonHiliteTime, kMenuButtonHiliteScale);
+ _startButton.hide();
+ setLastCommand(kMenuCmdStartAdventure);
+ break;
+ case kMainMenuQuitDemo:
+ _quitButton.show();
+ vm->delayShell(kMenuButtonHiliteTime, kMenuButtonHiliteScale);
+ _quitButton.hide();
+ setLastCommand(kMenuCmdQuit);
+ break;
+ }
+ } else {
+ switch (_menuSelection) {
+ case kMainMenuOverview:
+ _overviewButton.show();
+ vm->delayShell(kMenuButtonHiliteTime, kMenuButtonHiliteScale);
+ _overviewButton.hide();
+ setLastCommand(kMenuCmdOverview);
+ break;
+ case kMainMenuRestore:
+ _restoreButton.show();
+ vm->delayShell(kMenuButtonHiliteTime, kMenuButtonHiliteScale);
+ _restoreButton.hide();
+ setLastCommand(kMenuCmdRestore);
+ break;
+ case kMainMenuCredits:
+ _creditsButton.show();
+ vm->delayShell(kMenuButtonHiliteTime, kMenuButtonHiliteScale);
+ _creditsButton.hide();
+ setLastCommand(kMenuCmdCredits);
+ break;
+ case kMainMenuStart:
+ _startButton.show();
+ vm->delayShell(kMenuButtonHiliteTime, kMenuButtonHiliteScale);
+ _startButton.hide();
+ if (_adventureMode)
+ setLastCommand(kMenuCmdStartAdventure);
+ else
+ setLastCommand(kMenuCmdStartWalkthrough);
+ break;
+ case kMainMenuDifficulty:
+ _adventureMode = !_adventureMode;
+ updateDisplay();
+ break;
+ case kMainMenuQuit:
+ _quitButton.show();
+ vm->delayShell(kMenuButtonHiliteTime, kMenuButtonHiliteScale);
+ _quitButton.hide();
+ setLastCommand(kMenuCmdQuit);
+ break;
+ }
+ }
+ }
+
+ InputHandler::handleInput(input, cursorSpot);
+}
+
+void MainMenu::updateDisplay() {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ if (vm->isDemo()) {
+ switch (_menuSelection) {
+ case kMainMenuStartDemo:
+ _smallSelect.moveElementTo(kStartSelectLeftDemo, kStartSelectTopDemo);
+ _smallSelect.show();
+ _largeSelect.hide();
+ break;
+ case kMainMenuCreditsDemo:
+ _smallSelect.moveElementTo(kCreditsSelectLeftDemo, kCreditsSelectTopDemo);
+ _smallSelect.show();
+ _largeSelect.hide();
+ break;
+ case kMainMenuQuitDemo:
+ _largeSelect.moveElementTo(kMainMenuQuitSelectLeftDemo, kMainMenuQuitSelectTopDemo);
+ _largeSelect.show();
+ _smallSelect.hide();
+ break;
+ }
+ } else {
+ switch (_menuSelection) {
+ case kMainMenuOverview:
+ _largeSelect.moveElementTo(kOverviewSelectLeft, kOverviewSelectTop);
+ _largeSelect.show();
+ _smallSelect.hide();
+ break;
+ case kMainMenuRestore:
+ _smallSelect.moveElementTo(kRestoreSelectLeft, kRestoreSelectTop);
+ _smallSelect.show();
+ _largeSelect.hide();
+ break;
+ case kMainMenuDifficulty:
+ if (_adventureMode) {
+ _adventureButton.show();
+ _walkthroughButton.hide();
+ } else {
+ _walkthroughButton.show();
+ _adventureButton.hide();
+ }
+
+ _largeSelect.moveElementTo(kDifficultySelectLeft, kDifficultySelectTop);
+ _largeSelect.show();
+ _smallSelect.hide();
+ break;
+ case kMainMenuStart:
+ _smallSelect.moveElementTo(kStartSelectLeft, kStartSelectTop);
+ _smallSelect.show();
+ _largeSelect.hide();
+ break;
+ case kMainMenuCredits:
+ _smallSelect.moveElementTo(kCreditsSelectLeft, kCreditsSelectTop);
+ _smallSelect.show();
+ _largeSelect.hide();
+ break;
+ case kMainMenuQuit:
+ _smallSelect.moveElementTo(kMainMenuQuitSelectLeft, kMainMenuQuitSelectTop);
+ _smallSelect.show();
+ _largeSelect.hide();
+ break;
+ }
+
+ vm->resetIntroTimer();
+ }
+}
+
+enum {
+ kCreditsMenuCoreTeam,
+ kCreditsMenuSupportTeam,
+ kCreditsMenuOriginalTeam,
+ kCreditsMenuTalent,
+ kCreditsMenuOtherTitles,
+ kCreditsMenuMainMenu,
+
+ kCreditsFirstSelection = kCreditsMenuCoreTeam,
+ kCreditsLastSelection = kCreditsMenuMainMenu
+};
+
+static const CoordType kCreditsMovieLeft = 288;
+static const CoordType kCreditsMovieTop = 0;
+
+static const CoordType kCoreTeamSelectLeft = 40;
+static const CoordType kCoreTeamSelectTop = 223;
+
+static const CoordType kSupportTeamSelectLeft = 40;
+static const CoordType kSupportTeamSelectTop = 259;
+
+static const CoordType kOriginalTeamSelectLeft = 40;
+static const CoordType kOriginalTeamSelectTop = 295;
+
+static const CoordType kTalentSelectLeft = 40;
+static const CoordType kTalentSelectTop = 331;
+
+static const CoordType kOtherTitlesSelectLeft = 40;
+static const CoordType kOtherTitlesSelectTop = 367;
+
+static const CoordType kCreditsMainMenuLeft = 32;
+static const CoordType kCreditsMainMenuTop = 412;
+
+static const CoordType kCreditsMainMenuSelectLeft = 30;
+static const CoordType kCreditsMainMenuSelectTop = 408;
+
+static const TimeValue kCoreTeamTime = 0;
+static const TimeValue kSupportTeamTime = 1920;
+static const TimeValue kOriginalTeamTime = 3000;
+static const TimeValue kTalentTime = 4440;
+static const TimeValue kOtherTitlesTime = 4680;
+
+static const TimeValue kFrameIncrement = 120; // Three frames...
+
+// Never set the current input handler to the CreditsMenu.
+CreditsMenu::CreditsMenu() : GameMenu(kCreditsMenuID), _menuBackground(0), _creditsMovie(0),
+ _mainMenuButton(0), _largeSelect(0), _smallSelect(0) {
+
+ _menuBackground.initFromPICTFile("Images/Credits/CredScrn.pict");
+ _menuBackground.setDisplayOrder(0);
+ _menuBackground.startDisplaying();
+ _menuBackground.show();
+
+ _creditsMovie.initFromMovieFile("Images/Credits/Credits.movie");
+ _creditsMovie.setDisplayOrder(1);
+ _creditsMovie.moveElementTo(kCreditsMovieLeft, kCreditsMovieTop);
+ _creditsMovie.startDisplaying();
+ _creditsMovie.show();
+ _creditsMovie.redrawMovieWorld();
+
+ _mainMenuButton.initFromPICTFile("Images/Credits/MainMenu.pict");
+ _mainMenuButton.setDisplayOrder(1);
+ _mainMenuButton.moveElementTo(kCreditsMainMenuLeft, kCreditsMainMenuTop);
+ _mainMenuButton.startDisplaying();
+
+ _largeSelect.initFromPICTFile("Images/Credits/SelectL.pict", true);
+ _largeSelect.setDisplayOrder(2);
+ _largeSelect.moveElementTo(kCreditsMainMenuSelectLeft, kCreditsMainMenuSelectTop);
+ _largeSelect.startDisplaying();
+
+ _smallSelect.initFromPICTFile("Images/Credits/SelectS.pict", true);
+ _smallSelect.setDisplayOrder(2);
+ _smallSelect.show();
+ _smallSelect.startDisplaying();
+
+ _menuSelection = -1;
+
+ newMenuSelection(kCreditsMenuCoreTeam);
+}
+
+// Assumes the new selection is never more than one away from the old...
+void CreditsMenu::newMenuSelection(const int newSelection) {
+ if (newSelection != _menuSelection) {
+ switch (newSelection) {
+ case kCreditsMenuCoreTeam:
+ _smallSelect.moveElementTo(kCoreTeamSelectLeft, kCoreTeamSelectTop);
+ _creditsMovie.setTime(kCoreTeamTime);
+ _creditsMovie.redrawMovieWorld();
+ break;
+ case kCreditsMenuSupportTeam:
+ _smallSelect.moveElementTo(kSupportTeamSelectLeft, kSupportTeamSelectTop);
+ _creditsMovie.setTime(kSupportTeamTime);
+ _creditsMovie.redrawMovieWorld();
+ break;
+ case kCreditsMenuOriginalTeam:
+ _smallSelect.moveElementTo(kOriginalTeamSelectLeft, kOriginalTeamSelectTop);
+ _creditsMovie.setTime(kOriginalTeamTime);
+ _creditsMovie.redrawMovieWorld();
+ break;
+ case kCreditsMenuTalent:
+ _smallSelect.moveElementTo(kTalentSelectLeft, kTalentSelectTop);
+ _creditsMovie.setTime(kTalentTime);
+ _creditsMovie.redrawMovieWorld();
+ break;
+ case kCreditsMenuOtherTitles:
+ _smallSelect.moveElementTo(kOtherTitlesSelectLeft, kOtherTitlesSelectTop);
+ _smallSelect.show();
+ _largeSelect.hide();
+ _creditsMovie.setTime(kOtherTitlesTime);
+ _creditsMovie.redrawMovieWorld();
+ break;
+ case kCreditsMenuMainMenu:
+ _smallSelect.hide();
+ _largeSelect.show();
+ break;
+ }
+
+ _menuSelection = newSelection;
+ }
+}
+
+void CreditsMenu::newMovieTime(const TimeValue newTime) {
+ if (newTime < kSupportTeamTime) {
+ _smallSelect.moveElementTo(kCoreTeamSelectLeft, kCoreTeamSelectTop);
+ _menuSelection = kCreditsMenuCoreTeam;
+ } else if (newTime < kOriginalTeamTime) {
+ _smallSelect.moveElementTo(kSupportTeamSelectLeft, kSupportTeamSelectTop);
+ _menuSelection = kCreditsMenuSupportTeam;
+ } else if (newTime < kTalentTime) {
+ _smallSelect.moveElementTo(kOriginalTeamSelectLeft, kOriginalTeamSelectTop);
+ _menuSelection = kCreditsMenuOriginalTeam;
+ } else if (newTime < kOtherTitlesTime) {
+ _smallSelect.moveElementTo(kTalentSelectLeft, kTalentSelectTop);
+ _smallSelect.show();
+ _largeSelect.hide();
+ _menuSelection = kCreditsMenuTalent;
+ } else if ((int)newTime == -120) {
+ // HACK: Avoid getting sent to the bottom button in the default case
+ return;
+ } else {
+ _smallSelect.moveElementTo(kOtherTitlesSelectLeft, kOtherTitlesSelectTop);
+ _smallSelect.show();
+ _largeSelect.hide();
+ _menuSelection = kCreditsMenuOtherTitles;
+ }
+
+ _creditsMovie.setTime(newTime);
+ _creditsMovie.redrawMovieWorld();
+}
+
+void CreditsMenu::handleInput(const Input &input, const Hotspot *cursorSpot) {
+ if (input.upButtonDown()) {
+ if (_menuSelection > kCreditsFirstSelection)
+ newMenuSelection(_menuSelection - 1);
+ } else if (input.downButtonDown()) {
+ if (_menuSelection < kCreditsLastSelection)
+ newMenuSelection(_menuSelection + 1);
+ } else if (input.leftButtonDown()) {
+ newMovieTime(_creditsMovie.getTime() - kFrameIncrement);
+ } else if (input.rightButtonDown()) {
+ newMovieTime(_creditsMovie.getTime() + kFrameIncrement);
+ } else if (JMPPPInput::isMenuButtonPressInput(input)) {
+ if (_menuSelection == kCreditsMenuMainMenu) {
+ _mainMenuButton.show();
+ ((PegasusEngine *)g_engine)->delayShell(kMenuButtonHiliteTime, kMenuButtonHiliteScale);
+ _mainMenuButton.hide();
+ setLastCommand(kMenuCmdCreditsMainMenu);
+ }
+ }
+
+ InputHandler::handleInput(input, cursorSpot);
+}
+
+static const CoordType kContinueLeft = 44;
+static const CoordType kContinueTop = 336;
+
+static const CoordType kContinueSelectLeft = 40;
+static const CoordType kContinueSelectTopDemo = 331;
+static const CoordType kContinueSelectTop = 332;
+
+static const CoordType kMainMenuLeftDemo = 44;
+static const CoordType kMainMenuTopDemo = 372;
+
+static const CoordType kMainMenuSelectLeftDemo = 40;
+static const CoordType kMainMenuSelectTopDemo = 367;
+
+static const CoordType kQuitLeftDemo = 32;
+static const CoordType kQuitTopDemo = 412;
+
+static const CoordType kQuitSelectLeftDemo = 28;
+static const CoordType kQuitSelectTopDemo = 408;
+
+static const CoordType kRestoreLeftDeath = 44;
+static const CoordType kRestoreTopDeath = 372;
+
+static const CoordType kRestoreSelectLeftDeath = 40;
+static const CoordType kRestoreSelectTopDeath = 368;
+
+static const CoordType kMainMenuLeft = 32;
+static const CoordType kMainMenuTop = 412;
+
+static const CoordType kMainMenuSelectLeft = 28;
+static const CoordType kMainMenuSelectTop = 408;
+
+enum {
+ kDeathScreenContinueDemo = 0,
+ kDeathScreenMainMenuDemo,
+ kDeathScreenQuitDemo,
+
+ kFirstDeathSelectionDemo = kDeathScreenContinueDemo,
+ kLastDeathSelectionDemo = kDeathScreenQuitDemo,
+
+ kDeathScreenContinue = 0,
+ kDeathScreenRestore,
+ kDeathScreenMainMenu,
+
+ kFirstDeathSelection = kDeathScreenContinue,
+ kLastDeathSelection = kDeathScreenMainMenu
+};
+
+// Never set the current input handler to the DeathMenu.
+DeathMenu::DeathMenu(const DeathReason deathReason) : GameMenu(kDeathMenuID), _deathBackground(0), _continueButton(0),
+ _mainMenuButton(0), _quitButton(0), _restoreButton(0), _largeSelect(0), _smallSelect(0) {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+ bool isDemo = vm->isDemo();
+
+ _playerWon = (deathReason == kPlayerWonGame);
+
+ Common::String prefix = "Images/";
+ Common::String imageName;
+ if (isDemo) {
+ prefix += "Demo/";
+ imageName = prefix;
+
+ switch (deathReason) {
+ case kDeathFallOffCliff:
+ imageName += "dPfall";
+ break;
+ case kDeathEatenByDinosaur:
+ imageName += "dPdino";
+ break;
+ case kDeathStranded:
+ imageName += "dPstuck";
+ break;
+ default:
+ imageName += "dPdemowin";
+ break;
+ }
+
+ imageName += ".pict";
+ } else {
+ prefix += "Death Screens/";
+ imageName = prefix;
+
+ static const char *fileNames[] = {
+ "dAunmade", "dAbombed", "dAshot", "dAassass", "dAnuked",
+ "dTunmade", "dTshot", "dPfall", "dPdino", "dPstuck",
+ "dNchoke", "dNcaught", "dNcaught", "dNsub", "dNrobot1",
+ "dNrobot2", "dMfall", "dMcaught", "dMtracks", "dMrobot",
+ "dMtoast", "dMexplo1", "dMexplo2", "dMchoke1", "dMchoke2",
+ "dMdroid", "dMfall", "dMgears", "dMshutt1", "dMshutt2",
+ "dWpoison", "dWcaught", "dWplasma", "dWshot", "dAfinale"
+ };
+
+ imageName += fileNames[deathReason - 1];
+ imageName += ".pict";
+ }
+
+ _deathBackground.initFromPICTFile(imageName);
+ _deathReason = deathReason;
+
+ if (!isDemo) {
+ vm->_gfx->setCurSurface(_deathBackground.getSurface());
+ drawAllScores();
+ vm->_gfx->setCurSurface(vm->_gfx->getWorkArea());
+ }
+
+ _deathBackground.setDisplayOrder(0);
+ _deathBackground.startDisplaying();
+ _deathBackground.show();
+
+ if (isDemo) {
+ if (_playerWon) // Make credits button...
+ _continueButton.initFromPICTFile(prefix + "Credits.pict");
+ else // Make continue button...
+ _continueButton.initFromPICTFile(prefix + "Continue.pict");
+
+ _mainMenuButton.initFromPICTFile(prefix + "MainMenu.pict");
+ _mainMenuButton.setDisplayOrder(1);
+ _mainMenuButton.moveElementTo(kMainMenuLeftDemo, kMainMenuTopDemo);
+ _mainMenuButton.startDisplaying();
+
+ _quitButton.initFromPICTFile(prefix + "Quit.pict");
+ _quitButton.setDisplayOrder(1);
+ _quitButton.moveElementTo(kQuitLeftDemo, kQuitTopDemo);
+ _quitButton.startDisplaying();
+
+ _menuSelection = kDeathScreenContinueDemo;
+ } else {
+ if (!_playerWon) {
+ _mainMenuButton.initFromPICTFile(prefix + "MainMenu.pict");
+ _mainMenuButton.setDisplayOrder(1);
+ _mainMenuButton.moveElementTo(kMainMenuLeft, kMainMenuTop);
+ _mainMenuButton.startDisplaying();
+
+ _restoreButton.initFromPICTFile(prefix + "Restore.pict");
+ _restoreButton.setDisplayOrder(1);
+ _restoreButton.moveElementTo(kRestoreLeftDeath, kRestoreTopDeath);
+ _restoreButton.startDisplaying();
+ }
+
+ _continueButton.initFromPICTFile(prefix + "Continue.pict");
+
+ _menuSelection = kDeathScreenContinue;
+ }
+
+ _smallSelect.initFromPICTFile(prefix + "SelectS.pict", true);
+ _smallSelect.setDisplayOrder(2);
+ _smallSelect.startDisplaying();
+
+ _continueButton.setDisplayOrder(1);
+ _continueButton.moveElementTo(kContinueLeft, kContinueTop);
+ _continueButton.startDisplaying();
+
+ if (isDemo || !_playerWon) {
+ _largeSelect.initFromPICTFile(prefix + "SelectL.pict", true);
+ _largeSelect.setDisplayOrder(2);
+ _largeSelect.startDisplaying();
+ } else {
+ _triumphSound.initFromQuickTime("Sounds/Caldoria/Galactic Triumph");
+ _triumphSound.playSound();
+ }
+
+ updateDisplay();
+}
+
+void DeathMenu::handleInput(const Input &input, const Hotspot *cursorSpot) {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ if (input.upButtonDown()) {
+ if (_menuSelection > (vm->isDemo() ? kFirstDeathSelectionDemo : kFirstDeathSelection)) {
+ _menuSelection--;
+ updateDisplay();
+ }
+ } else if (input.downButtonDown() && (vm->isDemo() || !_playerWon)) {
+ if (_menuSelection < (vm->isDemo() ? kLastDeathSelectionDemo : kLastDeathSelection)) {
+ _menuSelection++;
+ updateDisplay();
+ }
+ } else if (JMPPPInput::isMenuButtonPressInput(input)) {
+ if (vm->isDemo()) {
+ switch (_menuSelection) {
+ case kDeathScreenContinueDemo:
+ _continueButton.show();
+ vm->delayShell(kMenuButtonHiliteTime, kMenuButtonHiliteScale);
+ _continueButton.hide();
+ setLastCommand(kMenuCmdDeathContinue);
+ break;
+ case kDeathScreenQuitDemo:
+ _quitButton.show();
+ vm->delayShell(kMenuButtonHiliteTime, kMenuButtonHiliteScale);
+ _quitButton.hide();
+ setLastCommand(kMenuCmdDeathQuitDemo);
+ break;
+ case kDeathScreenMainMenuDemo:
+ _mainMenuButton.show();
+ vm->delayShell(kMenuButtonHiliteTime, kMenuButtonHiliteScale);
+ _mainMenuButton.hide();
+ setLastCommand(kMenuCmdDeathMainMenuDemo);
+ break;
+ }
+ } else {
+ switch (_menuSelection) {
+ case kDeathScreenContinue:
+ _continueButton.show();
+ vm->delayShell(kMenuButtonHiliteTime, kMenuButtonHiliteScale);
+ _continueButton.hide();
+ setLastCommand(kMenuCmdDeathContinue);
+ break;
+ case kDeathScreenRestore:
+ _restoreButton.show();
+ vm->delayShell(kMenuButtonHiliteTime, kMenuButtonHiliteScale);
+ _restoreButton.hide();
+ setLastCommand(kMenuCmdDeathRestore);
+ break;
+ case kDeathScreenMainMenu:
+ _mainMenuButton.show();
+ vm->delayShell(kMenuButtonHiliteTime, kMenuButtonHiliteScale);
+ _mainMenuButton.hide();
+ setLastCommand(kMenuCmdDeathMainMenu);
+ break;
+ }
+ }
+ }
+
+ InputHandler::handleInput(input, cursorSpot);
+}
+
+void DeathMenu::updateDisplay() {
+ if (((PegasusEngine *)g_engine)->isDemo()) {
+ switch (_menuSelection) {
+ case kDeathScreenContinueDemo:
+ _smallSelect.moveElementTo(kContinueSelectLeft, kContinueSelectTopDemo);
+ _smallSelect.show();
+ _largeSelect.hide();
+ break;
+ case kDeathScreenQuitDemo:
+ _largeSelect.moveElementTo(kQuitSelectLeftDemo, kQuitSelectTopDemo);
+ _largeSelect.show();
+ _smallSelect.hide();
+ break;
+ case kDeathScreenMainMenuDemo:
+ _smallSelect.moveElementTo(kMainMenuSelectLeftDemo, kMainMenuSelectTopDemo);
+ _smallSelect.show();
+ _largeSelect.hide();
+ break;
+ }
+ } else {
+ switch (_menuSelection) {
+ case kDeathScreenContinue:
+ _smallSelect.moveElementTo(kContinueSelectLeft, kContinueSelectTop);
+ _smallSelect.show();
+ _largeSelect.hide();
+ break;
+ case kDeathScreenRestore:
+ _smallSelect.moveElementTo(kRestoreSelectLeftDeath, kRestoreSelectTopDeath);
+ _smallSelect.show();
+ _largeSelect.hide();
+ break;
+ case kDeathScreenMainMenu:
+ _largeSelect.moveElementTo(kMainMenuSelectLeft, kMainMenuSelectTop);
+ _largeSelect.show();
+ _smallSelect.hide();
+ break;
+ }
+ }
+}
+
+void DeathMenu::drawAllScores() {
+ Surface numbers;
+ numbers.getImageFromPICTFile("Images/Death Screens/Numbers.pict");
+
+ Common::Rect scoreBounds;
+ GameScoreType caldoriaTotal = 0;
+
+ switch (_deathReason) {
+ case kDeathCardBomb:
+ case kDeathShotBySinclair:
+ case kDeathSinclairShotDelegate:
+ case kDeathNuclearExplosion:
+ case kDeathGassedInNorad:
+ case kDeathWokeUpNorad:
+ case kDeathArrestedInNorad:
+ case kDeathSubDestroyed:
+ case kDeathRobotThroughNoradDoor:
+ case kDeathRobotSubControlRoom:
+ case kDeathWrongShuttleLock:
+ case kDeathArrestedInMars:
+ case kDeathRunOverByPod:
+ case kDeathDidntGetOutOfWay:
+ case kDeathReactorBurn:
+ case kDeathDidntFindMarsBomb:
+ case kDeathDidntDisarmMarsBomb:
+ case kDeathNoMaskInMaze:
+ case kDeathNoAirInMaze:
+ case kDeathGroundByMazebot:
+ case kDeathMissedOreBucket:
+ case kDeathDidntLeaveBucket:
+ case kDeathRanIntoCanyonWall:
+ case kDeathRanIntoSpaceJunk:
+ case kDeathDidntStopPoison:
+ case kDeathArrestedInWSC:
+ case kDeathHitByPlasma:
+ case kDeathShotOnCatwalk:
+ case kPlayerWonGame:
+ caldoriaTotal += kMaxCaldoriaTSAScoreAfter;
+ scoreBounds = Common::Rect(kDeathScreenScoreLeft, kDeathScreenScoreTop - kDeathScreenScoreSkipVert * 5,
+ kDeathScreenScoreLeft + kDeathScreenScoreWidth, kDeathScreenScoreTop - kDeathScreenScoreSkipVert * 5 + kDeathScreenScoreHeight);
+ drawScore(GameState.getGandhiScore(), kMaxGandhiScore, scoreBounds, &numbers);
+
+ scoreBounds.translate(0, kDeathScreenScoreSkipVert);
+ drawScore(GameState.getWSCScore(), kMaxWSCScore, scoreBounds, &numbers);
+
+ scoreBounds.translate(0, kDeathScreenScoreSkipVert);
+ drawScore(GameState.getNoradScore(), kMaxNoradScore, scoreBounds, &numbers);
+
+ scoreBounds.translate(0, kDeathScreenScoreSkipVert);
+ drawScore(GameState.getMarsScore(), kMaxMarsScore, scoreBounds, &numbers);
+ // fall through
+ case kDeathFallOffCliff:
+ case kDeathEatenByDinosaur:
+ case kDeathStranded:
+ case kDeathShotByTSARobots:
+ scoreBounds = Common::Rect(kDeathScreenScoreLeft, kDeathScreenScoreTop - kDeathScreenScoreSkipVert,
+ kDeathScreenScoreLeft + kDeathScreenScoreWidth, kDeathScreenScoreTop - kDeathScreenScoreSkipVert + kDeathScreenScoreHeight);
+ drawScore(GameState.getPrehistoricScore(), kMaxPrehistoricScore, scoreBounds, &numbers);
+ // fall through
+ case kDeathUncreatedInCaldoria:
+ case kDeathUncreatedInTSA:
+ scoreBounds = Common::Rect(kDeathScreenScoreLeft, kDeathScreenScoreTop, kDeathScreenScoreLeft + kDeathScreenScoreWidth,
+ kDeathScreenScoreTop + kDeathScreenScoreHeight);
+ caldoriaTotal += kMaxCaldoriaTSAScoreBefore;
+ drawScore(GameState.getCaldoriaTSAScore(), caldoriaTotal, scoreBounds, &numbers);
+
+ scoreBounds = Common::Rect(kDeathScreenScoreLeft, kDeathScreenScoreTop - kDeathScreenScoreSkipVert * 6,
+ kDeathScreenScoreLeft + kDeathScreenScoreWidth, kDeathScreenScoreTop - kDeathScreenScoreSkipVert * 6 + kDeathScreenScoreHeight);
+
+ drawScore(GameState.getTotalScore(), kMaxTotalScore, scoreBounds, &numbers);
+ break;
+ }
+}
+
+enum {
+ kPauseMenuSave,
+ kPauseMenuContinue,
+ kPauseMenuRestore,
+ kPauseMenuSoundFX,
+ kPauseMenuAmbience,
+ kPauseMenuWalkthru,
+ kPauseMenuQuitToMainMenu,
+
+ kFirstPauseSelection = kPauseMenuSave,
+ kLastPauseSelection = kPauseMenuQuitToMainMenu
+};
+
+static const CoordType kPauseLeft = 194;
+static const CoordType kPauseTop = 68;
+
+static const CoordType kSaveGameLeft = kPauseLeft + 6;
+static const CoordType kSaveGameTop = kPauseTop + 56;
+
+static const CoordType kSaveGameSelectLeft = kPauseLeft - 44;
+static const CoordType kSaveGameSelectTop = kPauseTop + 52;
+
+static const CoordType kPauseContinueLeft = kPauseLeft + 18;
+static const CoordType kPauseContinueTop = kPauseTop + 100;
+
+static const CoordType kPauseContinueSelectLeft = kPauseLeft - 44;
+static const CoordType kPauseContinueSelectTop = kPauseTop + 95;
+
+static const CoordType kPauseRestoreLeft = kPauseLeft + 18;
+static const CoordType kPauseRestoreTop = kPauseTop + 136;
+
+static const CoordType kPauseRestoreSelectLeft = kPauseLeft - 44;
+static const CoordType kPauseRestoreSelectTop = kPauseTop + 131;
+
+static const CoordType kSoundFXLeft = kPauseLeft + 128;
+static const CoordType kSoundFXTop = kPauseTop + 187;
+static const CoordType kSoundFXRight = kSoundFXLeft + 96;
+static const CoordType kSoundFXBottom = kSoundFXTop + 14;
+
+static const CoordType kSoundFXSelectLeft = kPauseLeft - 44;
+static const CoordType kSoundFXSelectTop = kPauseTop + 172;
+
+static const CoordType kAmbienceLeft = kPauseLeft + 128;
+static const CoordType kAmbienceTop = kPauseTop + 227;
+static const CoordType kAmbienceRight = kAmbienceLeft + 96;
+static const CoordType kAmbienceBottom = kAmbienceTop + 14;
+
+static const CoordType kAmbienceSelectLeft = kPauseLeft - 44;
+static const CoordType kAmbienceSelectTop = kPauseTop + 212;
+
+static const CoordType kWalkthruLeft = kPauseLeft + 128;
+static const CoordType kWalkthruTop = kPauseTop + 264;
+
+static const CoordType kWalkthruSelectLeft = kPauseLeft - 44;
+static const CoordType kWalkthruSelectTop = kPauseTop + 255;
+
+static const CoordType kQuitLeft = kPauseLeft + 18;
+static const CoordType kQuitTop = kPauseTop + 302;
+
+static const CoordType kQuitSelectLeft = kPauseLeft - 44;
+static const CoordType kQuitSelectTop = kPauseTop + 297;
+
+// These are relative to the pause background.
+static const CoordType kPauseScoreLeft = 130;
+static const CoordType kPauseScoreTop = 34;
+static const CoordType kPauseScoreRight = kPauseScoreLeft + 108;
+static const CoordType kPauseScoreBottom = kPauseScoreTop + 12;
+
+// Never set the current input handler to the CPauseMenu.
+PauseMenu::PauseMenu() : GameMenu(kPauseMenuID), _pauseBackground(0), _saveButton(0), _restoreButton(0),
+ _walkthroughButton(0), _continueButton(0), _soundFXLevel(0), _ambienceLevel(0), _quitButton(0),
+ _largeSelect(0), _smallSelect(0) {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ _pauseBackground.initFromPICTFile("Images/Pause Screen/PausScrn.pict", true);
+
+ if (!vm->isDemo()) {
+ Surface numbers;
+ numbers.getImageFromPICTFile("Images/Pause Screen/Numbers.pict");
+ vm->_gfx->setCurSurface(_pauseBackground.getSurface());
+ drawScore(GameState.getTotalScore(), kMaxTotalScore,
+ Common::Rect(kPauseScoreLeft, kPauseScoreTop, kPauseScoreRight, kPauseScoreBottom), &numbers);
+ vm->_gfx->setCurSurface(vm->_gfx->getWorkArea());
+ }
+
+ _pauseBackground.setDisplayOrder(kPauseMenuOrder);
+ _pauseBackground.moveElementTo(kPauseLeft, kPauseTop);
+ _pauseBackground.startDisplaying();
+ _pauseBackground.show();
+
+ if (!vm->isDemo()) {
+ _saveButton.initFromPICTFile("Images/Pause Screen/SaveGame.pict");
+ _saveButton.setDisplayOrder(kSaveGameOrder);
+ _saveButton.moveElementTo(kSaveGameLeft, kSaveGameTop);
+ _saveButton.startDisplaying();
+
+ _restoreButton.initFromPICTFile("Images/Pause Screen/Restore.pict");
+ _restoreButton.setDisplayOrder(kRestoreOrder);
+ _restoreButton.moveElementTo(kPauseRestoreLeft, kPauseRestoreTop);
+ _restoreButton.startDisplaying();
+
+ _walkthroughButton.initFromPICTFile("Images/Pause Screen/Walkthru.pict");
+ _walkthroughButton.setDisplayOrder(kWalkthruOrder);
+ _walkthroughButton.moveElementTo(kWalkthruLeft, kWalkthruTop);
+ _walkthroughButton.startDisplaying();
+
+ if (GameState.getWalkthroughMode())
+ _walkthroughButton.show();
+ }
+
+ _continueButton.initFromPICTFile("Images/Pause Screen/Continue.pict");
+ _continueButton.setDisplayOrder(kContinueOrder);
+ _continueButton.moveElementTo(kPauseContinueLeft, kPauseContinueTop);
+ _continueButton.startDisplaying();
+
+ _soundFXLevel.setDisplayOrder(kSoundFXOrder);
+ _soundFXLevel.setBounds(Common::Rect(kSoundFXLeft, kSoundFXTop, kSoundFXRight, kSoundFXBottom));
+ _soundFXLevel.startDisplaying();
+ _soundFXLevel.show();
+ _soundFXLevel.setSoundLevel(vm->getSoundFXLevel());
+
+ _ambienceLevel.setDisplayOrder(kAmbienceOrder);
+ _ambienceLevel.setBounds(Common::Rect(kAmbienceLeft, kAmbienceTop, kAmbienceRight, kAmbienceBottom));
+ _ambienceLevel.startDisplaying();
+ _ambienceLevel.show();
+ _ambienceLevel.setSoundLevel(vm->getAmbienceLevel());
+
+ _quitButton.initFromPICTFile("Images/Pause Screen/Quit2MM.pict");
+ _quitButton.setDisplayOrder(kQuitToMainMenuOrder);
+ _quitButton.moveElementTo(kQuitLeft, kQuitTop);
+ _quitButton.startDisplaying();
+
+ _largeSelect.initFromPICTFile("Images/Pause Screen/SelectL.pict", true);
+ _largeSelect.setDisplayOrder(kPauseLargeHiliteOrder);
+ _largeSelect.startDisplaying();
+
+ _smallSelect.initFromPICTFile("Images/Pause Screen/SelectS.pict", true);
+ _smallSelect.setDisplayOrder(kPauseSmallHiliteOrder);
+ _smallSelect.startDisplaying();
+
+ _menuSelection = (vm->isDemo()) ? kPauseMenuContinue : kPauseMenuSave;
+
+ updateDisplay();
+}
+
+void PauseMenu::handleInput(const Input &input, const Hotspot *cursorSpot) {
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ if (input.upButtonDown()) {
+ if (vm->isDemo()) {
+ if (_menuSelection > kPauseMenuContinue) {
+ switch (_menuSelection) {
+ case kPauseMenuSoundFX:
+ _menuSelection = kPauseMenuContinue;
+ break;
+ case kPauseMenuAmbience:
+ _menuSelection = kPauseMenuSoundFX;
+ break;
+ case kPauseMenuQuitToMainMenu:
+ _menuSelection = kPauseMenuAmbience;
+ break;
+ }
+ updateDisplay();
+ }
+ } else {
+ if (_menuSelection > kFirstPauseSelection) {
+ _menuSelection--;
+ updateDisplay();
+ }
+ }
+ } else if (input.downButtonDown()) {
+ if (vm->isDemo()) {
+ if (_menuSelection < kPauseMenuQuitToMainMenu) {
+ switch (_menuSelection) {
+ case kPauseMenuContinue:
+ _menuSelection = kPauseMenuSoundFX;
+ break;
+ case kPauseMenuSoundFX:
+ _menuSelection = kPauseMenuAmbience;
+ break;
+ case kPauseMenuAmbience:
+ _menuSelection = kPauseMenuQuitToMainMenu;
+ break;
+ }
+ updateDisplay();
+ }
+ } else {
+ if (_menuSelection < kLastPauseSelection) {
+ _menuSelection++;
+ updateDisplay();
+ }
+ }
+ } else if (input.leftButtonDown()) {
+ if (_menuSelection == kPauseMenuSoundFX) {
+ _soundFXLevel.decrementLevel();
+ vm->setSoundFXLevel(_soundFXLevel.getSoundLevel());
+ } else if (_menuSelection == kPauseMenuAmbience) {
+ _ambienceLevel.decrementLevel();
+ vm->setAmbienceLevel(_ambienceLevel.getSoundLevel());
+ } else if (!vm->isDemo() && _menuSelection == kPauseMenuWalkthru) {
+ GameState.setWalkthroughMode(!GameState.getWalkthroughMode());
+ if (GameState.getWalkthroughMode())
+ _walkthroughButton.show();
+ else
+ _walkthroughButton.hide();
+ }
+ } else if (input.rightButtonDown()) {
+ if (_menuSelection == kPauseMenuSoundFX) {
+ _soundFXLevel.incrementLevel();
+ vm->setSoundFXLevel(_soundFXLevel.getSoundLevel());
+ } else if (_menuSelection == kPauseMenuAmbience) {
+ _ambienceLevel.incrementLevel();
+ vm->setAmbienceLevel(_ambienceLevel.getSoundLevel());
+ } else if (!vm->isDemo() && _menuSelection == kPauseMenuWalkthru) {
+ GameState.setWalkthroughMode(!GameState.getWalkthroughMode());
+ if (GameState.getWalkthroughMode())
+ _walkthroughButton.show();
+ else
+ _walkthroughButton.hide();
+ }
+ } else if (JMPPPInput::isMenuButtonPressInput(input)) {
+ switch (_menuSelection) {
+ case kPauseMenuSave:
+ _saveButton.show();
+ vm->delayShell(kMenuButtonHiliteTime, kMenuButtonHiliteScale);
+ _saveButton.hide();
+ setLastCommand(kMenuCmdPauseSave);
+ break;
+ case kPauseMenuRestore:
+ _restoreButton.show();
+ vm->delayShell(kMenuButtonHiliteTime, kMenuButtonHiliteScale);
+ _restoreButton.hide();
+ setLastCommand(kMenuCmdPauseRestore);
+ break;
+ case kPauseMenuContinue:
+ _continueButton.show();
+ vm->delayShell(kMenuButtonHiliteTime, kMenuButtonHiliteScale);
+ _continueButton.hide();
+ setLastCommand(kMenuCmdPauseContinue);
+ break;
+ case kPauseMenuWalkthru:
+ GameState.setWalkthroughMode(!GameState.getWalkthroughMode());
+ if (GameState.getWalkthroughMode())
+ _walkthroughButton.show();
+ else
+ _walkthroughButton.hide();
+ break;
+ case kPauseMenuQuitToMainMenu:
+ _quitButton.show();
+ vm->delayShell(kMenuButtonHiliteTime, kMenuButtonHiliteScale);
+ _quitButton.hide();
+ setLastCommand(kMenuCmdPauseQuit);
+ break;
+ }
+ }
+
+ InputHandler::handleInput(input, cursorSpot);
+}
+
+void PauseMenu::updateDisplay() {
+ switch (_menuSelection) {
+ case kPauseMenuSave:
+ _largeSelect.moveElementTo(kSaveGameSelectLeft, kSaveGameSelectTop);
+ _largeSelect.show();
+ _smallSelect.hide();
+ break;
+ case kPauseMenuContinue:
+ _smallSelect.moveElementTo(kPauseContinueSelectLeft, kPauseContinueSelectTop);
+ _smallSelect.show();
+ _largeSelect.hide();
+ break;
+ case kPauseMenuRestore:
+ _smallSelect.moveElementTo(kPauseRestoreSelectLeft, kPauseRestoreSelectTop);
+ _smallSelect.show();
+ _largeSelect.hide();
+ break;
+ case kPauseMenuSoundFX:
+ _largeSelect.moveElementTo(kSoundFXSelectLeft, kSoundFXSelectTop);
+ _largeSelect.show();
+ _smallSelect.hide();
+ break;
+ case kPauseMenuAmbience:
+ _largeSelect.moveElementTo(kAmbienceSelectLeft, kAmbienceSelectTop);
+ _largeSelect.show();
+ _smallSelect.hide();
+ break;
+ case kPauseMenuWalkthru:
+ _largeSelect.moveElementTo(kWalkthruSelectLeft, kWalkthruSelectTop);
+ _largeSelect.show();
+ _smallSelect.hide();
+ break;
+ case kPauseMenuQuitToMainMenu:
+ _smallSelect.moveElementTo(kQuitSelectLeft, kQuitSelectTop);
+ _smallSelect.show();
+ _largeSelect.hide();
+ break;
+ }
+
+ ((PegasusEngine *)g_engine)->resetIntroTimer();
+}
+
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/menu.h b/engines/pegasus/menu.h
new file mode 100644
index 0000000000..288b846093
--- /dev/null
+++ b/engines/pegasus/menu.h
@@ -0,0 +1,171 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_MENU_H
+#define PEGASUS_MENU_H
+
+#include "pegasus/constants.h"
+#include "pegasus/fader.h"
+#include "pegasus/input.h"
+#include "pegasus/movie.h"
+#include "pegasus/sound.h"
+#include "pegasus/surface.h"
+#include "pegasus/util.h"
+
+namespace Pegasus {
+
+class GameMenu : public IDObject, public InputHandler {
+public:
+ GameMenu(const uint32);
+ virtual ~GameMenu() {}
+
+ virtual void becomeCurrentHandler();
+ virtual void restorePreviousHandler();
+
+ GameMenuCommand getLastCommand() { return _lastCommand; }
+ void clearLastCommand() { _lastCommand = kMenuCmdNoCommand; }
+
+protected:
+ void setLastCommand(const GameMenuCommand command) { _lastCommand = command; }
+
+ InputHandler *_previousHandler;
+ GameMenuCommand _lastCommand;
+
+ void drawScore(GameScoreType, GameScoreType, const Common::Rect &, Surface *);
+
+private:
+ void drawNumber(GameScoreType, CoordType &, CoordType, Surface *);
+};
+
+class Hotspot;
+
+class MainMenu : public GameMenu {
+public:
+ MainMenu();
+ virtual ~MainMenu();
+
+ virtual void handleInput(const Input &input, const Hotspot *);
+ void startMainMenuLoop();
+ void stopMainMenuLoop();
+
+protected:
+ void updateDisplay();
+
+ uint32 _menuSelection;
+
+ // Full and Demo
+ Picture _menuBackground;
+ Picture _startButton;
+ Picture _creditsButton;
+ Picture _quitButton;
+ Picture _largeSelect;
+ Picture _smallSelect;
+
+ // Full only
+ bool _adventureMode;
+ Picture _overviewButton;
+ Picture _restoreButton;
+ Picture _adventureButton;
+ Picture _walkthroughButton;
+
+ Sound _menuLoop;
+ SoundFader _menuFader;
+};
+
+class CreditsMenu : public GameMenu {
+public:
+ CreditsMenu();
+ virtual ~CreditsMenu() {}
+
+ virtual void handleInput(const Input &input, const Hotspot *);
+
+protected:
+ void newMenuSelection(const int);
+ void newMovieTime(const TimeValue);
+
+ int _menuSelection;
+ Picture _menuBackground;
+ Movie _creditsMovie;
+ Picture _mainMenuButton;
+ Picture _largeSelect;
+ Picture _smallSelect;
+};
+
+class DeathMenu : public GameMenu {
+public:
+ DeathMenu(const DeathReason);
+ virtual ~DeathMenu() {}
+
+ virtual void handleInput(const Input &input, const Hotspot *);
+
+ bool playerWon() { return _playerWon; }
+
+protected:
+ void drawAllScores();
+
+ void updateDisplay();
+
+ bool _playerWon;
+ int _menuSelection;
+ DeathReason _deathReason;
+
+ Picture _deathBackground;
+ Picture _continueButton;
+ Picture _restoreButton;
+ Picture _mainMenuButton;
+ Picture _quitButton;
+
+ Picture _largeSelect;
+ Picture _smallSelect;
+
+ Sound _triumphSound;
+};
+
+class PauseMenu : public GameMenu {
+public:
+ PauseMenu();
+ virtual ~PauseMenu() {}
+
+ virtual void handleInput(const Input &input, const Hotspot *);
+
+protected:
+ void updateDisplay();
+
+ uint32 _menuSelection;
+ Picture _pauseBackground;
+ Picture _saveButton;
+ Picture _restoreButton;
+ Picture _walkthroughButton;
+ Picture _continueButton;
+ SoundLevel _soundFXLevel;
+ SoundLevel _ambienceLevel;
+ Picture _quitButton;
+ Picture _largeSelect;
+ Picture _smallSelect;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/module.mk b/engines/pegasus/module.mk
new file mode 100644
index 0000000000..cb44a04171
--- /dev/null
+++ b/engines/pegasus/module.mk
@@ -0,0 +1,100 @@
+MODULE := engines/pegasus
+
+MODULE_OBJS = \
+ compass.o \
+ console.o \
+ cursor.o \
+ detection.o \
+ elements.o \
+ energymonitor.o \
+ fader.o \
+ gamestate.o \
+ graphics.o \
+ hotspot.o \
+ input.o \
+ interface.o \
+ menu.o \
+ movie.o \
+ notification.o \
+ pegasus.o \
+ sound.o \
+ surface.o \
+ timers.o \
+ transition.o \
+ util.o \
+ ai/ai_action.o \
+ ai/ai_area.o \
+ ai/ai_condition.o \
+ ai/ai_rule.o \
+ items/autodragger.o \
+ items/inventory.o \
+ items/inventorypicture.o \
+ items/item.o \
+ items/itemdragger.o \
+ items/itemlist.o \
+ items/biochips/aichip.o \
+ items/biochips/biochipitem.o \
+ items/biochips/mapchip.o \
+ items/biochips/mapimage.o \
+ items/biochips/opticalchip.o \
+ items/biochips/pegasuschip.o \
+ items/biochips/retscanchip.o \
+ items/biochips/shieldchip.o \
+ items/inventory/airmask.o \
+ items/inventory/gascanister.o \
+ items/inventory/inventoryitem.o \
+ items/inventory/keycard.o \
+ neighborhood/door.o \
+ neighborhood/exit.o \
+ neighborhood/extra.o \
+ neighborhood/hotspotinfo.o \
+ neighborhood/neighborhood.o \
+ neighborhood/spot.o \
+ neighborhood/turn.o \
+ neighborhood/view.o \
+ neighborhood/zoom.o \
+ neighborhood/caldoria/caldoria.o \
+ neighborhood/caldoria/caldoria4dsystem.o \
+ neighborhood/caldoria/caldoriabomb.o \
+ neighborhood/caldoria/caldoriamessages.o \
+ neighborhood/caldoria/caldoriamirror.o \
+ neighborhood/mars/energybeam.o \
+ neighborhood/mars/gravitoncannon.o \
+ neighborhood/mars/hermite.o \
+ neighborhood/mars/mars.o \
+ neighborhood/mars/planetmover.o \
+ neighborhood/mars/reactor.o \
+ neighborhood/mars/robotship.o \
+ neighborhood/mars/shuttleenergymeter.o \
+ neighborhood/mars/shuttlehud.o \
+ neighborhood/mars/shuttleweapon.o \
+ neighborhood/mars/spacechase3d.o \
+ neighborhood/mars/spacejunk.o \
+ neighborhood/mars/tractorbeam.o \
+ neighborhood/norad/norad.o \
+ neighborhood/norad/noradelevator.o \
+ neighborhood/norad/pressuredoor.o \
+ neighborhood/norad/pressuretracker.o \
+ neighborhood/norad/subcontrolroom.o \
+ neighborhood/norad/subplatform.o \
+ neighborhood/norad/alpha/ecrmonitor.o \
+ neighborhood/norad/alpha/fillingstation.o \
+ neighborhood/norad/alpha/noradalpha.o \
+ neighborhood/norad/alpha/panorama.o \
+ neighborhood/norad/alpha/panoramascroll.o \
+ neighborhood/norad/delta/globegame.o \
+ neighborhood/norad/delta/noraddelta.o \
+ neighborhood/prehistoric/prehistoric.o \
+ neighborhood/tsa/fulltsa.o \
+ neighborhood/tsa/tinytsa.o \
+ neighborhood/wsc/moleculebin.o \
+ neighborhood/wsc/wsc.o
+
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_PEGASUS), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/pegasus/movie.cpp b/engines/pegasus/movie.cpp
new file mode 100644
index 0000000000..75c287c7a6
--- /dev/null
+++ b/engines/pegasus/movie.cpp
@@ -0,0 +1,280 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/system.h"
+#include "graphics/surface.h"
+#include "video/qt_decoder.h"
+#include "video/video_decoder.h"
+
+#include "pegasus/movie.h"
+
+namespace Pegasus {
+
+Movie::Movie(const DisplayElementID id) : Animation(id) {
+ _video = 0;
+ setScale(600);
+}
+
+Movie::~Movie() {
+ releaseMovie();
+}
+
+// *** Make sure this will stop displaying the movie.
+
+void Movie::releaseMovie() {
+ if (_video) {
+ delete _video;
+ _video = 0;
+ disposeAllCallBacks();
+ deallocateSurface();
+ }
+
+ setBounds(Common::Rect(0, 0, 0, 0));
+}
+
+void Movie::initFromMovieFile(const Common::String &fileName, bool transparent) {
+ _transparent = transparent;
+
+ releaseMovie();
+ _video = new Video::QuickTimeDecoder();
+ if (!_video->loadFile(fileName)) {
+ // Replace any colon with an underscore, since only Mac OS X
+ // supports that. See PegasusEngine::detectOpeningClosingDirectory()
+ // for more info.
+ Common::String newName(fileName);
+ if (newName.contains(':'))
+ for (uint i = 0; i < newName.size(); i++)
+ if (newName[i] == ':')
+ newName.setChar('_', i);
+
+ if (!_video->loadFile(newName))
+ error("Could not load video '%s'", fileName.c_str());
+ }
+
+ Common::Rect bounds(0, 0, _video->getWidth(), _video->getHeight());
+ sizeElement(_video->getWidth(), _video->getHeight());
+ _movieBox = bounds;
+
+ if (!isSurfaceValid())
+ allocateSurface(bounds);
+
+ setStart(0, getScale());
+ TimeBase::setStop(_video->getDuration().convertToFramerate(getScale()).totalNumberOfFrames(), getScale());
+}
+
+void Movie::redrawMovieWorld() {
+ if (_video && _video->needsUpdate()) {
+ const Graphics::Surface *frame = _video->decodeNextFrame();
+
+ if (!frame)
+ return;
+
+ // Make sure we have a surface in the current pixel format
+ Graphics::Surface *convertedFrame = 0;
+
+ if (frame->format != g_system->getScreenFormat()) {
+ convertedFrame = frame->convertTo(g_system->getScreenFormat());
+ frame = convertedFrame;
+ }
+
+ // Copy to the surface using _movieBox
+ uint16 width = MIN<int>(frame->w, _movieBox.width());
+ uint16 height = MIN<int>(frame->h, _movieBox.height());
+
+ for (uint16 y = 0; y < height; y++)
+ memcpy((byte *)_surface->getBasePtr(_movieBox.left, _movieBox.top + y), (const byte *)frame->getBasePtr(0, y), width * frame->format.bytesPerPixel);
+
+ if (convertedFrame) {
+ convertedFrame->free();
+ delete convertedFrame;
+ }
+
+ triggerRedraw();
+ }
+}
+
+void Movie::draw(const Common::Rect &r) {
+ Common::Rect worldBounds = _movieBox;
+ Common::Rect elementBounds;
+ getBounds(elementBounds);
+
+ worldBounds.moveTo(elementBounds.left, elementBounds.top);
+ Common::Rect r1 = r.findIntersectingRect(worldBounds);
+
+ Common::Rect r2 = r1;
+ r2.translate(_movieBox.left - elementBounds.left, _movieBox.top - elementBounds.top);
+ drawImage(r2, r1);
+}
+
+void Movie::moveMovieBoxTo(const CoordType h, const CoordType v) {
+ _movieBox.moveTo(h, v);
+}
+
+void Movie::setStop(const TimeValue stopTime, const TimeScale scale) {
+ TimeBase::setStop(stopTime, scale);
+
+ if (_video)
+ _video->setEndTime(Audio::Timestamp(0, _stopTime, _stopScale));
+}
+
+void Movie::setVolume(uint16 volume) {
+ if (_video)
+ _video->setVolume(MIN<uint>(volume, 0xFF));
+}
+
+void Movie::setTime(const TimeValue time, const TimeScale scale) {
+ if (_video) {
+ // Don't go past the ends of the movie
+ Common::Rational timeFrac = Common::Rational(time, ((scale == 0) ? getScale() : scale));
+
+ if (timeFrac < Common::Rational(_startTime, _startScale))
+ timeFrac = Common::Rational(_startTime, _startScale);
+ else if (timeFrac >= Common::Rational(_stopTime, _stopScale))
+ return;
+
+ _video->seek(Audio::Timestamp(0, timeFrac.getNumerator(), timeFrac.getDenominator()));
+ _time = timeFrac;
+ _lastMillis = 0;
+ }
+}
+
+void Movie::setRate(const Common::Rational rate) {
+ if (rate != 1 && rate != 0) {
+ warning("Cannot set movie rate");
+ start();
+ return;
+ }
+
+ TimeBase::setRate(rate);
+}
+
+void Movie::start() {
+ if (_video)
+ _video->start();
+
+ TimeBase::start();
+}
+
+void Movie::stop() {
+ if (_video)
+ _video->stop();
+
+ TimeBase::stop();
+}
+
+void Movie::resume() {
+ if (_paused) {
+ if (_video)
+ _video->pauseVideo(false);
+
+ _paused = false;
+ }
+}
+
+void Movie::pause() {
+ if (isRunning() && !_paused) {
+ if (_video)
+ _video->pauseVideo(true);
+
+ _paused = true;
+ _pauseStart = g_system->getMillis();
+ }
+}
+
+TimeValue Movie::getDuration(const TimeScale scale) const {
+ // Unlike TimeBase::getDuration(), this returns the whole duration of the movie
+ // The original source has a TODO to make this behave like TimeBase::getDuration(),
+ // but the problem is that too much code requires this function to behave this way...
+
+ if (_video)
+ return _video->getDuration().convertToFramerate(((scale == 0) ? getScale() : scale)).totalNumberOfFrames();
+
+ return 0;
+}
+
+void Movie::updateTime() {
+ // The reason why we overrode TimeBase's updateTime():
+ // Again, avoiding timers and handling it here
+ if (_video && _video->isPlaying() && !_video->isPaused()) {
+ redrawMovieWorld();
+
+ uint32 startTime = _startTime * getScale() / _startScale;
+ uint32 stopTime = _stopTime * getScale() / _stopScale;
+ uint32 actualTime = CLIP<int>(_video->getTime() * getScale() / 1000, startTime, stopTime);
+
+ // HACK: Due to the inaccuracy of the time, we won't actually allow us to hit
+ // the stop time unless we've actually reached the end of the segment.
+ if (actualTime == stopTime && !_video->endOfVideo())
+ actualTime--;
+
+ _time = Common::Rational(actualTime, getScale());
+ }
+}
+
+GlowingMovie::GlowingMovie(const DisplayElementID id) : Movie(id) {
+ _glowing = false;
+}
+
+void GlowingMovie::draw(const Common::Rect &r) {
+ // Make sure the rectangles are clipped properly, OR guarantee that _bounds will
+ // never fall off the screen.
+ if (_glowing) {
+ Common::Rect bounds;
+ getBounds(bounds);
+
+ copyToCurrentPortTransparentGlow(_movieBox, bounds);
+ } else {
+ Movie::draw(r);
+ }
+}
+
+void GlowingMovie::setBounds(const Common::Rect &r) {
+ Common::Rect bounds;
+ getBounds(bounds);
+
+ if (r != bounds) {
+ // Avoid Movie::setBounds.
+ // clone2727 asks why, but goes along with it
+ Animation::setBounds(r);
+ }
+}
+
+ScalingMovie::ScalingMovie(const DisplayElementID id) : GlowingMovie(id) {
+}
+
+void ScalingMovie::draw(const Common::Rect &) {
+ // Make sure the rectangles are clipped properly, OR guarantee that _bounds will
+ // never fall off the screen.
+
+ Common::Rect bounds;
+ getBounds(bounds);
+
+ if (_glowing)
+ scaleTransparentCopyGlow(_movieBox, bounds);
+ else
+ scaleTransparentCopy(_movieBox, bounds);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/movie.h b/engines/pegasus/movie.h
new file mode 100644
index 0000000000..9b9cc2bdbe
--- /dev/null
+++ b/engines/pegasus/movie.h
@@ -0,0 +1,105 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_MOVIE_H
+#define PEGASUS_MOVIE_H
+
+#include "common/str.h"
+
+#include "pegasus/elements.h"
+#include "pegasus/surface.h"
+
+namespace Video {
+class VideoDecoder;
+}
+
+namespace Pegasus {
+
+class Movie : public Animation, public PixelImage {
+public:
+ Movie(const DisplayElementID);
+ virtual ~Movie();
+
+ virtual void initFromMovieFile(const Common::String &fileName, bool transparent = false);
+
+ bool isMovieValid() { return _video != 0; }
+
+ virtual void releaseMovie();
+
+ virtual void draw(const Common::Rect &);
+ virtual void redrawMovieWorld();
+
+ virtual void setTime(const TimeValue, const TimeScale = 0);
+
+ virtual void setRate(const Common::Rational);
+
+ virtual void start();
+ virtual void stop();
+ virtual void resume();
+ virtual void pause();
+
+ virtual void moveMovieBoxTo(const CoordType, const CoordType);
+
+ virtual void setStop(const TimeValue, const TimeScale = 0);
+
+ virtual TimeValue getDuration(const TimeScale = 0) const;
+
+ // *** HACK ALERT
+ Video::VideoDecoder *getMovie() { return _video; }
+ void setVolume(uint16);
+
+protected:
+ void updateTime();
+
+ Video::VideoDecoder *_video;
+ Common::Rect _movieBox;
+};
+
+class GlowingMovie : public Movie {
+public:
+ GlowingMovie(DisplayElementID);
+ virtual ~GlowingMovie() {}
+
+ virtual void draw(const Common::Rect &);
+
+ void setBounds(const Common::Rect &);
+
+ void setGlowing(const bool glowing) { _glowing = glowing; }
+
+protected:
+ bool _glowing;
+};
+
+class ScalingMovie : public GlowingMovie {
+public:
+ ScalingMovie(DisplayElementID);
+ virtual ~ScalingMovie() {}
+
+ virtual void draw(const Common::Rect &);
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/caldoria/caldoria.cpp b/engines/pegasus/neighborhood/caldoria/caldoria.cpp
new file mode 100644
index 0000000000..140e6e8093
--- /dev/null
+++ b/engines/pegasus/neighborhood/caldoria/caldoria.cpp
@@ -0,0 +1,1962 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/system.h"
+#include "video/qt_decoder.h"
+
+#include "pegasus/cursor.h"
+#include "pegasus/energymonitor.h"
+#include "pegasus/gamestate.h"
+#include "pegasus/interface.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/biochips/biochipitem.h"
+#include "pegasus/neighborhood/caldoria/caldoria.h"
+#include "pegasus/neighborhood/caldoria/caldoria4dsystem.h"
+#include "pegasus/neighborhood/caldoria/caldoriabomb.h"
+#include "pegasus/neighborhood/caldoria/caldoriamessages.h"
+#include "pegasus/neighborhood/caldoria/caldoriamirror.h"
+#include "pegasus/neighborhood/tsa/fulltsa.h"
+
+namespace Pegasus {
+
+static const int16 kVidPhoneAngle = 30;
+static const int16 kReplicatorAngle = 50;
+static const int16 kDrawersAngle = -30;
+static const int16 kCaldoria53Angle = 45;
+static const int16 kCaldoria55Angle = -45;
+
+static const TimeValue kSinclairInterruptionTime1 = 2955;
+static const TimeValue kSinclairInterruptionTime2 = 6835;
+static const TimeValue kSinclairInterruptionTime3 = 9835;
+static const TimeValue kSinclairInterruptionTime4 = 12555;
+
+static const InputBits kPullbackInterruptFilter = kFilterAllInput;
+static const InputBits kRecalibrationInterruptFilter = kFilterAllInput;
+
+static const TimeValue kCaldoriaReplicatorIntroIn = 4933;
+static const TimeValue kCaldoriaReplicatorIntroOut = 6557;
+
+static const TimeValue kCaldoriaReplicatorWrongChoiceIn = 6557;
+static const TimeValue kCaldoriaReplicatorWrongChoiceOut = 8586;
+
+static const TimeValue kCaldoriaReplicatorOJChoiceIn = 8586;
+static const TimeValue kCaldoriaReplicatorOJChoiceOut = 11687;
+
+static const TimeValue kCaldoriaMessagesIntroIn = 11687;
+static const TimeValue kCaldoriaMessagesIntroOut = 13641;
+
+static const TimeValue kCaldoriaFirstMessageIn = 13641;
+static const TimeValue kCaldoriaFirstMessageOut = 14203;
+
+static const TimeValue kCaldoriaSecondMessageIn = 14203;
+static const TimeValue kCaldoriaSecondMessageOut = 14750;
+
+static const TimeValue kCaldoriaDoorCloseIn = 14750;
+static const TimeValue kCaldoriaDoorCloseOut = 15472;
+
+static const TimeValue kCaldoriaElevatorCloseIn = 15472;
+static const TimeValue kCaldoriaElevatorCloseOut = 16336;
+
+static const TimeValue kCaldoriaShowerCloseIn = 16336;
+static const TimeValue kCaldoriaShowerCloseOut = 17101;
+
+static const TimeValue kCaldoriaGTDoorCloseIn = 17101;
+static const TimeValue kCaldoriaGTDoorCloseOut = 18523;
+
+static const TimeValue kCaldoriaNobodyHomeIn = 18523;
+static const TimeValue kCaldoriaNobodyHomeOut = 21469;
+
+static const TimeValue kCaldoriaNoOtherFloorIn = 21469;
+static const TimeValue kCaldoriaNoOtherFloorOut = 28013;
+
+static const TimeValue kCaldoria4DInstructionsIn = 28013;
+static const TimeValue kCaldoria4DInstructionsOut = 29730;
+
+static const TimeValue kCaldoriaDrinkOJIn = 33910;
+static const TimeValue kCaldoriaDrinkOJOut = 35846;
+
+static const TimeValue kCaldoriaNoOtherDestinationIn = 35846;
+static const TimeValue kCaldoriaNoOtherDestinationOut = 37877;
+
+static const TimeValue kCaldoriaUhghIn = 37877;
+static const TimeValue kCaldoriaUhghOut = 38025;
+
+static const TimeValue kCaldoriaSinclairShootsOSIn = 38025;
+static const TimeValue kCaldoriaSinclairShootsOSOut = 40649;
+
+static const TimeValue kCaldoriaScreamingAfterIn = 40649;
+static const TimeValue kCaldoriaScreamingAfterOut = 47661;
+
+static const TimeValue k4FloorTime = 0;
+
+static const TimeValue k4To1Start = 40;
+static const TimeValue k4To1Stop = 7720;
+
+static const TimeValue k4To5Start = 7720;
+static const TimeValue k4To5Stop = 10280;
+
+static const TimeValue k4To2Time = 10280;
+
+static const TimeValue k4To3Time = 10320;
+
+static const TimeValue k1FloorTime = 10360;
+
+static const TimeValue k1To4Start = 10400;
+static const TimeValue k1To4Stop = 18080;
+
+static const TimeValue k1To5Start = 18080;
+static const TimeValue k1To5Stop = 28320;
+
+static const TimeValue k1To2Time = 28320;
+
+static const TimeValue k1To3Time = 28360;
+
+static const TimeValue k5FloorTime = 28400;
+
+static const TimeValue k5To1Start = 28440;
+static const TimeValue k5To1Stop = 38680;
+
+static const TimeValue k5To4Start = 38680;
+static const TimeValue k5To4Stop = 41240;
+
+static const TimeValue k5To2Time = 41240;
+
+static const TimeValue k5To3Time = 41280;
+
+// FuseFunction functions...
+
+const NotificationFlags kSinclairLoopDoneFlag = kLastNeighborhoodNotificationFlag << 1;
+
+SinclairCallBack::SinclairCallBack(Caldoria *caldoria) {
+ _caldoria = caldoria;
+}
+
+void SinclairCallBack::callBack() {
+ _caldoria->checkInterruptSinclair();
+}
+
+Caldoria::Caldoria(InputHandler* nextHandler, PegasusEngine *owner)
+ : Neighborhood(nextHandler, owner, "Caldoria", kCaldoriaID), _sinclairInterrupt(this) {
+ setIsItemTaken(kKeyCard);
+ setIsItemTaken(kOrangeJuiceGlassEmpty);
+ GameState.setTakenItemID(kOrangeJuiceGlassFull, GameState.isTakenItemID(kOrangeJuiceGlassEmpty));
+ _zoomOutSpot = 0;
+ _gunSprite = 0;
+}
+
+Caldoria::~Caldoria() {
+ _sinclairInterrupt.releaseCallBack();
+}
+
+void Caldoria::init() {
+ Neighborhood::init();
+
+ // We need this notification flag as well.
+ _neighborhoodNotification.notifyMe(this, kSinclairLoopDoneFlag, kSinclairLoopDoneFlag);
+
+ _sinclairInterrupt.initCallBack(&_navMovie, kCallBackAtTime);
+
+ forceStridingStop(kCaldoria55, kSouth, kAltCaldoriaSinclairDown);
+ forceStridingStop(kCaldoria50, kNorth, kAltCaldoriaSinclairDown);
+}
+
+void Caldoria::start() {
+ g_energyMonitor->stopEnergyDraining();
+
+ if (!GameState.getCaldoriaSeenPullback()) {
+ _vm->_gfx->doFadeOutSync(kOneSecond * kFifteenTicksPerSecond, kFifteenTicksPerSecond);
+
+ g_system->delayMillis(2 * 1000);
+
+ Video::VideoDecoder *pullbackMovie = new Video::QuickTimeDecoder();
+
+ if (!pullbackMovie->loadFile("Images/Caldoria/Pullback.movie"))
+ error("Could not load pullback movie");
+
+ // Draw the first frame so we can fade to it
+ 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);
+
+ bool saveAllowed = _vm->swapSaveAllowed(false);
+ bool openAllowed = _vm->swapLoadAllowed(false);
+
+ bool skipped = false;
+ Input input;
+
+ pullbackMovie->start();
+
+ while (!_vm->shouldQuit() && !pullbackMovie->endOfVideo()) {
+ if (pullbackMovie->needsUpdate()) {
+ frame = pullbackMovie->decodeNextFrame();
+
+ if (frame) {
+ g_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, 64, 112, frame->w, frame->h);
+ g_system->updateScreen();
+ }
+ }
+
+ InputDevice.getInput(input, kPullbackInterruptFilter);
+ if (input.anyInput() || _vm->saveRequested() || _vm->loadRequested()) {
+ skipped = true;
+ break;
+ }
+
+ g_system->delayMillis(10);
+ }
+
+ delete pullbackMovie;
+
+ if (_vm->shouldQuit())
+ return;
+
+ _vm->swapSaveAllowed(saveAllowed);
+ _vm->swapLoadAllowed(openAllowed);
+
+ ExtraTable::Entry entry;
+
+ if (!skipped) {
+ _vm->_gfx->doFadeOutSync(kThreeSeconds * kFifteenTicksPerSecond, kFifteenTicksPerSecond, false);
+ g_system->delayMillis(3 * 1000 / 2);
+ getExtraEntry(kCaldoria00WakeUp1, entry);
+ _navMovie.setTime(entry.movieStart);
+ _navMovie.redrawMovieWorld();
+ _navMovie.show();
+ _vm->refreshDisplay();
+ _vm->_gfx->doFadeInSync(kOneSecond * kFifteenTicksPerSecond, kFifteenTicksPerSecond, false);
+ } else {
+ getExtraEntry(kCaldoria00WakeUp1, entry);
+ _navMovie.setTime(entry.movieStart);
+ _navMovie.redrawMovieWorld();
+ _navMovie.show();
+ }
+
+ GameState.setCaldoriaSeenPullback(true);
+ }
+
+ Neighborhood::start();
+}
+
+void Caldoria::flushGameState() {
+ GameState.setCaldoriaFuseTimeLimit(_utilityFuse.getTimeRemaining());
+}
+
+class AIBombActiveCondition : public AICondition {
+public:
+ AIBombActiveCondition() {}
+
+ bool fireCondition();
+};
+
+// Return true if player is on 53 east and Sinclair is shot.
+bool AIBombActiveCondition::fireCondition() {
+ return GameState.getCurrentRoom() == kCaldoria53 && GameState.getCurrentDirection() == kEast &&
+ GameState.getCaldoriaSinclairShot();
+}
+
+void Caldoria::setUpAIRules() {
+ Neighborhood::setUpAIRules();
+
+ if (g_AIArea) {
+ if (GameState.allTimeZonesFinished()) {
+ AIPlayMessageAction *messageAction = new AIPlayMessageAction("Images/AI/Caldoria/X49NB1", false);
+ AILocationCondition *locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kCaldoria49, kNorth));
+ AIRule *rule = new AIRule(locCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Caldoria/X56EH1", false);
+ AIBombActiveCondition *activeCondition = new AIBombActiveCondition();
+ rule = new AIRule(activeCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+ } else {
+ AIPlayMessageAction *messageAction = new AIPlayMessageAction("Images/AI/Caldoria/XAB2", false);
+ AITimerCondition *timerCondition = new AITimerCondition(kLateWarning3TimeLimit, 1, true);
+ AILocationCondition *locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kCaldoria44, kEast));
+ AINotCondition *notCondition = new AINotCondition(locCondition);
+ AIAndCondition *andCondition = new AIAndCondition(timerCondition, notCondition);
+ AIRule *rule = new AIRule(andCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Caldoria/XAB1", false);
+ timerCondition = new AITimerCondition(kLateWarning2TimeLimit, 1, true);
+ locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kCaldoria44, kEast));
+ notCondition = new AINotCondition(locCondition);
+ andCondition = new AIAndCondition(timerCondition, notCondition);
+ rule = new AIRule(andCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Caldoria/XA44EB", false);
+ locCondition = new AILocationCondition(3);
+ locCondition->addLocation(MakeRoomView(kCaldoria01, kNorth));
+ locCondition->addLocation(MakeRoomView(kCaldoria01, kEast));
+ locCondition->addLocation(MakeRoomView(kCaldoria01, kSouth));
+ rule = new AIRule(locCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Caldoria/X42WH1", false);
+ AICondition *condition = makeLocationAndDoesntHaveItemCondition(kCaldoria44, kEast, kKeyCard);
+ rule = new AIRule(condition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ AIActivateRuleAction *ruleAction = new AIActivateRuleAction(rule);
+ locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kCaldoria42, kEast));
+ rule = new AIRule(locCondition, ruleAction);
+ g_AIArea->addAIRule(rule);
+ }
+ }
+}
+
+uint16 Caldoria::getDateResID() const {
+ return kDate2318ID;
+}
+
+TimeValue Caldoria::getViewTime(const RoomID room, const DirectionConstant direction) {
+ ExtraTable::Entry extra;
+ uint32 extraID = 0xffffffff;
+
+ switch (room) {
+ case kCaldoria00:
+ if (direction == kEast && _privateFlags.getFlag(kCaldoriaPrivate4DSystemOpenFlag))
+ extraID = k4DEnvironOpenView;
+ break;
+ case kCaldoriaDrawers:
+ if (direction == kNorth && _privateFlags.getFlag(kCaldoriaPrivateRightDrawerOpenFlag)) {
+ if (GameState.isTakenItemID(kKeyCard))
+ extraID = kRightDrawerOpenViewNoKeys;
+ else
+ extraID = kRightDrawerOpenViewWithKeys;
+ }
+ break;
+ case kCaldoria16:
+ if (direction == kSouth && GameState.getCaldoriaSeenSinclairInElevator())
+ extraID = kCaldoria16SouthViewWithElevator;
+ break;
+ case kCaldoriaReplicator:
+ if (GameState.getCaldoriaMadeOJ() && !(GameState.isTakenItemID(kOrangeJuiceGlassEmpty) || GameState.isTakenItemID(kOrangeJuiceGlassFull)))
+ extraID = kReplicatorNorthViewWithOJ;
+ break;
+ case kCaldoriaKiosk:
+ case kCaldoriaBinoculars:
+ return 0xffffffff;
+ case kCaldoria48:
+ if (direction == kNorth && GameState.getCaldoriaRoofDoorOpen())
+ extraID = kCa48NorthExplosion;
+ break;
+ }
+
+ if (extraID == 0xffffffff)
+ return Neighborhood::getViewTime(room, direction);
+
+ getExtraEntry(extraID, extra);
+ return extra.movieEnd - 1;
+}
+
+void Caldoria::startSpotOnceOnly(TimeValue startTime, TimeValue stopTime) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kCaldoria13, kEast):
+ if (!_privateFlags.getFlag(kCaldoriaPrivateSeen13CarFlag) && _vm->getRandomBit() == 0) {
+ _privateFlags.setFlag(kCaldoriaPrivateSeen13CarFlag, true);
+ Neighborhood::startSpotOnceOnly(startTime, stopTime);
+ }
+ break;
+ case MakeRoomView(kCaldoria14, kEast):
+ if (!_privateFlags.getFlag(kCaldoriaPrivateSeen14CarFlag) && _vm->getRandomBit() == 0) {
+ _privateFlags.setFlag(kCaldoriaPrivateSeen14CarFlag, true);
+ Neighborhood::startSpotOnceOnly(startTime, stopTime);
+ }
+ break;
+ case MakeRoomView(kCaldoria18, kWest):
+ if (!_privateFlags.getFlag(kCaldoriaPrivateSeen18CarFlag) && _vm->getRandomBit() == 0) {
+ _privateFlags.setFlag(kCaldoriaPrivateSeen18CarFlag, true);
+ Neighborhood::startSpotOnceOnly(startTime, stopTime);
+ }
+ break;
+ case MakeRoomView(kCaldoria23, kSouth):
+ if (!_privateFlags.getFlag(kCaldoriaPrivateSeen23CarFlag) && _vm->getRandomBit() == 0) {
+ _privateFlags.setFlag(kCaldoriaPrivateSeen23CarFlag, true);
+ Neighborhood::startSpotOnceOnly(startTime, stopTime);
+ }
+ break;
+ case MakeRoomView(kCaldoria33, kSouth):
+ if (!_privateFlags.getFlag(kCaldoriaPrivateSeen33CarFlag) && _vm->getRandomBit() == 0) {
+ _privateFlags.setFlag(kCaldoriaPrivateSeen33CarFlag, true);
+ Neighborhood::startSpotOnceOnly(startTime, stopTime);
+ }
+ break;
+ case MakeRoomView(kCaldoria36, kNorth):
+ if (!_privateFlags.getFlag(kCaldoriaPrivateSeen36CarFlag) && _vm->getRandomBit() == 0) {
+ _privateFlags.setFlag(kCaldoriaPrivateSeen36CarFlag, true);
+ Neighborhood::startSpotOnceOnly(startTime, stopTime);
+ }
+ break;
+ case MakeRoomView(kCaldoria41, kNorth):
+ if (!_privateFlags.getFlag(kCaldoriaPrivateSeen41NorthCarFlag) && _vm->getRandomBit() == 0) {
+ _privateFlags.setFlag(kCaldoriaPrivateSeen41NorthCarFlag, true);
+ Neighborhood::startSpotOnceOnly(startTime, stopTime);
+ }
+ break;
+ case MakeRoomView(kCaldoria41, kEast):
+ if (!_privateFlags.getFlag(kCaldoriaPrivateSeen41EastCarFlag) && _vm->getRandomBit() == 0) {
+ _privateFlags.setFlag(kCaldoriaPrivateSeen41EastCarFlag, true);
+ Neighborhood::startSpotOnceOnly(startTime, stopTime);
+ }
+ break;
+ case MakeRoomView(kCaldoria41, kWest):
+ if (!_privateFlags.getFlag(kCaldoriaPrivateSeen41WestCarFlag) && _vm->getRandomBit() == 0) {
+ _privateFlags.setFlag(kCaldoriaPrivateSeen41WestCarFlag, true);
+ Neighborhood::startSpotOnceOnly(startTime, stopTime);
+ }
+ break;
+ default:
+ Neighborhood::startSpotOnceOnly(startTime, stopTime);
+ break;
+ }
+}
+
+void Caldoria::findSpotEntry(const RoomID room, const DirectionConstant direction, SpotFlags flags, SpotTable::Entry &entry) {
+ Neighborhood::findSpotEntry(room, direction, flags, entry);
+
+ switch (room) {
+ case kCaldoria00:
+ if (direction == kEast && (!GameState.getCaldoriaINNAnnouncing() || GameState.getCaldoriaSeenINN()))
+ entry.clear();
+ break;
+ case kCaldoriaVidPhone:
+ if (direction == kNorth && GameState.getCaldoriaSeenMessages())
+ entry.clear();
+ break;
+ case kCaldoria44:
+ if (direction == kEast && GameState.getLastRoom() != kCaldoria42)
+ entry.clear();
+ break;
+ }
+}
+
+void Caldoria::startExitMovie(const ExitTable::Entry &exitEntry) {
+ switch (GameState.getCurrentRoom()) {
+ case kCaldoria05:
+ case kCaldoria07:
+ if (GameState.getCurrentDirection() == kWest)
+ closeCroppedMovie();
+ // fall through
+ case kCaldoria11:
+ if (GameState.getCurrentDirection() == kEast)
+ closeCroppedMovie();
+ break;
+ case kCaldoria13:
+ case kCaldoria14:
+ if (GameState.getCurrentDirection() == kNorth)
+ closeCroppedMovie();
+ break;
+ }
+
+ Neighborhood::startExitMovie(exitEntry);
+}
+
+void Caldoria::startZoomMovie(const ZoomTable::Entry &zoomEntry) {
+ switch (GameState.getCurrentRoom()) {
+ case kCaldoria12:
+ if (GameState.getCurrentDirection() == kNorth)
+ closeCroppedMovie();
+ break;
+ }
+
+ Neighborhood::startZoomMovie(zoomEntry);
+}
+
+void Caldoria::startDoorOpenMovie(const TimeValue startTime, const TimeValue stopTime) {
+ if (GameState.getCurrentRoom() == kCaldoria27 || GameState.getCurrentRoom() == kCaldoria28 || GameState.getCurrentRoom() == kCaldoria45)
+ // Must be opening elevator door.
+ closeCroppedMovie();
+
+ if (GameState.getCurrentRoom() == kCaldoria44 && GameState.getLastRoom() != kCaldoria42)
+ startExtraSequence(kArriveAtCaldoriaFromTSA, kDoorOpenCompletedFlag, false);
+ else
+ Neighborhood::startDoorOpenMovie(startTime, stopTime);
+}
+
+void Caldoria::startTurnPush(const TurnDirection turnDirection, const TimeValue newViewTime, const DirectionConstant destDirection) {
+ switch (GameState.getCurrentRoom()) {
+ case kCaldoria05:
+ case kCaldoria07:
+ if (GameState.getCurrentDirection() == kWest)
+ closeCroppedMovie();
+ break;
+ case kCaldoria11:
+ if (GameState.getCurrentDirection() == kEast)
+ closeCroppedMovie();
+ break;
+ case kCaldoria12:
+ case kCaldoria13:
+ case kCaldoria14:
+ case kCaldoria27:
+ case kCaldoria28:
+ case kCaldoria45:
+ if (GameState.getCurrentDirection() == kNorth)
+ closeCroppedMovie();
+ break;
+ case kCaldoria48:
+ if (_croppedMovie.isSurfaceValid())
+ closeCroppedMovie();
+ break;
+ }
+
+ Neighborhood::startTurnPush(turnDirection, newViewTime, destDirection);
+}
+
+void Caldoria::bumpIntoWall() {
+ requestSpotSound(kCaldoriaUhghIn, kCaldoriaUhghOut, kFilterNoInput, 0);
+ Neighborhood::bumpIntoWall();
+}
+
+void Caldoria::closeDoorOffScreen(const RoomID room, const DirectionConstant direction) {
+ switch (room) {
+ case kCaldoria08:
+ if (direction == kNorth)
+ playSpotSoundSync(kCaldoriaShowerCloseIn, kCaldoriaShowerCloseOut);
+ else
+ playSpotSoundSync(kCaldoriaDoorCloseIn, kCaldoriaDoorCloseOut);
+ break;
+ case kCaldoria09:
+ playSpotSoundSync(kCaldoriaShowerCloseIn, kCaldoriaShowerCloseOut);
+ break;
+ case kCaldoria16:
+ case kCaldoria38:
+ case kCaldoria46:
+ case kCaldoria27:
+ case kCaldoria28:
+ case kCaldoria45:
+ playSpotSoundSync(kCaldoriaElevatorCloseIn, kCaldoriaElevatorCloseOut);
+ break;
+ case kCaldoria44:
+ case kCaldoria42:
+ if (GameState.getCurrentRoom() == kCaldoria42)
+ playSpotSoundSync(kCaldoriaGTDoorCloseIn, kCaldoriaGTDoorCloseOut);
+ break;
+ default:
+ playSpotSoundSync(kCaldoriaDoorCloseIn, kCaldoriaDoorCloseOut);
+ break;
+ }
+}
+
+int16 Caldoria::getStaticCompassAngle(const RoomID room, const DirectionConstant dir) {
+ int16 result = Neighborhood::getStaticCompassAngle(room, dir);
+
+ switch (room) {
+ case kCaldoriaVidPhone:
+ result += kVidPhoneAngle;
+ break;
+ case kCaldoriaReplicator:
+ result += kReplicatorAngle;
+ break;
+ case kCaldoriaDrawers:
+ result += kDrawersAngle;
+ break;
+ case kCaldoria53:
+ result += kCaldoria53Angle;
+ break;
+ case kCaldoria55:
+ result += kCaldoria55Angle;
+ break;
+ }
+
+ return result;
+}
+
+void Caldoria::getExitCompassMove(const ExitTable::Entry &exitEntry, FaderMoveSpec &compassMove) {
+ Neighborhood::getExitCompassMove(exitEntry, compassMove);
+
+ switch (MakeRoomView(exitEntry.room, exitEntry.direction)) {
+ case MakeRoomView(kCaldoria08, kNorth):
+ case MakeRoomView(kCaldoria09, kSouth):
+ compassMove.insertFaderKnot((exitEntry.movieStart + exitEntry.movieEnd) >> 1, compassMove.getNthKnotValue(0) + 30);
+ break;
+ case MakeRoomView(kCaldoria10, kEast):
+ compassMove.insertFaderKnot(exitEntry.movieStart + 4 * kCaldoriaFrameDuration, 90);
+ compassMove.insertFaderKnot(exitEntry.movieStart + 19 * kCaldoriaFrameDuration, -90);
+ break;
+ case MakeRoomView(kCaldoria42, kWest):
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), exitEntry.movieStart, -90, exitEntry.movieEnd, 90);
+ compassMove.insertFaderKnot(exitEntry.movieStart + 3 * kCaldoriaFrameDuration, -90);
+ compassMove.insertFaderKnot(exitEntry.movieStart + 33 * kCaldoriaFrameDuration, 90);
+ break;
+ case MakeRoomView(kCaldoria54, kEast):
+ if (getCurrentAlternate() != kAltCaldoriaSinclairDown) {
+ compassMove.insertFaderKnot(exitEntry.movieStart + 16 * kCaldoriaFrameDuration, 135);
+ compassMove.insertFaderKnot(exitEntry.movieEnd, 135);
+ }
+ break;
+ case MakeRoomView(kCaldoria55, kNorth):
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), exitEntry.movieStart, 315, exitEntry.movieEnd, 270);
+ break;
+ }
+}
+
+void Caldoria::getZoomCompassMove(const ZoomTable::Entry &zoomEntry, FaderMoveSpec &compassMove) {
+ Neighborhood::getZoomCompassMove(zoomEntry, compassMove);
+
+ switch (zoomEntry.hotspot) {
+ case kCaBathroomToiletSpotID:
+ compassMove.insertFaderKnot(zoomEntry.movieStart + 4 * kCaldoriaFrameDuration, 90);
+ compassMove.insertFaderKnot(zoomEntry.movieStart + 19 * kCaldoriaFrameDuration, -90);
+ compassMove.insertFaderKnot(zoomEntry.movieEnd, -90);
+ break;
+ }
+}
+
+void Caldoria::getExtraCompassMove(const ExtraTable::Entry &entry, FaderMoveSpec &compassMove) {
+ switch (entry.extra) {
+ case kCaldoria00WakeUp1:
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), entry.movieStart, 90, entry.movieEnd, 180);
+ compassMove.insertFaderKnot(entry.movieStart + 1000, 90);
+ compassMove.insertFaderKnot(entry.movieStart + 1640, 120);
+ compassMove.insertFaderKnot(entry.movieStart + 2240, 135);
+ compassMove.insertFaderKnot(entry.movieStart + 2640, 180);
+ break;
+ case kCaldoria00WakeUp2:
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), entry.movieStart, 180, entry.movieEnd, 90);
+ compassMove.insertFaderKnot(entry.movieStart + 560, 90);
+ break;
+ case kCaldoria56BombStage1:
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), entry.movieStart, 90, entry.movieEnd, 10);
+ compassMove.insertFaderKnot(entry.movieStart + 31 * kCaldoriaFrameDuration, 60);
+ compassMove.insertFaderKnot(entry.movieStart + 49 * kCaldoriaFrameDuration, 60);
+ compassMove.insertFaderKnot(entry.movieStart + 66 * kCaldoriaFrameDuration, 10);
+ break;
+ case kCaldoria56BombStage7:
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), entry.movieStart, 10, entry.movieEnd, 90);
+ compassMove.insertFaderKnot(entry.movieStart + 131 * kCaldoriaFrameDuration, 10);
+ compassMove.insertFaderKnot(entry.movieStart + 148 * kCaldoriaFrameDuration, 60);
+ compassMove.insertFaderKnot(entry.movieStart + 165 * kCaldoriaFrameDuration, 60);
+ compassMove.insertFaderKnot(entry.movieEnd - 5 * kCaldoriaFrameDuration, 90);
+ break;
+ default:
+ Neighborhood::getExtraCompassMove(entry, compassMove);
+ break;
+ }
+}
+
+void Caldoria::loadAmbientLoops() {
+ RoomID room = GameState.getCurrentRoom();
+
+ if (room == kCaldoria00 && GameState.getCaldoriaWokenUp())
+ loadLoopSound1("Sounds/Caldoria/Apartment Music.AIFF", 0x100 / 4);
+ else if (room >= kCaldoria01 && room <= kCaldoria14)
+ loadLoopSound1("Sounds/Caldoria/Apartment Music.AIFF", 0x100 / 4);
+ else if (room == kCaldoria27 || room == kCaldoria28 || room == kCaldoria45)
+ loadLoopSound1("Sounds/Caldoria/Elevator Loop.AIFF", 0x100 / 5);
+ else if (room == kCaldoria44)
+ loadLoopSound1("Sounds/Caldoria/TSA Hum Loop.AIFF");
+ else if (room >= kCaldoria15 && room <= kCaldoria48)
+ loadLoopSound1("Sounds/Caldoria/Industrial Nuage.aiff", 2 * 0x100 / 3);
+ else if (room >= kCaldoria49 && room <= kCaldoria56)
+ loadLoopSound1("Sounds/Caldoria/A50NLB00.22K.AIFF", 0x100 / 4);
+}
+
+void Caldoria::checkContinuePoint(const RoomID room, const DirectionConstant direction) {
+ switch (MakeRoomView(room, direction)) {
+ case MakeRoomView(kCaldoria06, kSouth):
+ case MakeRoomView(kCaldoria13, kNorth):
+ case MakeRoomView(kCaldoria16, kSouth):
+ case MakeRoomView(kCaldoria38, kEast):
+ case MakeRoomView(kCaldoria38, kWest):
+ case MakeRoomView(kCaldoria40, kNorth):
+ case MakeRoomView(kCaldoria44, kEast):
+ case MakeRoomView(kCaldoria48, kNorth):
+ case MakeRoomView(kCaldoria49, kNorth):
+ makeContinuePoint();
+ break;
+ }
+}
+
+void Caldoria::spotCompleted() {
+ Neighborhood::spotCompleted();
+ if (GameState.getCurrentRoom() == kCaldoriaBinoculars)
+ startExtraSequence(kBinocularsZoomInOnShip, kExtraCompletedFlag, kFilterNoInput);
+}
+
+void Caldoria::arriveAt(const RoomID room, const DirectionConstant direction) {
+ switch (room) {
+ case kCaldoria56:
+ if (!GameState.getCaldoriaGunAimed())
+ // Fall through...
+ case kCaldoria49:
+ case kCaldoria50:
+ case kCaldoria51:
+ case kCaldoria52:
+ case kCaldoria53:
+ case kCaldoria54:
+ case kCaldoria55:
+ if (GameState.getCaldoriaSinclairShot())
+ setCurrentAlternate(kAltCaldoriaSinclairDown);
+ break;
+ }
+
+ Neighborhood::arriveAt(room, direction);
+ Input dummy;
+
+ switch (room) {
+ case kCaldoria00:
+ arriveAtCaldoria00();
+ break;
+ case kCaldoria05:
+ if (direction == kWest && GameState.getCaldoriaINNAnnouncing())
+ loopCroppedMovie("Images/Caldoria/A05 Light Loop", kCaldoriaA05LightLoopLeft, kCaldoriaA05LightLoopTop);
+ break;
+ case kCaldoria07:
+ if (direction == kWest && GameState.getCaldoriaINNAnnouncing())
+ loopCroppedMovie("Images/Caldoria/A07 Light Loop", kCaldoriaA07LightLoopLeft, kCaldoriaA07LightLoopTop);
+ break;
+ case kCaldoria09:
+ _lastExtra = 0xffffffff;
+ break;
+ case kCaldoriaToilet:
+ GameState.setScoringReadPaper(true);
+ break;
+ case kCaldoriaReplicator:
+ setCurrentActivation(kActivateReplicatorReady);
+ requestSpotSound(kCaldoriaReplicatorIntroIn, kCaldoriaReplicatorIntroOut, kFilterNoInput, 0);
+ break;
+ case kCaldoria11:
+ setCurrentAlternate(kAltCaldoriaNormal);
+ if (direction == kEast && !GameState.getCaldoriaSeenMessages())
+ loopCroppedMovie("Images/Caldoria/A11 Message Machine Loop", kCaldoria11MessageLoopLeft, kCaldoria11MessageLoopTop);
+ break;
+ case kCaldoria12:
+ if (direction == kNorth && !GameState.getCaldoriaSeenMessages())
+ loopCroppedMovie("Images/Caldoria/A12 Message Machine Loop", kCaldoria12MessageLoopLeft, kCaldoria12MessageLoopTop);
+ break;
+ case kCaldoriaDrawers:
+ setCurrentActivation(kActivateDrawersClosed);
+ break;
+ case kCaldoria13:
+ GameState.setCaldoriaINNAnnouncing(true);
+ if (direction == kNorth && !GameState.getCaldoriaSeenMessages())
+ loopCroppedMovie("Images/Caldoria/A13 Message Machine Loop", kCaldoria13MessageLoopLeft, kCaldoria13MessageLoopTop);
+ break;
+ case kCaldoria14:
+ if (direction == kNorth && !GameState.getCaldoriaSeenMessages())
+ loopCroppedMovie("Images/Caldoria/A14 Message Machine Loop", kCaldoria14MessageLoopLeft, kCaldoria14MessageLoopTop);
+ break;
+ case kCaldoria08:
+ if (direction == kWest)
+ setCurrentActivation(kActivateMirrorReady);
+ // Fall through...
+ case kCaldoria15:
+ GameState.setCaldoriaINNAnnouncing(true);
+ break;
+ case kCaldoria27:
+ case kCaldoria28:
+ case kCaldoria45:
+ if (GameState.getCurrentDirection() == kNorth)
+ openDoor();
+ break;
+ case kCaldoriaBinoculars:
+ GameState.setScoringLookThroughTelescope(true);
+ break;
+ case kCaldoriaKiosk:
+ GameState.setScoringSawCaldoriaKiosk(true);
+ startExtraSequenceSync(kCaldoriaKioskVideo, kFilterAllInput);
+ downButton(dummy);
+ break;
+ case kCaldoria44:
+ arriveAtCaldoria44();
+ break;
+ case kCaldoria49:
+ arriveAtCaldoria49();
+ break;
+ case kCaldoria53:
+ if (direction == kEast && !GameState.getCaldoriaSinclairShot())
+ zoomToSinclair();
+ break;
+ case kCaldoria50:
+ if (direction == kNorth && !GameState.getCaldoriaSinclairShot())
+ setUpSinclairLoops();
+ break;
+ case kCaldoria54:
+ if (direction == kSouth && !GameState.getCaldoriaSinclairShot())
+ setUpSinclairLoops();
+ break;
+ case kCaldoria56:
+ arriveAtCaldoria56();
+ break;
+ case kCaldoriaDeathRoom:
+ arriveAtCaldoriaDeath();
+ break;
+ }
+
+ checkSinclairShootsOS();
+ setUpRoofTop();
+}
+
+void Caldoria::doAIRecalibration() {
+ GameState.setCaldoriaDidRecalibration(true);
+
+ if (!g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Caldoria/XA01EB1", true, kRecalibrationInterruptFilter))
+ return;
+
+ g_interface->calibrateEnergyBar();
+ if (!g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Caldoria/XA01EB4", true, kRecalibrationInterruptFilter))
+ return;
+
+ g_interface->raiseInventoryDrawerSync();
+ if (!g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Caldoria/XA01EB6", true, kRecalibrationInterruptFilter)) {
+ g_interface->lowerInventoryDrawerSync();
+ return;
+ }
+
+ g_interface->lowerInventoryDrawerSync();
+ g_interface->raiseBiochipDrawerSync();
+
+ if (!g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Caldoria/XA01EB5", true, kRecalibrationInterruptFilter)) {
+ g_interface->lowerBiochipDrawerSync();
+ return;
+ }
+
+ g_interface->lowerBiochipDrawerSync();
+
+ g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Caldoria/XA01EB8", false, kRecalibrationInterruptFilter);
+}
+
+void Caldoria::arriveAtCaldoria00() {
+ if (GameState.getCurrentDirection() == kEast) {
+ if (GameState.getCaldoriaWokenUp()) {
+ if (!GameState.getCaldoriaDidRecalibration())
+ doAIRecalibration();
+ setCurrentActivation(kActivate4DClosed);
+ } else {
+ // Good morning, sleeping beauty
+ ExtraTable::Entry extra;
+ getExtraEntry(kCaldoria00WakeUp1, extra);
+
+ if (_navMovie.getTime() != extra.movieStart) {
+ _navMovie.setTime(extra.movieStart);
+ _navMovie.redrawMovieWorld();
+ }
+
+ startExtraSequenceSync(kCaldoria00WakeUp1, kFilterNoInput);
+ GameState.setCaldoriaWokenUp(true);
+ playCroppedMovieOnce("Images/Caldoria/VidPhone.movie", kCaldoriaVidPhoneLeft, kCaldoriaVidPhoneTop, kFilterAllInput);
+ startExtraSequence(kCaldoria00WakeUp2, kExtraCompletedFlag, kFilterNoInput);
+ }
+ }
+}
+
+bool Caldoria::wantsCursor() {
+ return GameState.getCaldoriaDidRecalibration();
+}
+
+void Caldoria::arriveAtCaldoria44() {
+ if (GameState.getLastNeighborhood() != kCaldoriaID) {
+ openDoor();
+ } else {
+ setCurrentActivation(kActivateReadyForCard);
+ loopExtraSequence(kCaldoriaTransporterArrowLoop, 0);
+ }
+}
+
+void Caldoria::arriveAtCaldoria49() {
+ if (GameState.getLastRoom() == kCaldoria48)
+ setCurrentAlternate(kAltCaldoriaNormal);
+
+ // Need to force the loop to play.
+ if (GameState.getCurrentDirection() == kNorth) {
+ GameState.setCaldoriaFuseTimeLimit(kSinclairShootsTimeLimit);
+ startExtraSequence(kCa49NorthVoiceAnalysis, kExtraCompletedFlag, kFilterNoInput);
+ }
+}
+
+void Caldoria::arriveAtCaldoria56() {
+ if (!GameState.getCaldoriaBombDisarmed()) {
+ _privateFlags.setFlag(kCaldoriaPrivateZoomingToBombFlag, true);
+
+ if (GameState.getCurrentDirection() == kNorth) {
+ turnRight();
+ } else if (GameState.getCurrentDirection() == kSouth) {
+ turnLeft();
+ } else if (GameState.getCurrentDirection() == kEast) {
+ _privateFlags.setFlag(kCaldoriaPrivateZoomingToBombFlag, false);
+ newInteraction(kCaldoriaBombInteractionID);
+ }
+ }
+}
+
+void Caldoria::arriveAtCaldoriaDeath() {
+ if (GameState.getLastRoom() == kCaldoria49) {
+ if (GameState.getCaldoriaSinclairShot()) {
+ die(kDeathNuclearExplosion);
+ } else {
+ playSpotSoundSync(kCaldoriaSinclairShootsOSIn, kCaldoriaSinclairShootsOSOut);
+ playSpotSoundSync(kCaldoriaScreamingAfterIn, kCaldoriaScreamingAfterOut);
+ die(kDeathSinclairShotDelegate);
+ }
+ } else {
+ die(kDeathShotBySinclair);
+ }
+}
+
+void Caldoria::setUpRoofTop() {
+ switch (GameState.getCurrentRoom()) {
+ case kCaldoria48:
+ if (GameState.getCurrentDirection() == kNorth) {
+ if (GameState.getCaldoriaRoofDoorOpen()) {
+ setCurrentAlternate(kAltCaldoriaRoofDoorBlown);
+ } else if (GameState.getCaldoriaDoorBombed()) {
+ // Long enough for AI hints...?
+ _utilityFuse.primeFuse(kCardBombCountDownTime);
+ _utilityFuse.setFunctor(new Common::Functor0Mem<void, Caldoria>(this, &Caldoria::doorBombTimerExpired));
+ _utilityFuse.lightFuse();
+
+ loopCroppedMovie("Images/Caldoria/A48 Bomb Loop", kCaldoria48CardBombLoopLeft, kCaldoria48CardBombLoopTop);
+ } else {
+ setCurrentActivation(kActivateRoofSlotEmpty);
+ }
+ }
+ break;
+ case kCaldoria56:
+ if (GameState.getCurrentDirection() == kEast && GameState.getCaldoriaGunAimed())
+ startExtraSequence(kCa53EastShootSinclair, kExtraCompletedFlag, false);
+ else
+ // Fall through...
+ case kCaldoria49:
+ case kCaldoria50:
+ case kCaldoria51:
+ case kCaldoria52:
+ case kCaldoria53:
+ case kCaldoria54:
+ case kCaldoria55:
+ if (!GameState.getCaldoriaSinclairShot()) {
+ if (GameState.getCaldoriaSawVoiceAnalysis() && !_utilityFuse.isFuseLit()) {
+ _utilityFuse.primeFuse(GameState.getCaldoriaFuseTimeLimit());
+ _utilityFuse.setFunctor(new Common::Functor0Mem<void, Caldoria>(this, &Caldoria::sinclairTimerExpired));
+ _utilityFuse.lightFuse();
+ }
+ } else {
+ setCurrentAlternate(kAltCaldoriaSinclairDown);
+ }
+ break;
+ }
+}
+
+void Caldoria::downButton(const Input &input) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kCaldoria01, kEast):
+ GameState.setCaldoriaWokenUp(true);
+ startExtraSequence(kCaldoria00SitDown, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ default:
+ Neighborhood::downButton(input);
+ break;
+ }
+}
+
+void Caldoria::turnTo(const DirectionConstant direction) {
+ Neighborhood::turnTo(direction);
+
+ switch (GameState.getCurrentRoom()) {
+ case kCaldoria00:
+ if (direction == kEast)
+ setCurrentActivation(kActivate4DClosed);
+ break;
+ case kCaldoria01:
+ if (direction == kEast) {
+ GameState.setCaldoriaWokenUp(true);
+ startExtraSequence(kCaldoria00SitDown, kExtraCompletedFlag, kFilterNoInput);
+ }
+ break;
+ case kCaldoria05:
+ if (direction == kWest && GameState.getCaldoriaINNAnnouncing())
+ loopCroppedMovie("Images/Caldoria/A05 Light Loop", kCaldoriaA05LightLoopLeft, kCaldoriaA05LightLoopTop);
+ break;
+ case kCaldoria07:
+ if (direction == kWest && GameState.getCaldoriaINNAnnouncing())
+ loopCroppedMovie("Images/Caldoria/A07 Light Loop", kCaldoriaA07LightLoopLeft, kCaldoriaA07LightLoopTop);
+ break;
+ case kCaldoria08:
+ if (direction == kWest)
+ setCurrentActivation(kActivateMirrorReady);
+ break;
+ case kCaldoria09:
+ _lastExtra = 0xffffffff;
+ break;
+ case kCaldoria11:
+ if (direction == kEast && !GameState.getCaldoriaSeenMessages())
+ loopCroppedMovie("Images/Caldoria/A11 Message Machine Loop", kCaldoria11MessageLoopLeft, kCaldoria11MessageLoopTop);
+ break;
+ case kCaldoria12:
+ if (direction == kNorth && !GameState.getCaldoriaSeenMessages())
+ loopCroppedMovie("Images/Caldoria/A12 Message Machine Loop", kCaldoria12MessageLoopLeft, kCaldoria12MessageLoopTop);
+ break;
+ case kCaldoria13:
+ if (direction == kNorth && !GameState.getCaldoriaSeenMessages())
+ loopCroppedMovie("Images/Caldoria/A13 Message Machine Loop", kCaldoria13MessageLoopLeft, kCaldoria13MessageLoopTop);
+ break;
+ case kCaldoria14:
+ if (direction == kNorth && !GameState.getCaldoriaSeenMessages())
+ loopCroppedMovie("Images/Caldoria/A14 Message Machine Loop", kCaldoria14MessageLoopLeft, kCaldoria14MessageLoopTop);
+ break;
+ case kCaldoria27:
+ case kCaldoria28:
+ case kCaldoria45:
+ if (direction == kNorth)
+ openElevatorMovie();
+ else
+ closeCroppedMovie();
+ break;
+ case kCaldoria48:
+ if (direction == kNorth && !GameState.getCaldoriaDoorBombed())
+ setCurrentActivation(kActivateRoofSlotEmpty);
+ break;
+ case kCaldoria53:
+ if (GameState.getCurrentDirection() == kEast && !GameState.getCaldoriaSinclairShot())
+ zoomToSinclair();
+ break;
+ case kCaldoria50:
+ if (direction == kNorth && !GameState.getCaldoriaSinclairShot())
+ setUpSinclairLoops();
+ break;
+ case kCaldoria54:
+ if (direction == kSouth && !GameState.getCaldoriaSinclairShot())
+ setUpSinclairLoops();
+ break;
+ case kCaldoria56:
+ if (_privateFlags.getFlag(kCaldoriaPrivateZoomingToBombFlag)) {
+ _privateFlags.setFlag(kCaldoriaPrivateZoomingToBombFlag, false);
+ newInteraction(kCaldoriaBombInteractionID);
+ } else if (GameState.getCaldoriaBombDisarmed()) {
+ _vm->playEndMessage();
+ }
+ break;
+ }
+
+ checkSinclairShootsOS();
+}
+
+void Caldoria::zoomTo(const Hotspot *zoomOutSpot) {
+ // Need to set _zoomOutSpot here because we may come through
+ // this function another way, say by pressing the down arrow,
+ // that doesn't involve the ClickInHotSpot function.
+ _zoomOutSpot = zoomOutSpot;
+
+ if (zoomOutSpot->getObjectID() == kCaldoriaDrawersOutSpotID) {
+ if (_privateFlags.getFlag(kCaloriaPrivateLeftDrawerOpenFlag)) {
+ _privateFlags.setFlag(kCaloriaPrivateLeftDrawerOpenFlag, false);
+ startExtraSequence(kLeftDrawerClose, kExtraCompletedFlag, kFilterNoInput);
+ } else if (_privateFlags.getFlag(kCaldoriaPrivateRightDrawerOpenFlag)) {
+ _privateFlags.setFlag(kCaldoriaPrivateRightDrawerOpenFlag, false);
+ if (GameState.isTakenItemID(kKeyCard))
+ startExtraSequence(kRightDrawerCloseNoKeys, kExtraCompletedFlag, false);
+ else
+ startExtraSequence(kRightDrawerCloseWithKeys, kExtraCompletedFlag, false);
+ } else {
+ Neighborhood::zoomTo(zoomOutSpot);
+ }
+ } else {
+ Neighborhood::zoomTo(zoomOutSpot);
+ }
+}
+
+void Caldoria::setUpSinclairLoops() {
+ _navMovie.stop();
+ scheduleNavCallBack(kSinclairLoopDoneFlag);
+ _sinclairLoopCount = 0;
+ _numSinclairLoops = 2;
+ _navMovie.start();
+}
+
+void Caldoria::zoomToSinclair() {
+ _utilityFuse.stopFuse();
+ _privateFlags.setFlag(kCaldoriaPrivateReadyToShootFlag, true);
+ setCurrentActivation(kActivateZoomedOnSinclair);
+
+ ExtraTable::Entry entry;
+ getExtraEntry(kCa53EastZoomToSinclair, entry);
+ _sinclairInterrupt.scheduleCallBack(kTriggerTimeFwd, entry.movieStart + kSinclairInterruptionTime1, _navMovie.getScale());
+ startExtraSequence(kCa53EastZoomToSinclair, kExtraCompletedFlag, kFilterAllInput);
+}
+
+void Caldoria::receiveNotification(Notification *notification, const NotificationFlags flags) {
+ Neighborhood::receiveNotification(notification, flags);
+
+ if ((flags & kExtraCompletedFlag) != 0) {
+ InventoryItem *item;
+ _interruptionFilter = kFilterAllInput;
+
+ switch (_lastExtra) {
+ case kCaldoria00WakeUp2:
+ makeContinuePoint();
+ // Force ArriveAt to do its thing...
+ GameState.setCurrentRoom(kNoRoomID);
+ arriveAt(kCaldoria00, kEast);
+ break;
+ case k4DEnvironOpenToINN:
+ GameState.setCaldoriaSeenINN(true);
+ GameState.setScoringSawINN(true);
+ // Fall through to k4DEnvironOpen...
+ case k4DEnvironOpen:
+ _privateFlags.setFlag(kCaldoriaPrivate4DSystemOpenFlag, true);
+ setCurrentActivation(kActivate4DOpen);
+ newInteraction(kCaldoria4DInteractionID);
+ break;
+ case kCaldoriaShowerUp:
+ GameState.setScoringTookShower(true);
+ GameState.setCaldoriaDoneHygiene(true);
+ break;
+ case kLeftDrawerClose:
+ case kRightDrawerCloseNoKeys:
+ case kRightDrawerCloseWithKeys:
+ if (_zoomOutSpot && _zoomOutSpot->getObjectID() == kCaldoriaDrawersOutSpotID) {
+ Input input;
+ clickInHotspot(input, _zoomOutSpot);
+ }
+ break;
+ case kCreateOrangeJuice:
+ setCurrentActivation(kActivateOJOnThePad);
+ requestSpotSound(kCaldoriaReplicatorOJChoiceIn, kCaldoriaReplicatorOJChoiceOut, kFilterNoInput, 0);
+ break;
+ case kCaldoria00SitDown:
+ arriveAt(kCaldoria00, kEast);
+ break;
+ case kCaldoria16ElevatorUp:
+ startExtraSequence(kCaldoria16ElevatorDown, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaldoria16ElevatorDown:
+ GameState.setCaldoriaSeenSinclairInElevator(true);
+ _privateFlags.setFlag(kCaldoriaPrivateCanOpenElevatorDoorFlag, true);
+ openDoor();
+ break;
+ case kCaldoriaFourthToGround:
+ case kCaldoriaRoofToGround:
+ arriveAt(kCaldoria28, GameState.getCurrentDirection());
+ break;
+ case kCaldoriaFourthToRoof:
+ case kCaldoriaGroundToRoof:
+ arriveAt(kCaldoria45, GameState.getCurrentDirection());
+ break;
+ case kCaldoriaGroundToFourth:
+ case kCaldoriaRoofToFourth:
+ arriveAt(kCaldoria27, GameState.getCurrentDirection());
+ break;
+ case kCaGTCardSwipe:
+ item = (InventoryItem *)_vm->getAllItems().findItemByID(kKeyCard);
+ _vm->addItemToInventory(item);
+ setCurrentActivation(kActivateReadyToTransport);
+ break;
+ case kCaGTFryTheFly:
+ case kCaGTGoToTSA:
+ _vm->jumpToNewEnvironment(kFullTSAID, kTSA00, kNorth);
+ break;
+ case kCaGTGoToTokyo:
+ playDeathExtra(kCaGTArriveAtTokyo, kDeathUncreatedInCaldoria);
+ break;
+ case kCaGTGoToBeach:
+ playDeathExtra(kCaGTArriveAtBeach, kDeathUncreatedInCaldoria);
+ break;
+ case kCa48NorthExplosion:
+ // Current biochip must be the shield if we got here.
+ _vm->getCurrentBiochip()->setItemState(kShieldNormal);
+ break;
+ case kBinocularsZoomInOnShip:
+ setCurrentActivation(kActivateFocusedOnShip);
+ break;
+ case kCa49NorthVoiceAnalysis:
+ _utilityFuse.primeFuse(kSinclairShootsTimeLimit);
+ _utilityFuse.setFunctor(new Common::Functor0Mem<void, Caldoria>(this, &Caldoria::sinclairTimerExpired));
+ _utilityFuse.lightFuse();
+ GameState.setCaldoriaSawVoiceAnalysis(true);
+ break;
+ case kCa53EastZoomToSinclair:
+ if (GameState.getCaldoriaSinclairShot()) {
+ delete _gunSprite;
+ _gunSprite = 0;
+ startExtraSequence(kCa53EastShootSinclair, kExtraCompletedFlag, false);
+ } else {
+ playDeathExtra(kCa53EastDeath2, kDeathSinclairShotDelegate);
+ }
+ break;
+ case kCa53EastShootSinclair:
+ _vm->addItemToInventory((InventoryItem *)_vm->getAllItems().findItemByID(kStunGun));
+ startExtraSequence(kCa53EastZoomOutFromSinclair, kExtraCompletedFlag, false);
+ GameState.setScoringStunnedSinclair(true);
+ break;
+ case kCa53EastZoomOutFromSinclair:
+ setCurrentAlternate(kAltCaldoriaSinclairDown);
+ updateViewFrame();
+ makeContinuePoint();
+ break;
+ }
+ } else if ((flags & kSpotSoundCompletedFlag) != 0) {
+ switch (GameState.getCurrentRoom()) {
+ case kCaldoria20:
+ case kCaldoria21:
+ case kCaldoria26:
+ case kCaldoria29:
+ case kCaldoria34:
+ case kCaldoria35:
+ updateViewFrame();
+ break;
+ case kCaldoria27:
+ case kCaldoria28:
+ case kCaldoria45:
+ updateElevatorMovie();
+ break;
+ case kCaldoriaReplicator:
+ emptyOJGlass();
+ break;
+ }
+ } else if ((flags & kSinclairLoopDoneFlag) != 0) {
+ if (++_sinclairLoopCount == _numSinclairLoops) {
+ switch (GameState.getCurrentRoom()) {
+ case kCaldoria50:
+ playDeathExtra(kCa50SinclairShoots, kDeathShotBySinclair);
+ break;
+ case kCaldoria54:
+ playDeathExtra(kCa54SouthDeath, kDeathShotBySinclair);
+ break;
+ }
+ } else {
+ _navMovie.stop();
+ scheduleNavCallBack(kSinclairLoopDoneFlag);
+ _navMovie.start();
+ }
+ }
+
+ g_AIArea->checkMiddleArea();
+}
+
+InputBits Caldoria::getInputFilter() {
+ InputBits result = Neighborhood::getInputFilter();
+
+ switch (GameState.getCurrentRoom()) {
+ case kCaldoria00:
+ if (_privateFlags.getFlag(kCaldoriaPrivate4DSystemOpenFlag))
+ result &= ~kFilterAllDirections;
+ break;
+ case kCaldoriaBinoculars:
+ if (getCurrentActivation() == kActivateNotFocusedOnShip)
+ result &= ~(kFilterDownButton | kFilterDownAuto);
+ break;
+ case kCaldoria53:
+ if (_privateFlags.getFlag(kCaldoriaPrivateReadyToShootFlag) && !GameState.getCaldoriaSinclairShot())
+ result &= ~kFilterAllDirections;
+ break;
+ case kCaldoria48:
+ if (GameState.getCaldoriaDoorBombed())
+ result &= ~kFilterAllDirections;
+ }
+
+ return result;
+}
+
+void Caldoria::activateHotspots() {
+ Neighborhood::activateHotspots();
+
+ switch (GameState.getCurrentRoom()) {
+ case kCaldoriaDrawers:
+ if (getCurrentActivation() == kActivateRightOpen) {
+ if (GameState.isTakenItemID(kKeyCard)) {
+ _vm->getAllHotspots().activateOneHotspot(kCaldoriaRightDrawerNoKeysCloseSpotID);
+ _vm->getAllHotspots().deactivateOneHotspot(kCaldoriaRightDrawerWithKeysCloseSpotID);
+ } else {
+ _vm->getAllHotspots().activateOneHotspot(kCaldoriaRightDrawerWithKeysCloseSpotID);
+ _vm->getAllHotspots().deactivateOneHotspot(kCaldoriaRightDrawerNoKeysCloseSpotID);
+ }
+ }
+ case kCaldoriaReplicator:
+ if (GameState.getCaldoriaMadeOJ())
+ _vm->getAllHotspots().deactivateOneHotspot(kCaldoriaMakeOJSpotID);
+ break;
+ case kCaldoria27:
+ if (GameState.isCurrentDoorOpen()) {
+ _vm->getAllHotspots().deactivateOneHotspot(kCaldoriaFourthFloorElevator1);
+ _vm->getAllHotspots().deactivateOneHotspot(kCaldoriaFourthFloorElevator2);
+ _vm->getAllHotspots().deactivateOneHotspot(kCaldoriaFourthFloorElevator3);
+ _vm->getAllHotspots().deactivateOneHotspot(kCaldoriaFourthFloorElevator4);
+ _vm->getAllHotspots().deactivateOneHotspot(kCaldoriaFourthFloorElevator5);
+ }
+ break;
+ case kCaldoria28:
+ if (GameState.isCurrentDoorOpen()) {
+ _vm->getAllHotspots().deactivateOneHotspot(kCaldoriaGroundElevator1);
+ _vm->getAllHotspots().deactivateOneHotspot(kCaldoriaGroundElevator2);
+ _vm->getAllHotspots().deactivateOneHotspot(kCaldoriaGroundElevator3);
+ _vm->getAllHotspots().deactivateOneHotspot(kCaldoriaGroundElevator4);
+ _vm->getAllHotspots().deactivateOneHotspot(kCaldoriaGroundElevator5);
+ }
+ break;
+ case kCaldoria45:
+ if (GameState.isCurrentDoorOpen()) {
+ _vm->getAllHotspots().deactivateOneHotspot(kCaldoriaRoofElevator1);
+ _vm->getAllHotspots().deactivateOneHotspot(kCaldoriaRoofElevator2);
+ _vm->getAllHotspots().deactivateOneHotspot(kCaldoriaRoofElevator3);
+ _vm->getAllHotspots().deactivateOneHotspot(kCaldoriaRoofElevator4);
+ _vm->getAllHotspots().deactivateOneHotspot(kCaldoriaRoofElevator5);
+ }
+ break;
+ }
+}
+
+void Caldoria::clickInHotspot(const Input &input, const Hotspot *spot) {
+ switch (spot->getObjectID()) {
+ case kCa4DEnvironOpenSpotID:
+ if (!GameState.getCaldoriaINNAnnouncing() || GameState.getCaldoriaSeenINN()) {
+ startExtraSequence(k4DEnvironOpen, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ // This trick depends on the following sequences being in order in the
+ // world movie:
+ // k4DEnvironOpenToINN
+ // k4DINNInterruption
+ // k4DINNIntro
+ // k4DINNMarkJohnson
+ // k4DINNMeganLove
+ // k4DINNFadeOut
+ // k4DEnvironOpenFromINN
+ loadLoopSound1("");
+ loadLoopSound2("");
+ startExtraLongSequence(k4DEnvironOpenToINN, k4DEnvironOpenFromINN, kExtraCompletedFlag, kFilterNoInput);
+ }
+ break;
+ case kCa4DEnvironCloseSpotID:
+ ((Caldoria4DSystem *)_currentInteraction)->shutDown4DSystem();
+ break;
+ case kCaBathroomMirrorSpotID:
+ newInteraction(kCaldoriaMirrorInteractionID);
+ break;
+ case kCaShowerSpotID:
+ requestExtraSequence(kCaldoriaShowerTitle, 0, kFilterNoInput);
+ requestExtraSequence(kCaldoriaShowerButton, 0, kFilterNoInput);
+ requestExtraSequence(kCaldoriaShowerDown, 0, kFilterNoInput);
+ requestExtraSequence(kCaldoriaShowerUp, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaldoriaLeftDrawerOpenSpotID:
+ _privateFlags.setFlag(kCaloriaPrivateLeftDrawerOpenFlag, true);
+ setCurrentActivation(kActivateLeftOpen);
+ startExtraSequence(kLeftDrawerOpen, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaldoriaLeftDrawerCloseSpotID:
+ _privateFlags.setFlag(kCaloriaPrivateLeftDrawerOpenFlag, false);
+ setCurrentActivation(kActivateDrawersClosed);
+ startExtraSequence(kLeftDrawerClose, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaldoriaRightDrawerOpenSpotID:
+ _privateFlags.setFlag(kCaldoriaPrivateRightDrawerOpenFlag, true);
+ setCurrentActivation(kActivateRightOpen);
+ if (GameState.isTakenItemID(kKeyCard))
+ startExtraSequence(kRightDrawerOpenNoKeys, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kRightDrawerOpenWithKeys, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaldoriaRightDrawerWithKeysCloseSpotID:
+ _privateFlags.setFlag(kCaldoriaPrivateRightDrawerOpenFlag, false);
+ setCurrentActivation(kActivateDrawersClosed);
+ startExtraSequence(kRightDrawerCloseWithKeys, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaldoriaRightDrawerNoKeysCloseSpotID:
+ _privateFlags.setFlag(kCaldoriaPrivateRightDrawerOpenFlag, false);
+ setCurrentActivation(kActivateDrawersClosed);
+ startExtraSequence(kRightDrawerCloseNoKeys, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaldoriaMakeStickyBunsSpotID:
+ requestSpotSound(kCaldoriaReplicatorWrongChoiceIn, kCaldoriaReplicatorWrongChoiceOut, kFilterNoInput, 0);
+ break;
+ case kCaldoriaMakeOJSpotID:
+ GameState.setCaldoriaMadeOJ(true);
+ startExtraSequence(kCreateOrangeJuice, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaBedroomVidPhoneActivationSpotID:
+ newInteraction(kCaldoriaMessagesInteractionID);
+ break;
+ case kCaldoriaFourthFloorElevatorSpotID:
+ if (!GameState.getCaldoriaSeenSinclairInElevator()) {
+ startExtraSequence(kCaldoria16ElevatorUp, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ _privateFlags.setFlag(kCaldoriaPrivateCanOpenElevatorDoorFlag, true);
+ openDoor();
+ }
+ break;
+ case kCaldoriaGroundElevatorSpotID:
+ _privateFlags.setFlag(kCaldoriaPrivateCanOpenElevatorDoorFlag, true);
+ openDoor();
+ break;
+ case kCaldoriaRoofElevatorSpotID:
+ _privateFlags.setFlag(kCaldoriaPrivateCanOpenElevatorDoorFlag, true);
+ openDoor();
+ break;
+ case kCaldoriaFourthFloorElevator1:
+ case kCaldoriaFourthFloorElevator2:
+ case kCaldoriaFourthFloorElevator3:
+ case kCaldoriaFourthFloorElevator4:
+ case kCaldoriaFourthFloorElevator5:
+ // Assumes that elevator hot spots are consecutive.
+ takeElevator(4, spot->getObjectID() - kCaldoriaFourthFloorElevator1 + 1);
+ break;
+ case kCaldoriaGroundElevator1:
+ case kCaldoriaGroundElevator2:
+ case kCaldoriaGroundElevator3:
+ case kCaldoriaGroundElevator4:
+ case kCaldoriaGroundElevator5:
+ // Assumes that elevator hot spots are consecutive.
+ takeElevator(1, spot->getObjectID() - kCaldoriaGroundElevator1 + 1);
+ break;
+ case kCaldoriaRoofElevator1:
+ case kCaldoriaRoofElevator2:
+ case kCaldoriaRoofElevator3:
+ case kCaldoriaRoofElevator4:
+ case kCaldoriaRoofElevator5:
+ // Assumes that elevator hot spots are consecutive.
+ takeElevator(5, spot->getObjectID() - kCaldoriaRoofElevator1 + 1);
+ break;
+ case kCaldoriaGTTokyoSpotID:
+ startExtraSequence(kCaGTGoToTokyo, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaldoriaGTTSASpotID:
+ GameState.setScoringGoToTSA(true);
+ startExtraLongSequence(kCaGTFryTheFly, kCaGTGoToTSA, kExtraCompletedFlag, false);
+ break;
+ case kCaldoriaGTBeachSpotID:
+ startExtraSequence(kCaGTGoToBeach, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaldoriaGTOtherSpotID:
+ showExtraView(kCaGTOtherChoice);
+ playSpotSoundSync(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut);
+ showExtraView(kCaGTCardSwipe);
+ break;
+ case kCaldoriaZoomInOnShipSpotID:
+ startExtraSequence(kBinocularsZoomInOnShip, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaldoriaRoofDoorSpotID:
+ startExtraSequence(kCa48NorthRooftopClosed, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaldoria20DoorbellSpotID:
+ case kCaldoria21DoorbellSpotID:
+ case kCaldoria26DoorbellSpotID:
+ case kCaldoria29DoorbellSpotID:
+ case kCaldoria34DoorbellSpotID:
+ case kCaldoria35DoorbellSpotID:
+ clickOnDoorbell(spot->getObjectID());
+ break;
+ default:
+ Neighborhood::clickInHotspot(input, spot);
+ break;
+ }
+}
+
+void Caldoria::clickOnDoorbell(const HotSpotID doorBellSpotID) {
+ uint32 extra;
+ ExtraTable::Entry entry;
+
+ switch (doorBellSpotID) {
+ case kCaldoria20DoorbellSpotID:
+ extra = kCaldoria20Doorbell;
+ break;
+ case kCaldoria21DoorbellSpotID:
+ extra = kCaldoria21Doorbell;
+ break;
+ case kCaldoria26DoorbellSpotID:
+ extra = kCaldoria26Doorbell;
+ break;
+ case kCaldoria29DoorbellSpotID:
+ extra = kCaldoria29Doorbell;
+ break;
+ case kCaldoria34DoorbellSpotID:
+ extra = kCaldoria34Doorbell;
+ break;
+ case kCaldoria35DoorbellSpotID:
+ extra = kCaldoria35Doorbell;
+ break;
+ default:
+ error("Invalid doorbell hotspot");
+ }
+
+ getExtraEntry(extra, entry);
+ showViewFrame(entry.movieStart);
+ requestSpotSound(kCaldoriaNobodyHomeIn, kCaldoriaNobodyHomeOut, kFilterNoInput, kSpotSoundCompletedFlag);
+}
+
+CanOpenDoorReason Caldoria::canOpenDoor(DoorTable::Entry &entry) {
+ switch (GameState.getCurrentRoom()) {
+ case kCaldoria16:
+ case kCaldoria38:
+ case kCaldoria46:
+ if (GameState.getCurrentDirection() == kSouth && !_privateFlags.getFlag(kCaldoriaPrivateCanOpenElevatorDoorFlag))
+ return kCantOpenLocked;
+ break;
+ }
+
+ return Neighborhood::canOpenDoor(entry);
+}
+
+void Caldoria::doorOpened() {
+ Neighborhood::doorOpened();
+ _privateFlags.setFlag(kCaldoriaPrivateCanOpenElevatorDoorFlag, false);
+}
+
+GameInteraction *Caldoria::makeInteraction(const InteractionID interactionID) {
+ switch (interactionID) {
+ case kCaldoria4DInteractionID:
+ return new Caldoria4DSystem(this);
+ case kCaldoriaBombInteractionID:
+ return new CaldoriaBomb(this, _vm);
+ case kCaldoriaMessagesInteractionID:
+ return new CaldoriaMessages(this, kCaldoriaMessagesNotificationID, _vm);
+ case kCaldoriaMirrorInteractionID:
+ return new CaldoriaMirror(this);
+ }
+
+ return 0;
+}
+
+void Caldoria::newInteraction(const InteractionID interactionID) {
+ Neighborhood::newInteraction(interactionID);
+
+ if (!_currentInteraction) {
+ if (_privateFlags.getFlag(kCaldoriaPrivate4DSystemOpenFlag)) {
+ _privateFlags.setFlag(kCaldoriaPrivate4DSystemOpenFlag, false);
+ setCurrentActivation(kActivate4DClosed);
+ startExtraSequence(k4DEnvironClose, kExtraCompletedFlag, kFilterNoInput);
+ } else if (GameState.getCaldoriaBombDisarmed()) {
+ turnLeft();
+ }
+ }
+}
+
+// Only called when trying to pick up an item and the player can't (because
+// the inventory is too full or because the player lets go of the item before
+// dropping it into the inventory).
+Hotspot *Caldoria::getItemScreenSpot(Item *item, DisplayElement *element) {
+ HotSpotID destSpotID = kNoHotSpotID;
+
+ switch (item->getObjectID()) {
+ case kKeyCard:
+ destSpotID = kCaldoriaKeyCardSpotID;
+ break;
+ case kOrangeJuiceGlassEmpty:
+ case kOrangeJuiceGlassFull:
+ destSpotID = kCaldoriaOrangeJuiceSpotID;
+ break;
+ }
+
+ if (destSpotID == kNoHotSpotID)
+ return Neighborhood::getItemScreenSpot(item, element);
+
+ return _vm->getAllHotspots().findHotspotByID(destSpotID);
+}
+
+void Caldoria::pickedUpItem(Item *item) {
+ switch (item->getObjectID()) {
+ case kKeyCard:
+ GameState.setScoringGotKeyCard(true);
+ break;
+ case kOrangeJuiceGlassFull:
+ setCurrentActivation(kActivateReplicatorReady);
+ requestSpotSound(kCaldoriaDrinkOJIn, kCaldoriaDrinkOJOut, kFilterNoInput, kSpotSoundCompletedFlag);
+ break;
+ case kStunGun:
+ GameState.setCaldoriaGunAimed(false);
+ break;
+ }
+}
+
+void Caldoria::dropItemIntoRoom(Item *item, Hotspot *dropSpot) {
+ switch (item->getObjectID()) {
+ case kKeyCard:
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ if (dropSpot->getObjectID() == kCaldoriaGTCardDropSpotID)
+ startExtraSequence(kCaGTCardSwipe, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kOrangeJuiceGlassEmpty:
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ if (dropSpot->getObjectID() == kCaldoriaOrangeJuiceDropSpotID) {
+ GameState.setCaldoriaMadeOJ(false);
+ startExtraSequence(kDisposeOrangeJuice, kExtraCompletedFlag, kFilterNoInput);
+ }
+ break;
+ case kCardBomb:
+ GameState.setCaldoriaDoorBombed(true);
+ setCurrentActivation(kActivateHotSpotAlways);
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ // Long enough for AI hints...?
+ _utilityFuse.primeFuse(kCardBombCountDownTime);
+ _utilityFuse.setFunctor(new Common::Functor0Mem<void, Caldoria>(this, &Caldoria::doorBombTimerExpired));
+ _utilityFuse.lightFuse();
+ GameState.setCaldoriaFuseTimeLimit(kCardBombCountDownTime);
+ loopCroppedMovie("Images/Caldoria/A48 Bomb Loop", kCaldoria48CardBombLoopLeft, kCaldoria48CardBombLoopTop);
+ GameState.setScoringUsedCardBomb(true);
+ break;
+ case kStunGun:
+ GameState.setCaldoriaGunAimed(true);
+ GameState.setCaldoriaSinclairShot(true);
+ _gunSprite = item->getDragSprite(0);
+ _gunSprite->setCurrentFrameIndex(1);
+ _gunSprite->setDisplayOrder(kDragSpriteOrder);
+ _gunSprite->moveElementTo(kCaldoriaGunSpriteLeft, kCaldoriaGunSpriteTop);
+ _gunSprite->startDisplaying();
+ _gunSprite->show();
+ break;
+ default:
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ break;
+ }
+}
+
+void Caldoria::takeElevator(uint startFloor, uint endFloor) {
+ _croppedMovie.stop();
+ _croppedMovie.setSegment(0, _croppedMovie.getDuration());
+
+ switch (startFloor) {
+ case 1:
+ switch (endFloor) {
+ case 1:
+ // Do nothing.
+ break;
+ case 2:
+ _croppedMovie.setTime(k1To2Time);
+ requestSpotSound(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut, kFilterNoInput, kSpotSoundCompletedFlag);
+ break;
+ case 3:
+ _croppedMovie.setTime(k1To3Time);
+ requestSpotSound(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut, kFilterNoInput, kSpotSoundCompletedFlag);
+ break;
+ case 4:
+ _croppedMovie.setSegment(k1To4Start, k1To4Stop);
+ _croppedMovie.setTime(k1To4Start);
+ startExtraSequence(kCaldoriaGroundToFourth, kExtraCompletedFlag, false);
+ _croppedMovie.start();
+ break;
+ case 5:
+ _croppedMovie.setSegment(k1To5Start, k1To5Stop);
+ _croppedMovie.setTime(k1To5Start);
+ startExtraSequence(kCaldoriaGroundToRoof, kExtraCompletedFlag, false);
+ _croppedMovie.start();
+ break;
+ }
+ break;
+ case 4:
+ switch (endFloor) {
+ case 1:
+ _croppedMovie.setSegment(k4To1Start, k4To1Stop);
+ _croppedMovie.setTime(k4To1Start);
+ startExtraSequence(kCaldoriaFourthToGround, kExtraCompletedFlag, false);
+ _croppedMovie.start();
+ break;
+ case 2:
+ _croppedMovie.setTime(k4To2Time);
+ requestSpotSound(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut, kFilterNoInput, kSpotSoundCompletedFlag);
+ break;
+ case 3:
+ _croppedMovie.setTime(k4To3Time);
+ requestSpotSound(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut, kFilterNoInput, kSpotSoundCompletedFlag);
+ break;
+ case 4:
+ // Do nothing.
+ break;
+ case 5:
+ _croppedMovie.setSegment(k4To5Start, k4To5Stop);
+ _croppedMovie.setTime(k4To5Start);
+ startExtraSequence(kCaldoriaFourthToRoof, kExtraCompletedFlag, false);
+ _croppedMovie.start();
+ break;
+ }
+ break;
+ case 5:
+ switch (endFloor) {
+ case 1:
+ _croppedMovie.setSegment(k5To1Start, k5To1Stop);
+ _croppedMovie.setTime(k5To1Start);
+ startExtraSequence(kCaldoriaRoofToGround, kExtraCompletedFlag, false);
+ _croppedMovie.start();
+ break;
+ case 2:
+ _croppedMovie.setTime(k5To2Time);
+ requestSpotSound(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut, kFilterNoInput, kSpotSoundCompletedFlag);
+ break;
+ case 3:
+ _croppedMovie.setTime(k5To3Time);
+ requestSpotSound(kCaldoriaNoOtherDestinationIn, kCaldoriaNoOtherDestinationOut, kFilterNoInput, kSpotSoundCompletedFlag);
+ break;
+ case 4:
+ _croppedMovie.setSegment(k5To4Start, k5To4Stop);
+ _croppedMovie.setTime(k5To4Start);
+ startExtraSequence(kCaldoriaRoofToFourth, kExtraCompletedFlag, false);
+ _croppedMovie.start();
+ break;
+ case 5:
+ // Do nothing.
+ break;
+ }
+ break;
+ };
+}
+
+void Caldoria::updateElevatorMovie() {
+ TimeValue time = 0xffffffff;
+
+ if (GameState.getCurrentDirection() == kNorth) {
+ switch (GameState.getCurrentRoom()) {
+ case kCaldoria27:
+ time = k4FloorTime;
+ break;
+ case kCaldoria28:
+ time = k1FloorTime;
+ break;
+ case kCaldoria45:
+ time = k5FloorTime;
+ break;
+ }
+ }
+
+ _croppedMovie.stop();
+
+ if (time == 0xffffffff) {
+ _croppedMovie.hide();
+ } else {
+ _croppedMovie.stop();
+ _croppedMovie.setSegment(0, _croppedMovie.getDuration());
+ _croppedMovie.setTime(time);
+ _croppedMovie.redrawMovieWorld();
+ _croppedMovie.show();
+
+ // *** Why do I need this?
+ // clone2727: "don't ask me!"
+ _navMovie.redrawMovieWorld();
+ }
+}
+
+void Caldoria::openElevatorMovie() {
+ if (!_croppedMovie.isSurfaceValid())
+ openCroppedMovie("Images/Caldoria/Caldoria Elevator.movie", kCaldoriaElevatorLeft, kCaldoriaElevatorTop);
+
+ updateElevatorMovie();
+}
+
+void Caldoria::emptyOJGlass() {
+ GameState.setTakenItemID(kOrangeJuiceGlassFull, false);
+ GameState.setTakenItemID(kOrangeJuiceGlassEmpty, true);
+ _vm->removeItemFromInventory((InventoryItem *)_vm->getAllItems().findItemByID(kOrangeJuiceGlassFull));
+ _vm->addItemToInventory((InventoryItem *)_vm->getAllItems().findItemByID(kOrangeJuiceGlassEmpty));
+}
+
+void Caldoria::doorBombTimerExpired() {
+ closeCroppedMovie();
+
+ if (GameState.getShieldOn()) {
+ _vm->getCurrentBiochip()->setItemState(kShieldCardBomb);
+ setCurrentAlternate(kAltCaldoriaRoofDoorBlown);
+ startExtraSequence(kCa48NorthExplosion, kExtraCompletedFlag, kFilterNoInput);
+ GameState.setScoringShieldedCardBomb(true);
+ GameState.setCaldoriaDoorBombed(false);
+ GameState.setCaldoriaRoofDoorOpen(true);
+ } else {
+ playDeathExtra(kCa48NorthExplosionDeath, kDeathCardBomb);
+ }
+}
+
+void Caldoria::sinclairTimerExpired() {
+ _privateFlags.setFlag(kCaldoriaPrivateSinclairTimerExpiredFlag, true);
+ checkSinclairShootsOS();
+}
+
+void Caldoria::checkSinclairShootsOS() {
+ if (_privateFlags.getFlag(kCaldoriaPrivateSinclairTimerExpiredFlag))
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kCaldoria49, kNorth):
+ case MakeRoomView(kCaldoria49, kSouth):
+ case MakeRoomView(kCaldoria49, kEast):
+ case MakeRoomView(kCaldoria49, kWest):
+ case MakeRoomView(kCaldoria50, kSouth):
+ case MakeRoomView(kCaldoria50, kEast):
+ case MakeRoomView(kCaldoria50, kWest):
+ case MakeRoomView(kCaldoria51, kNorth):
+ case MakeRoomView(kCaldoria51, kSouth):
+ case MakeRoomView(kCaldoria51, kWest):
+ case MakeRoomView(kCaldoria52, kNorth):
+ case MakeRoomView(kCaldoria52, kSouth):
+ case MakeRoomView(kCaldoria52, kWest):
+ case MakeRoomView(kCaldoria53, kNorth):
+ case MakeRoomView(kCaldoria53, kSouth):
+ case MakeRoomView(kCaldoria53, kWest):
+ case MakeRoomView(kCaldoria54, kNorth):
+ case MakeRoomView(kCaldoria54, kEast):
+ case MakeRoomView(kCaldoria54, kWest):
+ playSpotSoundSync(kCaldoriaSinclairShootsOSIn, kCaldoriaSinclairShootsOSOut);
+ playSpotSoundSync(kCaldoriaScreamingAfterIn, kCaldoriaScreamingAfterOut);
+ die(kDeathSinclairShotDelegate);
+ break;
+ }
+}
+
+void Caldoria::checkInterruptSinclair() {
+ if (GameState.getCaldoriaSinclairShot()) {
+ _navMovie.stop();
+ _neighborhoodNotification.setNotificationFlags(kExtraCompletedFlag, kExtraCompletedFlag);
+ g_AIArea->unlockAI();
+ } else {
+ uint32 currentTime = _navMovie.getTime();
+
+ ExtraTable::Entry entry;
+ getExtraEntry(kCa53EastZoomToSinclair, entry);
+
+ if (currentTime < entry.movieStart + kSinclairInterruptionTime2)
+ _sinclairInterrupt.scheduleCallBack(kTriggerTimeFwd, entry.movieStart + kSinclairInterruptionTime2,
+ _navMovie.getScale());
+ else if (currentTime < entry.movieStart + kSinclairInterruptionTime3)
+ _sinclairInterrupt.scheduleCallBack(kTriggerTimeFwd, entry.movieStart + kSinclairInterruptionTime3,
+ _navMovie.getScale());
+ else if (currentTime < entry.movieStart + kSinclairInterruptionTime4)
+ _sinclairInterrupt.scheduleCallBack(kTriggerTimeFwd, entry.movieStart + kSinclairInterruptionTime4,
+ _navMovie.getScale());
+ }
+}
+
+Common::String Caldoria::getBriefingMovie() {
+ Common::String movieName = Neighborhood::getBriefingMovie();
+
+ if (movieName.empty()) {
+ if (GameState.allTimeZonesFinished())
+ return "Images/AI/Caldoria/XA02";
+
+ return "Images/AI/Caldoria/XA01";
+ }
+
+ return movieName;
+}
+
+Common::String Caldoria::getEnvScanMovie() {
+ Common::String movieName = Neighborhood::getEnvScanMovie();
+
+ if (movieName.empty()) {
+ RoomID room = GameState.getCurrentRoom();
+
+ if (room >= kCaldoria00 && room <= kCaldoria14) {
+ // Inside apartment.
+ if (GameState.getCaldoriaDoneHygiene())
+ return "Images/AI/Caldoria/XAE2";
+
+ return "Images/AI/Caldoria/XAE1";
+ } else if (room >= kCaldoria15 && room <= kCaldoria48) {
+ // Wandering the halls...
+ return "Images/AI/Caldoria/XAE3";
+ } else {
+ // Must be the roof.
+ return "Images/AI/Caldoria/XAEH2";
+ }
+ }
+
+ return movieName;
+}
+
+uint Caldoria::getNumHints() {
+ uint numHints = Neighborhood::getNumHints();
+
+ if (numHints == 0) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kCaldoria44, kEast):
+ if (!GameState.isTakenItemID(kKeyCard) && GameState.getOpenDoorRoom() == kNoRoomID)
+ numHints = 1;
+ break;
+ case MakeRoomView(kCaldoria48, kNorth):
+ if (!GameState.getCaldoriaRoofDoorOpen()) {
+ if (_croppedMovie.isRunning()) // Bomb must be looping.
+ numHints = 3;
+ else if (GameState.isTakenItemID(kCardBomb))
+ numHints = 1;
+ }
+ break;
+ case MakeRoomView(kCaldoria49, kEast):
+ case MakeRoomView(kCaldoria54, kEast):
+ numHints = 1;
+ break;
+ case MakeRoomView(kCaldoria49, kNorth):
+ numHints = 1;
+ break;
+ }
+ }
+
+ return numHints;
+}
+
+Common::String Caldoria::getHintMovie(uint hintNum) {
+ Common::String movieName = Neighborhood::getHintMovie(hintNum);
+
+ if (movieName.empty()) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kCaldoria44, kEast):
+ return "Images/AI/Caldoria/X42WH2";
+ case MakeRoomView(kCaldoria48, kNorth):
+ if (_croppedMovie.isRunning()) { // Bomb must be looping.
+ if (hintNum == 1)
+ return "Images/AI/Caldoria/X48ND1";
+ else if (hintNum == 2)
+ return "Images/AI/Caldoria/X48ND2";
+ else if (GameState.isTakenItemID(kShieldBiochip))
+ return "Images/AI/Caldoria/X48ND3";
+
+ // *** Doesn't work yet, need global movies.
+ break;
+ }
+
+ return "Images/AI/Globals/XGLOB1A";
+ case MakeRoomView(kCaldoria49, kEast):
+ case MakeRoomView(kCaldoria54, kEast):
+ return "Images/AI/Caldoria/X49E";
+ case MakeRoomView(kCaldoria49, kNorth):
+ return "Images/AI/Caldoria/X49NB2";
+ }
+ }
+
+ return movieName;
+}
+
+void Caldoria::updateCursor(const Common::Point where, const Hotspot *cursorSpot) {
+ if (cursorSpot) {
+ switch (cursorSpot->getObjectID()) {
+ case kCa4DEnvironCloseSpotID:
+ _vm->_cursor->setCurrentFrameIndex(2);
+ return;
+ case kCaldoriaKioskSpotID:
+ _vm->_cursor->setCurrentFrameIndex(3);
+ return;
+ }
+ }
+
+ Neighborhood::updateCursor(where, cursorSpot);
+}
+
+Common::String Caldoria::getNavMovieName() {
+ return "Images/Caldoria/Caldoria.movie";
+}
+
+Common::String Caldoria::getSoundSpotsName() {
+ return "Sounds/Caldoria/Caldoria Spots";
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/caldoria/caldoria.h b/engines/pegasus/neighborhood/caldoria/caldoria.h
new file mode 100644
index 0000000000..3d6a155170
--- /dev/null
+++ b/engines/pegasus/neighborhood/caldoria/caldoria.h
@@ -0,0 +1,523 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_CALDORIA_CALDORIA_H
+#define PEGASUS_NEIGHBORHOOD_CALDORIA_CALDORIA_H
+
+#include "pegasus/neighborhood/neighborhood.h"
+
+namespace Pegasus {
+
+static const TimeScale kCaldoriaMovieScale = 600;
+static const TimeScale kCaldoriaFramesPerSecond = 15;
+static const TimeScale kCaldoriaFrameDuration = 40;
+
+// Alternate IDs.
+
+static const AlternateID kAltCaldoriaNormal = 0;
+static const AlternateID kAltCaldoriaRoofDoorBlown = 2;
+static const AlternateID kAltCaldoriaSinclairDown = 3;
+
+// Room IDs.
+
+static const RoomID kCaldoria00 = 1;
+static const RoomID kCaldoria01 = 2;
+static const RoomID kCaldoria02 = 3;
+static const RoomID kCaldoria03 = 4;
+static const RoomID kCaldoria04 = 5;
+static const RoomID kCaldoria05 = 6;
+static const RoomID kCaldoria06 = 7;
+static const RoomID kCaldoria07 = 8;
+static const RoomID kCaldoria08 = 9;
+static const RoomID kCaldoria09 = 10;
+static const RoomID kCaldoria10 = 11;
+static const RoomID kCaldoriaToilet = 12;
+static const RoomID kCaldoria11 = 13;
+static const RoomID kCaldoria12 = 14;
+static const RoomID kCaldoriaVidPhone = 15;
+static const RoomID kCaldoriaReplicator = 16;
+static const RoomID kCaldoriaDrawers = 17;
+static const RoomID kCaldoria13 = 18;
+static const RoomID kCaldoria14 = 19;
+static const RoomID kCaldoria15 = 20;
+static const RoomID kCaldoria16 = 21;
+static const RoomID kCaldoria17 = 22;
+static const RoomID kCaldoria18 = 23;
+static const RoomID kCaldoria19 = 24;
+static const RoomID kCaldoria20 = 25;
+static const RoomID kCaldoria21 = 26;
+static const RoomID kCaldoria22 = 27;
+static const RoomID kCaldoria23 = 28;
+static const RoomID kCaldoria24 = 29;
+static const RoomID kCaldoria25 = 30;
+static const RoomID kCaldoria26 = 31;
+static const RoomID kCaldoria27 = 32;
+static const RoomID kCaldoria28 = 33;
+static const RoomID kCaldoria29 = 34;
+static const RoomID kCaldoria30 = 35;
+static const RoomID kCaldoria31 = 36;
+static const RoomID kCaldoria32 = 37;
+static const RoomID kCaldoria33 = 38;
+static const RoomID kCaldoria34 = 39;
+static const RoomID kCaldoria35 = 40;
+static const RoomID kCaldoria36 = 41;
+static const RoomID kCaldoria37 = 42;
+static const RoomID kCaldoria38 = 43;
+static const RoomID kCaldoria39 = 44;
+static const RoomID kCaldoria40 = 45;
+static const RoomID kCaldoria41 = 46;
+static const RoomID kCaldoriaBinoculars = 47;
+static const RoomID kCaldoria42 = 48;
+static const RoomID kCaldoriaKiosk = 49;
+static const RoomID kCaldoria44 = 50;
+static const RoomID kCaldoria45 = 51;
+static const RoomID kCaldoria46 = 52;
+static const RoomID kCaldoria47 = 53;
+static const RoomID kCaldoria48 = 54;
+static const RoomID kCaldoria49 = 55;
+static const RoomID kCaldoria50 = 56;
+static const RoomID kCaldoria51 = 57;
+static const RoomID kCaldoria52 = 58;
+static const RoomID kCaldoria53 = 59;
+static const RoomID kCaldoria54 = 60;
+static const RoomID kCaldoria55 = 61;
+static const RoomID kCaldoria56 = 62;
+static const RoomID kCaldoriaDeathRoom = 0;
+
+// Hot Spot Activation IDs.
+
+static const HotSpotActivationID kActivate4DClosed = 1;
+static const HotSpotActivationID kActivate4DOpen = 2;
+static const HotSpotActivationID kActivateMirrorReady = 3;
+static const HotSpotActivationID kActivateStylistReady = 4;
+static const HotSpotActivationID kActivateReplicatorReady = 5;
+static const HotSpotActivationID kActivateOJOnThePad = 6;
+static const HotSpotActivationID kActivateDrawersClosed = 7;
+static const HotSpotActivationID kActivateRightOpen = 8;
+static const HotSpotActivationID kActivateLeftOpen = 9;
+static const HotSpotActivationID kActivateFocusedOnShip = 10;
+static const HotSpotActivationID kActivateNotFocusedOnShip = 11;
+static const HotSpotActivationID kActivateReadyForCard = 12;
+static const HotSpotActivationID kActivateReadyToTransport = 13;
+static const HotSpotActivationID kActivateRoofSlotEmpty = 14;
+static const HotSpotActivationID kActivateZoomedOnSinclair = 15;
+
+// Hot Spot IDs.
+
+static const HotSpotID kCa4DEnvironOpenSpotID = 5000;
+static const HotSpotID kCa4DEnvironCloseSpotID = 5001;
+static const HotSpotID kCa4DVisualSpotID = 5002;
+static const HotSpotID kCa4DAudioSpotID = 5003;
+static const HotSpotID kCa4DChoice1SpotID = 5004;
+static const HotSpotID kCa4DChoice2SpotID = 5005;
+static const HotSpotID kCa4DChoice3SpotID = 5006;
+static const HotSpotID kCa4DChoice4SpotID = 5007;
+static const HotSpotID kCaBathroomMirrorSpotID = 5008;
+static const HotSpotID kCaHairStyle1SpotID = 5009;
+static const HotSpotID kCaHairStyle2SpotID = 5010;
+static const HotSpotID kCaHairStyle3SpotID = 5011;
+static const HotSpotID kCaShowerSpotID = 5012;
+static const HotSpotID kCaBathroomToiletSpotID = 5013;
+static const HotSpotID kCaldoriaVidPhoneSpotID = 5014;
+static const HotSpotID kCaldoriaReplicatorSpotID = 5015;
+static const HotSpotID kCaldoriaDrawersSpotID = 5016;
+static const HotSpotID kCaldoriaVidPhoneOutSpotID = 5017;
+static const HotSpotID kCaBedroomVidPhoneActivationSpotID = 5018;
+static const HotSpotID kCaldoriaReplicatorOutSpotID = 5019;
+static const HotSpotID kCaldoriaMakeOJSpotID = 5020;
+static const HotSpotID kCaldoriaMakeStickyBunsSpotID = 5021;
+static const HotSpotID kCaldoriaOrangeJuiceSpotID = 5022;
+static const HotSpotID kCaldoriaOrangeJuiceDropSpotID = 5023;
+static const HotSpotID kCaldoriaDrawersOutSpotID = 5024;
+static const HotSpotID kCaldoriaLeftDrawerOpenSpotID = 5025;
+static const HotSpotID kCaldoriaRightDrawerOpenSpotID = 5026;
+static const HotSpotID kCaldoriaKeyCardSpotID = 5027;
+static const HotSpotID kCaldoriaLeftDrawerCloseSpotID = 5028;
+static const HotSpotID kCaldoriaRightDrawerWithKeysCloseSpotID = 5029;
+static const HotSpotID kCaldoriaRightDrawerNoKeysCloseSpotID = 5030;
+static const HotSpotID kCaldoriaFourthFloorElevatorSpotID = 5031;
+static const HotSpotID kCaldoria20DoorbellSpotID = 5032;
+static const HotSpotID kCaldoria21DoorbellSpotID = 5033;
+static const HotSpotID kCaldoria26DoorbellSpotID = 5034;
+static const HotSpotID kCaldoriaFourthFloorElevator1 = 5035;
+static const HotSpotID kCaldoriaFourthFloorElevator2 = 5036;
+static const HotSpotID kCaldoriaFourthFloorElevator3 = 5037;
+static const HotSpotID kCaldoriaFourthFloorElevator4 = 5038;
+static const HotSpotID kCaldoriaFourthFloorElevator5 = 5039;
+static const HotSpotID kCaldoriaGroundElevator1 = 5040;
+static const HotSpotID kCaldoriaGroundElevator2 = 5041;
+static const HotSpotID kCaldoriaGroundElevator3 = 5042;
+static const HotSpotID kCaldoriaGroundElevator4 = 5043;
+static const HotSpotID kCaldoriaGroundElevator5 = 5044;
+static const HotSpotID kCaldoria29DoorbellSpotID = 5045;
+static const HotSpotID kCaldoria34DoorbellSpotID = 5046;
+static const HotSpotID kCaldoria35DoorbellSpotID = 5047;
+static const HotSpotID kCaldoriaGroundElevatorSpotID = 5048;
+static const HotSpotID kCaldoriaBinocularZoomInSpotID = 5049;
+static const HotSpotID kCaldoriaBinocularsOutSpotID = 5050;
+static const HotSpotID kCaldoriaZoomInOnShipSpotID = 5051;
+static const HotSpotID kCaldoriaKioskSpotID = 5052;
+static const HotSpotID kCaldoriaKioskOutSpotID = 5053;
+static const HotSpotID kCaldoriaKioskInfoSpotID = 5054;
+static const HotSpotID kCaldoriaGTCardDropSpotID = 5055;
+static const HotSpotID kCaldoriaGTTokyoSpotID = 5056;
+static const HotSpotID kCaldoriaGTTSASpotID = 5057;
+static const HotSpotID kCaldoriaGTBeachSpotID = 5058;
+static const HotSpotID kCaldoriaGTOtherSpotID = 5059;
+static const HotSpotID kCaldoriaRoofElevator1 = 5060;
+static const HotSpotID kCaldoriaRoofElevator2 = 5061;
+static const HotSpotID kCaldoriaRoofElevator3 = 5062;
+static const HotSpotID kCaldoriaRoofElevator4 = 5063;
+static const HotSpotID kCaldoriaRoofElevator5 = 5064;
+static const HotSpotID kCaldoriaRoofElevatorSpotID = 5065;
+static const HotSpotID kCaldoriaRoofDoorSpotID = 5066;
+static const HotSpotID kCaldoriaRoofCardDropSpotID = 5067;
+static const HotSpotID kCaldoria53EastSinclairTargetSpotID = 5068;
+
+// Extra sequence IDs.
+
+static const ExtraID kCaldoriaWakeUpView1 = 0;
+static const ExtraID kCaldoria00WakeUp1 = 1;
+static const ExtraID kCaldoria00WakeUp2 = 2;
+static const ExtraID kCaldoria00SitDown = 3;
+static const ExtraID k4DEnvironOpenToINN = 4;
+static const ExtraID k4DINNInterruption = 5;
+static const ExtraID k4DINNIntro = 6;
+static const ExtraID k4DINNMarkJohnson = 7;
+static const ExtraID k4DINNMeganLove = 8;
+static const ExtraID k4DINNFadeOut = 9;
+static const ExtraID k4DEnvironOpenFromINN = 10;
+static const ExtraID k4DEnvironOpen = 11;
+static const ExtraID k4DEnvironOpenView = 12;
+static const ExtraID k4DEnvironClose = 13;
+static const ExtraID k4DIslandLoop = 14;
+static const ExtraID k4DDesertLoop = 15;
+static const ExtraID k4DMountainLoop = 16;
+static const ExtraID k4DIsland1ToIsland0 = 17;
+static const ExtraID k4DIsland2ToIsland0 = 18;
+static const ExtraID k4DIsland0ToDesert0 = 19;
+static const ExtraID k4DIsland1ToDesert0 = 20;
+static const ExtraID k4DIsland2ToDesert0 = 21;
+static const ExtraID k4DIsland0ToMountain0 = 22;
+static const ExtraID k4DIsland1ToMountain0 = 23;
+static const ExtraID k4DIsland2ToMountain0 = 24;
+static const ExtraID k4DDesert0ToIsland0 = 25;
+static const ExtraID k4DDesert1ToIsland0 = 26;
+static const ExtraID k4DDesert2ToIsland0 = 27;
+static const ExtraID k4DDesert0ToMountain0 = 28;
+static const ExtraID k4DDesert1ToMountain0 = 29;
+static const ExtraID k4DDesert2ToMountain0 = 30;
+static const ExtraID k4DMountain0ToIsland0 = 31;
+static const ExtraID k4DMountain1ToIsland0 = 32;
+static const ExtraID k4DMountain2ToIsland0 = 33;
+static const ExtraID k4DMountain0ToDesert0 = 34;
+static const ExtraID k4DMountain1ToDesert0 = 35;
+static const ExtraID k4DMountain2ToDesert0 = 36;
+static const ExtraID kCaBathroomGreeting = 37;
+static const ExtraID kCaBathroomBodyFat = 38;
+static const ExtraID kCaBathroomStylistIntro = 39;
+static const ExtraID kCaBathroomRetrothrash = 40;
+static const ExtraID kCaBathroomRetrothrashReturn = 41;
+static const ExtraID kCaBathroomGeoWave = 42;
+static const ExtraID kCaBathroomGeoWaveReturn = 43;
+static const ExtraID kCaBathroomAgencyStandard = 44;
+static const ExtraID kCaldoriaShowerTitle = 45;
+static const ExtraID kCaldoriaShowerButton = 46;
+static const ExtraID kCaldoriaShowerDown = 47;
+static const ExtraID kCaldoriaShowerUp = 48;
+static const ExtraID kCaBedroomVidPhone = 49;
+static const ExtraID kCaBedroomMessage1 = 50;
+static const ExtraID kCaBedroomMessage2 = 51;
+static const ExtraID kCreateOrangeJuice = 52;
+static const ExtraID kDisposeOrangeJuice = 53;
+static const ExtraID kReplicatorNorthViewWithOJ = 54;
+static const ExtraID kLeftDrawerOpen = 55;
+static const ExtraID kLeftDrawerClose = 56;
+static const ExtraID kRightDrawerOpenWithKeys = 57;
+static const ExtraID kRightDrawerCloseWithKeys = 58;
+static const ExtraID kRightDrawerOpenNoKeys = 59;
+static const ExtraID kRightDrawerCloseNoKeys = 60;
+static const ExtraID kRightDrawerOpenViewWithKeys = 61;
+static const ExtraID kRightDrawerOpenViewNoKeys = 62;
+static const ExtraID kCaldoria16ElevatorUp = 63;
+static const ExtraID kCaldoria16ElevatorDown = 64;
+static const ExtraID kCaldoria16SouthViewWithElevator = 65;
+static const ExtraID kCaldoria20Doorbell = 66;
+static const ExtraID kCaldoria21Doorbell = 67;
+static const ExtraID kCaldoria26Doorbell = 68;
+static const ExtraID kCaldoriaFourthToGround = 69;
+static const ExtraID kCaldoriaRoofToFourth = 70;
+static const ExtraID kCaldoriaRoofToGround = 71;
+static const ExtraID kCaldoriaGroundToFourth = 72;
+static const ExtraID kCaldoriaGroundToRoof = 73;
+static const ExtraID kCaldoriaFourthToRoof = 74;
+static const ExtraID kCaldoria29Doorbell = 75;
+static const ExtraID kCaldoria34Doorbell = 76;
+static const ExtraID kCaldoria35Doorbell = 77;
+static const ExtraID kBinocularsZoomInOnShip = 78;
+static const ExtraID kCaldoriaKioskVideo = 79;
+static const ExtraID kCaldoriaTransporterArrowLoop = 80;
+static const ExtraID kArriveAtCaldoriaFromTSA = 81;
+static const ExtraID kCaGTOtherChoice = 82;
+static const ExtraID kCaGTCardSwipe = 83;
+static const ExtraID kCaGTSelectTSA = 84;
+static const ExtraID kCaGTFryTheFly = 85;
+static const ExtraID kCaGTGoToTSA = 86;
+static const ExtraID kCaGTSelectBeach = 87;
+static const ExtraID kCaGTGoToBeach = 88;
+static const ExtraID kCaGTArriveAtBeach = 89;
+static const ExtraID kCaGTSelectTokyo = 90;
+static const ExtraID kCaGTGoToTokyo = 91;
+static const ExtraID kCaGTArriveAtTokyo = 92;
+static const ExtraID kCa48NorthRooftopClosed = 93;
+static const ExtraID kCa48NorthExplosion = 94;
+static const ExtraID kCa48NorthExplosionDeath = 95;
+static const ExtraID kCa49NorthVoiceAnalysis = 96;
+static const ExtraID kCa50SinclairShoots = 97;
+static const ExtraID kCa53EastZoomToSinclair = 98;
+static const ExtraID kCa53EastDeath2 = 99;
+static const ExtraID kCa53EastShootSinclair = 100;
+static const ExtraID kCa53EastZoomOutFromSinclair = 101;
+static const ExtraID kCa54SouthDeath = 102;
+static const ExtraID kCaldoria56BombStage1 = 103;
+static const ExtraID kCaldoria56BombStage2 = 104;
+static const ExtraID kCaldoria56BombStage3 = 105;
+static const ExtraID kCaldoria56BombStage4 = 106;
+static const ExtraID kCaldoria56BombStage5 = 107;
+static const ExtraID kCaldoria56BombStage6 = 108;
+static const ExtraID kCaldoria56BombStage7 = 109;
+static const ExtraID kCaldoria56BombExplodes = 110;
+
+// Caldoria interactions.
+
+static const InteractionID kCaldoria4DInteractionID = 0;
+static const InteractionID kCaldoriaBombInteractionID = 1;
+static const InteractionID kCaldoriaMessagesInteractionID = 2;
+static const InteractionID kCaldoriaMirrorInteractionID = 3;
+
+// Caldoria:
+
+static const DisplayOrder kVidPhoneOrder = kMonitorLayer;
+static const DisplayOrder k4DSpritesOrder = kMonitorLayer;
+static const DisplayOrder kCaldoriaMessagesOrder = kMonitorLayer;
+static const DisplayOrder kCaldoriaElevatorOrder = kMonitorLayer;
+static const DisplayOrder kCaldoriaA05LightLoopOrder = kMonitorLayer;
+static const DisplayOrder kCaldoriaA07LightLoopOrder = kMonitorLayer;
+static const DisplayOrder kCaldoriaBombGridOrder = kMonitorLayer;
+static const DisplayOrder kCaldoriaBombTimerOrder = kCaldoriaBombGridOrder + 1;
+
+/////////////////////////////////////////////
+//
+// Caldoria
+
+static const CoordType kCaldoriaVidPhoneLeft = kNavAreaLeft + 105;
+static const CoordType kCaldoriaVidPhoneTop = kNavAreaTop + 28;
+
+static const CoordType kCaldoria4DSpritesLeft = kNavAreaLeft + 10;
+static const CoordType kCaldoria4DSpritesTop = kNavAreaTop + 142;
+
+static const CoordType kCaldoriaMessageLeft = kNavAreaLeft + 202;
+static const CoordType kCaldoriaMessageTop = kNavAreaTop + 26;
+
+static const CoordType kCaldoriaElevatorLeft = kNavAreaLeft + 407;
+static const CoordType kCaldoriaElevatorTop = kNavAreaTop + 138;
+
+static const CoordType kCaldoriaA05LightLoopLeft = kNavAreaLeft + 213;
+static const CoordType kCaldoriaA05LightLoopTop = kNavAreaTop + 215;
+
+static const CoordType kCaldoriaA07LightLoopLeft = kNavAreaLeft + 414;
+static const CoordType kCaldoriaA07LightLoopTop = kNavAreaTop + 215;
+
+static const CoordType kCaldoriaGunSpriteLeft = kNavAreaLeft + 276;
+static const CoordType kCaldoriaGunSpriteTop = kNavAreaTop + 115;
+
+static const CoordType kCaldoria11MessageLoopLeft = kNavAreaLeft + 135;
+static const CoordType kCaldoria11MessageLoopTop = kNavAreaTop + 214;
+
+static const CoordType kCaldoria12MessageLoopLeft = kNavAreaLeft + 209;
+static const CoordType kCaldoria12MessageLoopTop = kNavAreaTop + 170;
+
+static const CoordType kCaldoria13MessageLoopLeft = kNavAreaLeft + 480;
+static const CoordType kCaldoria13MessageLoopTop = kNavAreaTop + 191;
+
+static const CoordType kCaldoria14MessageLoopLeft = kNavAreaLeft + 248;
+static const CoordType kCaldoria14MessageLoopTop = kNavAreaTop + 191;
+
+static const CoordType kCaldoria48CardBombLoopLeft = kNavAreaLeft + 337;
+static const CoordType kCaldoria48CardBombLoopTop = kNavAreaTop + 205;
+
+static const CoordType kCaldoriaBombGridLeft = kNavAreaLeft + 290;
+static const CoordType kCaldoriaBombGridTop = kNavAreaTop + 58;
+
+static const CoordType kCaldoriaBombTimerLeft = kNavAreaLeft + 58;
+static const CoordType kCaldoriaBombTimerTop = kNavAreaTop + 204;
+
+// Caldoria display IDs.
+
+static const DisplayElementID kCaldoriaVidPhoneID = kNeighborhoodDisplayID;
+static const DisplayElementID kCaldoria4DSpritesID = kCaldoriaVidPhoneID + 1;
+static const DisplayElementID kCaldoriaMessagesID = kCaldoria4DSpritesID + 1;
+static const DisplayElementID kCaldoriaUtilityID = kCaldoriaMessagesID + 1;
+static const DisplayElementID kCaldoriaBombGridID = kCaldoriaUtilityID + 1;
+static const DisplayElementID kCaldoriaBombTimerID = kCaldoriaBombGridID + 1;
+
+static const TimeValue kCaldoria4DBlankChoiceIn = 29730;
+static const TimeValue kCaldoria4DBlankChoiceOut = 33910;
+
+class Caldoria;
+
+class SinclairCallBack : public TimeBaseCallBack {
+public:
+ SinclairCallBack(Caldoria *);
+ ~SinclairCallBack() {}
+
+protected:
+ virtual void callBack();
+
+ Caldoria *_caldoria;
+};
+
+class Caldoria : public Neighborhood {
+friend class SinclairCallBack;
+
+public:
+ Caldoria(InputHandler *, PegasusEngine *);
+ virtual ~Caldoria();
+
+ virtual uint16 getDateResID() const;
+
+ void pickedUpItem(Item *);
+
+ virtual GameInteraction *makeInteraction(const InteractionID);
+
+ virtual Common::String getBriefingMovie();
+ virtual Common::String getEnvScanMovie();
+ virtual uint getNumHints();
+ virtual Common::String getHintMovie(uint);
+ void loadAmbientLoops();
+ bool wantsCursor();
+ void flushGameState();
+
+ void checkContinuePoint(const RoomID, const DirectionConstant);
+
+protected:
+ enum {
+ kCaldoriaPrivate4DSystemOpenFlag,
+ kCaloriaPrivateLeftDrawerOpenFlag,
+ kCaldoriaPrivateRightDrawerOpenFlag,
+ kCaldoriaPrivateReadyToShootFlag,
+ kCaldoriaPrivateZoomingToBombFlag,
+ kCaldoriaPrivateCanOpenElevatorDoorFlag,
+ kCaldoriaPrivateSinclairTimerExpiredFlag,
+ kCaldoriaPrivateSeen13CarFlag,
+ kCaldoriaPrivateSeen14CarFlag,
+ kCaldoriaPrivateSeen18CarFlag,
+ kCaldoriaPrivateSeen23CarFlag,
+ kCaldoriaPrivateSeen33CarFlag,
+ kCaldoriaPrivateSeen36CarFlag,
+ kCaldoriaPrivateSeen41NorthCarFlag,
+ kCaldoriaPrivateSeen41EastCarFlag,
+ kCaldoriaPrivateSeen41WestCarFlag,
+ kNumCaldoriaPrivateFlags
+ };
+
+ void init();
+ void start();
+
+ void setUpRoofTop();
+
+ void setUpAIRules();
+ void doAIRecalibration();
+ TimeValue getViewTime(const RoomID, const DirectionConstant);
+ void findSpotEntry(const RoomID, const DirectionConstant, SpotFlags, SpotTable::Entry &);
+ void startSpotOnceOnly(TimeValue, TimeValue);
+ void startExitMovie(const ExitTable::Entry &);
+ void startZoomMovie(const ZoomTable::Entry &);
+ void startDoorOpenMovie(const TimeValue, const TimeValue);
+ void startTurnPush(const TurnDirection, const TimeValue, const DirectionConstant);
+ void bumpIntoWall();
+ int16 getStaticCompassAngle(const RoomID, const DirectionConstant);
+ void getExitCompassMove(const ExitTable::Entry &, FaderMoveSpec &);
+ void getZoomCompassMove(const ZoomTable::Entry &, FaderMoveSpec &);
+ void getExtraCompassMove(const ExtraTable::Entry &, FaderMoveSpec &);
+ void spotCompleted();
+ void arriveAt(const RoomID, const DirectionConstant);
+ void arriveAtCaldoria00();
+ void arriveAtCaldoriaToilet();
+ void arriveAtCaldoria44();
+ void arriveAtCaldoria49();
+ void arriveAtCaldoria56();
+ void arriveAtCaldoriaDeath();
+ void turnTo(const DirectionConstant);
+ void zoomTo(const Hotspot *);
+ void downButton(const Input &);
+ void receiveNotification(Notification *, const NotificationFlags);
+ InputBits getInputFilter();
+ void activateHotspots();
+ void clickInHotspot(const Input &, const Hotspot *);
+ void newInteraction(const InteractionID);
+
+ void clickOnDoorbell(const HotSpotID);
+
+ Hotspot *getItemScreenSpot(Item *, DisplayElement *);
+ void dropItemIntoRoom(Item *, Hotspot *);
+ void takeElevator(uint, uint);
+ void updateElevatorMovie();
+ void openElevatorMovie();
+ void emptyOJGlass();
+ void closeDoorOffScreen(const RoomID, const DirectionConstant);
+ void doorBombTimerExpired();
+ void sinclairTimerExpired();
+ void checkSinclairShootsOS();
+ void setUpSinclairLoops();
+ void zoomToSinclair();
+ void playEndMessage();
+ void checkInterruptSinclair();
+
+ CanOpenDoorReason canOpenDoor(DoorTable::Entry &);
+ void doorOpened();
+
+ void updateCursor(const Common::Point, const Hotspot *);
+
+ FlagsArray<uint16, kNumCaldoriaPrivateFlags> _privateFlags;
+
+ const Hotspot *_zoomOutSpot;
+
+ FuseFunction _utilityFuse;
+
+ long _sinclairLoopCount;
+ long _numSinclairLoops;
+
+ Sprite *_gunSprite;
+
+ SinclairCallBack _sinclairInterrupt;
+
+ Common::String getSoundSpotsName();
+ Common::String getNavMovieName();
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp b/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp
new file mode 100644
index 0000000000..0494753661
--- /dev/null
+++ b/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp
@@ -0,0 +1,370 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/pegasus.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/neighborhood/caldoria/caldoria.h"
+#include "pegasus/neighborhood/caldoria/caldoria4dsystem.h"
+
+namespace Pegasus {
+
+static const TimeValue kSwitchableSlop = 3 * kCaldoriaFrameDuration;
+// Two seconds - some slop
+static const TimeValue kSwitchableDuration = kCaldoriaMovieScale * 2 - kSwitchableSlop;
+// Twelve frames + some slop
+static const TimeValue kNonswitchableDuration = kCaldoriaFrameDuration * 12 + kSwitchableSlop;
+
+static const TimeValue kSwitchable1Start = 0;
+static const TimeValue kSwitchable1Stop = kSwitchable1Start + kSwitchableDuration;
+
+static const TimeValue kSwitchable2Start = kSwitchable1Stop + kNonswitchableDuration;
+static const TimeValue kSwitchable2Stop = kSwitchable2Start + kSwitchableDuration;
+
+static const TimeValue kSwitchable3Start = kSwitchable2Stop + kNonswitchableDuration;
+static const TimeValue kSwitchable3Stop = kSwitchable3Start + kSwitchableDuration;
+
+static const NotificationFlags kVidPhoneDoneFlag = 1;
+
+static const TimeValue kRockMusicLoopIn = 0;
+static const TimeValue kRockMusicLoopOut = 2088;
+
+static const TimeValue kOrchestralMusicLoopIn = 2088;
+static const TimeValue kOrchestralMusicLoopOut = 4985;
+
+static const TimeValue kRhythmsMusicLoopIn = 4985;
+static const TimeValue kRhythmsMusicLoopOut = 6824;
+
+static const TimeValue kAcousticMusicLoopIn = 6824;
+static const TimeValue kAcousticMusicLoopOut = 9387;
+
+enum {
+ k4DVideoMenu,
+ k4DAudioMenu,
+ k4DShuttingDown,
+
+ // These constants are the exact frame numbers of the sprite movie.
+ k4DRockChoice = 0,
+ k4DOrchestralChoice,
+ k4DRhythmsChoice,
+ k4DAcousticChoice,
+ k4DIslandChoice,
+ k4DDesertChoice,
+ k4DMountainChoice,
+
+ k4DFirstVideoChoice = k4DIslandChoice
+};
+
+static const ExtraID s_transitionExtras0[3][3] = {
+ { 0xffffffff, k4DIsland0ToDesert0, k4DIsland0ToMountain0 },
+ { k4DDesert0ToIsland0, 0xffffffff, k4DDesert0ToMountain0 },
+ { k4DMountain0ToIsland0, k4DMountain0ToDesert0, 0xffffffff }
+};
+
+static const ExtraID s_transitionExtras1[3][3] = {
+ { 0xffffffff, k4DIsland1ToDesert0, k4DIsland1ToMountain0 },
+ { k4DDesert1ToIsland0, 0xffffffff, k4DDesert1ToMountain0 },
+ { k4DMountain1ToIsland0, k4DMountain1ToDesert0, 0xffffffff }
+};
+
+static const ExtraID s_transitionExtras2[3][3] = {
+ { 0xffffffff, k4DIsland2ToDesert0, k4DIsland2ToMountain0 },
+ { k4DDesert2ToIsland0, 0xffffffff, k4DDesert2ToMountain0 },
+ { k4DMountain2ToIsland0, k4DMountain2ToDesert0, 0xffffffff }
+};
+
+static const ExtraID s_shutDownExtras[3][3] = {
+ { 0xffffffff, k4DIsland1ToIsland0, k4DIsland2ToIsland0 },
+ { k4DDesert0ToIsland0, k4DDesert1ToIsland0, k4DDesert2ToIsland0 },
+ { k4DMountain0ToIsland0, k4DMountain1ToIsland0, k4DMountain2ToIsland0 }
+};
+
+Caldoria4DSystem::Caldoria4DSystem(Neighborhood *owner) : GameInteraction(kCaldoria4DInteractionID, owner),
+ _4DSpritesMovie(kCaldoria4DSpritesID) {
+ g_AIArea->lockAIOut();
+}
+
+Caldoria4DSystem::~Caldoria4DSystem() {
+ g_AIArea->unlockAI();
+}
+
+void Caldoria4DSystem::openInteraction() {
+ _whichMenu = k4DVideoMenu;
+ _videoChoice = k4DIslandChoice;
+ _audioChoice = k4DRockChoice;
+ _clickedHotspotID = kNoHotSpotID;
+
+ _4DSpritesMovie.initFromMovieFile("Images/Caldoria/4D Sprites", true);
+ _4DSpritesMovie.moveElementTo(kCaldoria4DSpritesLeft, kCaldoria4DSpritesTop);
+ _4DSpritesMovie.setDisplayOrder(k4DSpritesOrder);
+ _4DSpritesMovie.startDisplaying();
+ _4DSpritesMovie.show();
+
+ _4DSpritesScale = _4DSpritesMovie.getScale();
+
+ _neighborhoodNotification = _owner->getNeighborhoodNotification();
+ _neighborhoodNotification->notifyMe(this, kExtraCompletedFlag, kExtraCompletedFlag);
+
+ startIdling();
+}
+
+void Caldoria4DSystem::loopExtra(const ExtraID extraID) {
+ ExtraTable::Entry extraEntry;
+
+ _owner->getExtraEntry(extraID, extraEntry);
+ _loopStart = extraEntry.movieStart;
+ _owner->loopExtraSequence(extraID);
+}
+
+void Caldoria4DSystem::useIdleTime() {
+ if (_whichMenu == k4DShuttingDown) {
+ TimeValue movieTime = _owner->getNavMovie()->getTime() - _loopStart;
+ ExtraID extraID;
+
+ if (movieTime < kSwitchable1Stop)
+ extraID = s_shutDownExtras[_videoChoice - k4DFirstVideoChoice][0];
+ else if (movieTime >= kSwitchable2Start && movieTime < kSwitchable2Stop)
+ extraID = s_shutDownExtras[_videoChoice - k4DFirstVideoChoice][1];
+ else if (movieTime >= kSwitchable3Start && movieTime < kSwitchable3Stop)
+ extraID = s_shutDownExtras[_videoChoice - k4DFirstVideoChoice][2];
+ else
+ extraID = 0xffffffff;
+
+ if (extraID != 0xffffffff) {
+ setSpritesMovie();
+ _loopStart = 0;
+ _owner->startExtraSequence(extraID, kExtraCompletedFlag, kFilterNoInput);
+ }
+ } else if (_clickedHotspotID != kNoHotSpotID) {
+ TimeValue movieTime = _owner->getNavMovie()->getTime() - _loopStart;
+ ExtraID extraID;
+
+ if (movieTime < kSwitchable1Stop) {
+ extraID = s_transitionExtras0[_videoChoice - k4DFirstVideoChoice][_clickedHotspotID - kCa4DChoice1SpotID];
+ _clickedHotspotID = kNoHotSpotID;
+ } else if (movieTime >= kSwitchable2Start && movieTime < kSwitchable2Stop) {
+ extraID = s_transitionExtras1[_videoChoice - k4DFirstVideoChoice][_clickedHotspotID - kCa4DChoice1SpotID];
+ _clickedHotspotID = kNoHotSpotID;
+ } else if (movieTime >= kSwitchable3Start && movieTime < kSwitchable3Stop) {
+ extraID = s_transitionExtras2[_videoChoice - k4DFirstVideoChoice][_clickedHotspotID - kCa4DChoice1SpotID];
+ _clickedHotspotID = kNoHotSpotID;
+ } else
+ extraID = 0xffffffff;
+
+ if (extraID != 0xffffffff) {
+ switch (extraID) {
+ case k4DDesert0ToIsland0:
+ case k4DMountain0ToIsland0:
+ case k4DDesert1ToIsland0:
+ case k4DMountain1ToIsland0:
+ case k4DDesert2ToIsland0:
+ case k4DMountain2ToIsland0:
+ _videoChoice = k4DIslandChoice;
+ break;
+ case k4DIsland0ToDesert0:
+ case k4DMountain0ToDesert0:
+ case k4DIsland1ToDesert0:
+ case k4DMountain1ToDesert0:
+ case k4DIsland2ToDesert0:
+ case k4DMountain2ToDesert0:
+ _videoChoice = k4DDesertChoice;
+ break;
+ case k4DDesert0ToMountain0:
+ case k4DIsland0ToMountain0:
+ case k4DIsland1ToMountain0:
+ case k4DDesert1ToMountain0:
+ case k4DIsland2ToMountain0:
+ case k4DDesert2ToMountain0:
+ _videoChoice = k4DMountainChoice;
+ break;
+ }
+
+ setSpritesMovie();
+ _loopStart = 0;
+ _owner->startExtraSequence(extraID, kExtraCompletedFlag, kFilterNoInput);
+ }
+ }
+}
+
+void Caldoria4DSystem::initInteraction() {
+ setSpritesMovie();
+
+ _owner->loadLoopSound1("Sounds/Caldoria/Rock.aiff");
+ loopExtra(k4DIslandLoop);
+}
+
+void Caldoria4DSystem::closeInteraction() {
+ stopIdling();
+ _neighborhoodNotification->cancelNotification(this);
+ _4DSpritesMovie.releaseMovie();
+ _owner->loadAmbientLoops();
+}
+
+void Caldoria4DSystem::setSpritesMovie() {
+ if (_whichMenu == k4DShuttingDown)
+ _4DSpritesMovie.setTime(_4DSpritesScale * k4DIslandChoice);
+ else if (_whichMenu == k4DVideoMenu)
+ _4DSpritesMovie.setTime(_4DSpritesScale * _videoChoice);
+ else if (_whichMenu == k4DAudioMenu)
+ _4DSpritesMovie.setTime(_4DSpritesScale * _audioChoice);
+
+ _4DSpritesMovie.redrawMovieWorld();
+}
+
+void Caldoria4DSystem::handleInput(const Input &input, const Hotspot *cursorSpot) {
+ if (input.downButtonAnyDown())
+ return;
+ if (input.anyDirectionInput())
+ shutDown4DSystem();
+ else
+ GameInteraction::handleInput(input, cursorSpot);
+}
+
+void Caldoria4DSystem::activateHotspots() {
+ GameInteraction::activateHotspots();
+ if (_whichMenu == k4DAudioMenu)
+ g_allHotspots.activateOneHotspot(kCa4DChoice4SpotID);
+}
+
+void Caldoria4DSystem::clickInHotspot(const Input &input, const Hotspot *spot) {
+ switch (spot->getObjectID()) {
+ case kCa4DVisualSpotID:
+ if (_whichMenu == k4DAudioMenu) {
+ _whichMenu = k4DVideoMenu;
+ setSpritesMovie();
+ }
+ break;
+ case kCa4DAudioSpotID:
+ if (_whichMenu == k4DVideoMenu) {
+ _whichMenu = k4DAudioMenu;
+ setSpritesMovie();
+ }
+ break;
+ case kCa4DChoice1SpotID:
+ if (_whichMenu == k4DVideoMenu)
+ makeIslandChoice();
+ else if (_whichMenu == k4DAudioMenu)
+ makeRockChoice();
+ break;
+ case kCa4DChoice2SpotID:
+ if (_whichMenu == k4DVideoMenu)
+ makeDesertChoice();
+ else if (_whichMenu == k4DAudioMenu)
+ makeOrchestralChoice();
+ break;
+ case kCa4DChoice3SpotID:
+ if (_whichMenu == k4DVideoMenu)
+ makeMountainChoice();
+ else if (_whichMenu == k4DAudioMenu)
+ makeRhythmsChoice();
+ break;
+ case kCa4DChoice4SpotID:
+ if (_whichMenu == k4DAudioMenu)
+ makeAcousticChoice();
+ else
+ _owner->playSpotSoundSync(kCaldoria4DBlankChoiceIn, kCaldoria4DBlankChoiceOut);
+ break;
+ default:
+ GameInteraction::clickInHotspot(input, spot);
+ }
+}
+
+void Caldoria4DSystem::receiveNotification(Notification *, const NotificationFlags) {
+ if (_whichMenu == k4DShuttingDown) {
+ _owner->requestDeleteCurrentInteraction();
+ } else {
+ uint32 extraID;
+
+ switch (_videoChoice) {
+ case k4DIslandChoice:
+ extraID = k4DIslandLoop;
+ break;
+ case k4DDesertChoice:
+ extraID = k4DDesertLoop;
+ break;
+ case k4DMountainChoice:
+ extraID = k4DMountainLoop;
+ break;
+ default:
+ extraID = 0xffffffff;
+ break;
+ }
+
+ if (extraID != 0xffffffff)
+ loopExtra(extraID);
+ }
+}
+
+void Caldoria4DSystem::makeIslandChoice() {
+ if (_videoChoice != k4DIslandChoice && _clickedHotspotID == kNoHotSpotID)
+ _clickedHotspotID = kCa4DChoice1SpotID;
+}
+
+void Caldoria4DSystem::makeDesertChoice() {
+ if (_videoChoice != k4DDesertChoice && _clickedHotspotID == kNoHotSpotID)
+ _clickedHotspotID = kCa4DChoice2SpotID;
+}
+
+void Caldoria4DSystem::makeMountainChoice() {
+ if (_videoChoice != k4DMountainChoice && _clickedHotspotID == kNoHotSpotID)
+ _clickedHotspotID = kCa4DChoice3SpotID;
+}
+
+void Caldoria4DSystem::makeRockChoice() {
+ if (_audioChoice != k4DRockChoice) {
+ _audioChoice = k4DRockChoice;
+ setSpritesMovie();
+ _owner->loadLoopSound1("Sounds/Caldoria/Rock.aiff");
+ }
+}
+
+void Caldoria4DSystem::makeOrchestralChoice() {
+ if (_audioChoice != k4DOrchestralChoice) {
+ _audioChoice = k4DOrchestralChoice;
+ setSpritesMovie();
+ _owner->loadLoopSound1("Sounds/Caldoria/Orchestral.aiff");
+ }
+}
+
+void Caldoria4DSystem::makeRhythmsChoice() {
+ if (_audioChoice != k4DRhythmsChoice) {
+ _audioChoice = k4DRhythmsChoice;
+ setSpritesMovie();
+ _owner->loadLoopSound1("Sounds/Caldoria/Rhythms.aiff");
+ }
+}
+
+void Caldoria4DSystem::makeAcousticChoice() {
+ if (_audioChoice != k4DAcousticChoice) {
+ _audioChoice = k4DAcousticChoice;
+ setSpritesMovie();
+ _owner->loadLoopSound1("Sounds/Caldoria/Acoustic.aiff");
+ }
+}
+
+void Caldoria4DSystem::shutDown4DSystem() {
+ _whichMenu = k4DShuttingDown;
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.h b/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.h
new file mode 100644
index 0000000000..1c5fa44b90
--- /dev/null
+++ b/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.h
@@ -0,0 +1,78 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_CALDORIA_CALDORIA4DSYSTEM_H
+#define PEGASUS_NEIGHBORHOOD_CALDORIA_CALDORIA4DSYSTEM_H
+
+#include "pegasus/interaction.h"
+#include "pegasus/movie.h"
+#include "pegasus/notification.h"
+#include "pegasus/timers.h"
+
+namespace Pegasus {
+
+class Neighborhood;
+
+class Caldoria4DSystem : public GameInteraction, private Idler, public NotificationReceiver {
+public:
+ Caldoria4DSystem(Neighborhood *);
+ virtual ~Caldoria4DSystem();
+
+ void shutDown4DSystem();
+
+protected:
+ void openInteraction();
+ void initInteraction();
+ void closeInteraction();
+
+ void handleInput(const Input &, const Hotspot *);
+ void activateHotspots();
+ void clickInHotspot(const Input &, const Hotspot *);
+ void receiveNotification(Notification *, const NotificationFlags);
+ void setSpritesMovie();
+ void makeIslandChoice();
+ void makeRockChoice();
+ void makeMountainChoice();
+ void makeOrchestralChoice();
+ void makeDesertChoice();
+ void makeRhythmsChoice();
+ void makeAcousticChoice();
+
+ void useIdleTime();
+ void loopExtra(const ExtraID);
+
+ Movie _4DSpritesMovie;
+ TimeScale _4DSpritesScale;
+ uint _whichMenu;
+ uint _videoChoice;
+ uint _audioChoice;
+ Notification *_neighborhoodNotification;
+ TimeValue _loopStart;
+ HotSpotID _clickedHotspotID;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/caldoria/caldoriabomb.cpp b/engines/pegasus/neighborhood/caldoria/caldoriabomb.cpp
new file mode 100644
index 0000000000..abf34d3863
--- /dev/null
+++ b/engines/pegasus/neighborhood/caldoria/caldoriabomb.cpp
@@ -0,0 +1,1442 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/gamestate.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/neighborhood/caldoria/caldoria.h"
+#include "pegasus/neighborhood/caldoria/caldoriabomb.h"
+
+namespace Pegasus {
+
+// Bomb game PICTs:
+
+static const uint16 kYellowBombPICTBaseID = 700;
+static const uint16 kRedBombPICTBaseID = 709;
+static const uint16 kTimerLeftPICTID = 718;
+static const uint16 kTimerRightPICTID = 719;
+
+static const uint32 kFlashOnTime = 20;
+static const uint32 kFlashOffTime = 10;
+
+static const uint32 kOnTime1 = kFlashOnTime;
+static const uint32 kOffTime1 = kOnTime1 + kFlashOffTime;
+static const uint32 kOnTime2 = kOffTime1 + kFlashOnTime;
+static const uint32 kOffTime2 = kOnTime2 + kFlashOffTime;
+static const uint32 kOnTime3 = kOffTime2 + kFlashOnTime;
+static const uint32 kOffTime3 = kOnTime3 + kFlashOffTime;
+static const uint32 kOnTime4 = kOffTime3 + kFlashOnTime;
+
+static const HotSpotID kVertextHotSpotBaseID = 10000;
+
+static const CoordType kVertextHotSpotWidth = 24;
+static const CoordType kVertextHotSpotHeight = 24;
+
+static const NotificationFlags kBombTimerExpiredFlag = 1;
+
+static const VertexType kBombLevelOne[] = {
+ 0, 1, 0, 1, 0, // hot vertices first.
+ 1, 1, 0, 1, 1,
+ 1, 1, 0, 1, 0,
+ 1, 1, 0, 1, 1,
+ 0, 1, 0, 1, 0,
+
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ 9, // 9 edges in this level
+
+ kEdgeOneFourth,
+ 3,
+ 1, 2, 3,
+ 0, 0,
+
+ kEdgeOneFourth,
+ 5,
+ 5, 6, 7, 8, 9,
+ 0, 0, 0, 0,
+
+ kEdgeOneFourth,
+ 4,
+ 10, 11, 12, 13,
+ 0, 0, 0,
+
+ kEdgeOneFourth,
+ 5,
+ 15, 16, 17, 18, 19,
+ 0, 0, 0, 0,
+
+ kEdgeOneFourth,
+ 3,
+ 21, 22, 23,
+ 0, 0,
+
+ kEdgeOneHalf,
+ 3,
+ 5, 10, 15,
+ 0, 0,
+
+ kEdgeOneHalf,
+ 5,
+ 1, 6, 11, 16, 21,
+ 0, 0, 0, 0,
+
+ kEdgeOneHalf,
+ 5,
+ 3, 8, 13, 18, 23,
+ 0, 0, 0, 0,
+
+ kEdgeOneHalf,
+ 3,
+ 9, 14, 19,
+ 0, 0
+};
+
+static const VertexType kBombLevelTwo[] = {
+ 0, 1, 0, 1, 0,
+ 1, 1, 1, 0, 1,
+ 0, 0, 0, 1, 0,
+ 1, 1, 1, 0, 1,
+ 0, 1, 0, 1, 0,
+
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ 15,
+
+ kEdgeOneEighth,
+ 2,
+ 5, 1,
+ 0,
+
+ kEdgeOneEighth,
+ 3,
+ 17, 13, 9,
+ 0, 0,
+
+ kEdgeOneEighth,
+ 2,
+ 23, 19,
+ 0,
+
+ kEdgeThreeEighths,
+ 2,
+ 3, 9,
+ 0,
+
+ kEdgeThreeEighths,
+ 3,
+ 7, 13, 19,
+ 0, 0,
+
+ kEdgeThreeEighths,
+ 2,
+ 15, 21,
+ 0,
+
+ kEdgeOneFourth,
+ 3,
+ 1, 2, 3,
+ 0, 0,
+
+ kEdgeOneFourth,
+ 4,
+ 6, 7, 8, 9,
+ 0, 0, 0,
+
+ kEdgeOneFourth,
+ 4,
+ 16, 17, 18, 19,
+ 0, 0, 0,
+
+ kEdgeOneFourth,
+ 3,
+ 21, 22, 23,
+ 0, 0,
+
+ kEdgeOneHalf,
+ 3,
+ 5, 10, 15,
+ 0, 0,
+
+ kEdgeOneHalf,
+ 2,
+ 1, 6,
+ 0,
+
+ kEdgeOneHalf,
+ 3,
+ 7, 12, 17,
+ 0, 0,
+
+ kEdgeOneHalf,
+ 3,
+ 9, 14, 19,
+ 0, 0,
+
+ kEdgeOneHalf,
+ 2,
+ 16, 21,
+ 0
+};
+
+static const VertexType kBombLevelThree[] = {
+ 0, 1, 0, 1, 0,
+ 1, 1, 1, 1, 1,
+ 0, 1, 1, 0, 0,
+ 1, 1, 1, 1, 1,
+ 0, 1, 0, 1, 0,
+
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ 22,
+
+ kEdgeThreeSixteenths,
+ 3,
+ 15, 12, 9,
+ 0, 0,
+
+ kEdgeFiveSixteenths,
+ 3,
+ 5, 12, 19,
+ 0, 0,
+
+ kEdgeOneEighth,
+ 2,
+ 5, 1,
+ 0,
+
+ kEdgeOneEighth,
+ 2,
+ 7, 3,
+ 0,
+
+ kEdgeOneEighth,
+ 2,
+ 15, 11,
+ 0,
+
+ kEdgeOneEighth,
+ 2,
+ 21, 17,
+ 0,
+
+ kEdgeOneEighth,
+ 2,
+ 23, 19,
+ 0,
+
+ kEdgeThreeEighths,
+ 2,
+ 1, 7,
+ 0,
+
+ kEdgeThreeEighths,
+ 2,
+ 3, 9,
+ 0,
+
+ kEdgeThreeEighths,
+ 2,
+ 5, 11,
+ 0,
+
+ kEdgeThreeEighths,
+ 2,
+ 15, 21,
+ 0,
+
+ kEdgeThreeEighths,
+ 2,
+ 17, 23,
+ 0,
+
+ kEdgeOneFourth,
+ 3,
+ 1, 2, 3,
+ 0, 0,
+
+ kEdgeOneFourth,
+ 2,
+ 5, 6,
+ 0,
+
+ kEdgeOneFourth,
+ 2,
+ 8, 9,
+ 0,
+
+ kEdgeOneFourth,
+ 2,
+ 15, 16,
+ 0,
+
+ kEdgeOneFourth,
+ 2,
+ 18, 19,
+ 0,
+
+ kEdgeOneFourth,
+ 3,
+ 21, 22, 23,
+ 0, 0,
+
+ kEdgeOneHalf,
+ 2,
+ 1, 6,
+ 0,
+
+ kEdgeOneHalf,
+ 2,
+ 3, 8,
+ 0,
+
+ kEdgeOneHalf,
+ 2,
+ 16, 21,
+ 0,
+
+ kEdgeOneHalf,
+ 2,
+ 18, 23,
+ 0
+};
+
+static const VertexType kBombLevelFour[] = {
+ 1, 1, 1, 1, 0,
+ 1, 1, 0, 1, 1,
+ 1, 0, 1, 0, 1,
+ 1, 1, 0, 1, 1,
+ 0, 1, 1, 1, 1,
+
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ 19,
+
+ kEdgeOneEighth,
+ 2,
+ 5, 1,
+ 0,
+
+ kEdgeOneEighth,
+ 3,
+ 10, 6, 2,
+ 0, 0,
+
+ kEdgeOneEighth,
+ 3,
+ 16, 12, 8,
+ 0, 0,
+
+ kEdgeOneEighth,
+ 3,
+ 22, 18, 14,
+ 0, 0,
+
+ kEdgeOneEighth,
+ 2,
+ 23, 19,
+ 0,
+
+ kEdgeThreeEighths,
+ 3,
+ 2, 8, 14,
+ 0, 0,
+
+ kEdgeThreeEighths,
+ 3,
+ 10, 16, 22,
+ 0, 0,
+
+ kEdgeOneFourth,
+ 4,
+ 0, 1, 2, 3,
+ 0, 0, 0,
+
+ kEdgeOneFourth,
+ 2,
+ 5, 6,
+ 0,
+
+ kEdgeOneFourth,
+ 2,
+ 8, 9,
+ 0,
+
+ kEdgeOneFourth,
+ 2,
+ 15, 16,
+ 0,
+
+ kEdgeOneFourth,
+ 2,
+ 18, 19,
+ 0,
+
+ kEdgeOneFourth,
+ 4,
+ 21, 22, 23, 24,
+ 0, 0, 0,
+
+ kEdgeOneHalf,
+ 4,
+ 0, 5, 10, 15,
+ 0, 0, 0,
+
+ kEdgeOneHalf,
+ 2,
+ 1, 6,
+ 0,
+
+ kEdgeOneHalf,
+ 2,
+ 3, 8,
+ 0,
+
+ kEdgeOneHalf,
+ 4,
+ 9, 14, 19, 24,
+ 0, 0, 0,
+
+ kEdgeOneHalf,
+ 2,
+ 16, 21,
+ 0,
+
+ kEdgeOneHalf,
+ 2,
+ 18, 23,
+ 0
+};
+
+static const VertexType kBombLevelFive[] = {
+ 0, 1, 0, 1, 0,
+ 1, 1, 1, 1, 1,
+ 0, 1, 1, 1, 0,
+ 1, 1, 1, 1, 1,
+ 0, 1, 0, 1, 0,
+
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ 19,
+
+ kEdgeOneEighth,
+ 2,
+ 5, 1,
+ 0,
+
+ kEdgeOneEighth,
+ 2,
+ 7, 3,
+ 0,
+
+ kEdgeOneEighth,
+ 2,
+ 13, 9,
+ 0,
+
+ kEdgeOneEighth,
+ 2,
+ 15, 11,
+ 0,
+
+ kEdgeOneEighth,
+ 2,
+ 21, 17,
+ 0,
+
+ kEdgeOneEighth,
+ 2,
+ 23, 19,
+ 0,
+
+ kEdgeThreeEighths,
+ 2,
+ 1, 7,
+ 0,
+
+ kEdgeThreeEighths,
+ 4,
+ 5, 11, 17, 23,
+ 0, 0, 0,
+
+ kEdgeThreeEighths,
+ 3,
+ 6, 12, 18,
+ 0, 0,
+
+ kEdgeThreeEighths,
+ 2,
+ 13, 19,
+ 0,
+
+ kEdgeThreeEighths,
+ 2,
+ 15, 21,
+ 0,
+
+ kEdgeOneFourth,
+ 5,
+ 5, 6, 7, 8, 9,
+ 0, 0, 0, 0,
+
+ kEdgeOneFourth,
+ 3,
+ 15, 16, 17,
+ 0, 0,
+
+ kEdgeOneFourth,
+ 2,
+ 18, 19,
+ 0,
+
+ kEdgeOneFourth,
+ 3,
+ 21, 22, 23,
+ 0, 0,
+
+ kEdgeOneHalf,
+ 3,
+ 5, 10, 15,
+ 0, 0,
+
+ kEdgeOneHalf,
+ 2,
+ 1, 6,
+ 0,
+
+ kEdgeOneHalf,
+ 3,
+ 11, 16, 21,
+ 0, 0,
+
+ kEdgeOneHalf,
+ 5,
+ 3, 8, 13, 18, 23,
+ 0, 0, 0, 0
+};
+
+static const VertexType kBombLevelSix[] = {
+ 0, 1, 1, 1, 0,
+ 1, 1, 1, 1, 1,
+ 1, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1,
+ 0, 1, 1, 1, 0,
+
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ 25,
+
+ kEdgeOneSixteenth,
+ 2,
+ 10, 1,
+ 0,
+
+ kEdgeOneSixteenth,
+ 2,
+ 23, 14,
+ 0,
+
+ kEdgeSevenSixteenths,
+ 2,
+ 3, 14,
+ 0,
+
+ kEdgeSevenSixteenths,
+ 2,
+ 10, 21,
+ 0,
+
+ kEdgeOneEighth,
+ 2,
+ 5, 1,
+ 0,
+
+ kEdgeOneEighth,
+ 3,
+ 10, 6, 2,
+ 0, 0,
+
+ kEdgeOneEighth,
+ 2,
+ 7, 3,
+ 0,
+
+ kEdgeOneEighth,
+ 2,
+ 21, 17,
+ 0,
+
+ kEdgeOneEighth,
+ 3,
+ 22, 18, 14,
+ 0, 0,
+
+ kEdgeOneEighth,
+ 2,
+ 23, 19,
+ 0,
+
+ kEdgeThreeEighths,
+ 2,
+ 1, 7,
+ 0,
+
+ kEdgeThreeEighths,
+ 3,
+ 2, 8, 14,
+ 0, 0,
+
+ kEdgeThreeEighths,
+ 2,
+ 3, 9,
+ 0,
+
+ kEdgeThreeEighths,
+ 3,
+ 10, 16, 22,
+ 0, 0,
+
+ kEdgeThreeEighths,
+ 2,
+ 15, 21,
+ 0,
+
+ kEdgeThreeEighths,
+ 2,
+ 17, 23,
+ 0,
+
+ kEdgeOneFourth,
+ 3,
+ 1, 2, 3,
+ 0, 0,
+
+ kEdgeOneFourth,
+ 3,
+ 6, 7, 8,
+ 0, 0,
+
+ kEdgeOneFourth,
+ 3,
+ 16, 17, 18,
+ 0, 0,
+
+ kEdgeOneFourth,
+ 3,
+ 21, 22, 23,
+ 0, 0,
+
+ kEdgeOneHalf,
+ 3,
+ 5, 10, 15,
+ 0, 0,
+
+ kEdgeOneHalf,
+ 3,
+ 6, 11, 16,
+ 0, 0,
+
+ kEdgeOneHalf,
+ 5,
+ 2, 7, 12, 17, 22,
+ 0, 0, 0, 0,
+
+ kEdgeOneHalf,
+ 3,
+ 8, 13, 18,
+ 0, 0,
+
+ kEdgeOneHalf,
+ 3,
+ 9, 14, 19,
+ 0, 0
+};
+
+static const CoordType kBombGridWidth = 140;
+static const CoordType kBombGridHeight = 140;
+
+static const CoordType kDotOriginX = 0;
+static const CoordType kDotOriginY = 0;
+
+static const CoordType kVertOriginX = 2;
+static const CoordType kVertOriginY = 6;
+
+static const CoordType kHorizOriginX = 6;
+static const CoordType kHorizOriginY = 2;
+
+static const CoordType kDiagOriginX = 6;
+static const CoordType kDiagOriginY = 6;
+
+static const int g_originsX[] = {
+ kDiagOriginX,
+ kDiagOriginX,
+ kDiagOriginX,
+ kHorizOriginX,
+ kDiagOriginX,
+ kDiagOriginX,
+ kDiagOriginX,
+ kVertOriginX
+};
+
+static const int g_originsY[] = {
+ kDiagOriginY - 64,
+ kDiagOriginY - 32,
+ kDiagOriginY - 32,
+ kHorizOriginY,
+ kDiagOriginY,
+ kDiagOriginY,
+ kDiagOriginY,
+ kVertOriginY
+};
+
+struct HotVerticesList {
+ int numHotVerts;
+ VertexType hotVerts[25];
+};
+
+CoordType vertToX(VertexType vertex) {
+ return (vertex % 5) * 32;
+}
+
+CoordType vertToY(VertexType vertex) {
+ return (vertex / 5) * 32;
+}
+
+// This function returns the number of edges in the bomb edge list.
+VertexType getNumEdges(BombEdgeList edges) {
+ return edges[50];
+}
+
+// These four functions return pointers into the given edge list.
+
+// getFirstEdge and getNextEdge can be used to iterate across all edges
+// in an edge list. These functions can be used to walk all the edges
+// in a bomb edge list for drawing.
+VertexType *getFirstEdge(BombEdgeList edges) {
+ return &edges[51];
+}
+
+VertexType *getNextEdge(VertexType *anEdge) {
+ return anEdge + *(anEdge + 1) * 2 + 1;
+}
+
+// getVertices returns a pointer to all of the vertices that should are
+// hot. These vertices indicate all the vertices that should be drawn in
+// the game.
+VertexType *getVertices(BombEdgeList edges) {
+ return &edges[0];
+}
+
+// getUsedVertices returns a pointer to the "used" vertices area: the
+// area that keeps track of which vertices have been set by the
+// setVertexUsed used function.
+VertexType *getUsedVertices(BombEdgeList edges) {
+ return &edges[25];
+}
+
+// Useful for saving. Saving the state of the bomb game is as simple as writing
+// out the edge list.
+int getEdgeListSize(BombEdgeList edges) {
+ VertexType numEdges = getNumEdges(edges);
+ VertexType *anEdge = getFirstEdge(edges);
+
+ while (numEdges--)
+ anEdge = getNextEdge(anEdge);
+
+ return anEdge - edges + 4;
+}
+
+// Returns true if the given vertex lies on the given edge.
+bool vertexOnEdge(VertexType *anEdge, VertexType whichVertex) {
+ VertexType numVerts = *++anEdge;
+
+ while (numVerts--)
+ if (*++anEdge == whichVertex)
+ return true;
+
+ return false;
+}
+
+// Given an edge list and a from vertex, this function constructs a list
+// of all vertices that may be clicked on.
+// if fromVertex == -1, all vertices are eligible.
+// otherwise, only vertices on a line from fromVertex are eligible.
+void makeHotVertexList(BombEdgeList edges, VertexType fromVertex, HotVerticesList &hotVertices) {
+ hotVertices.numHotVerts = 0;
+
+ if (fromVertex == -1) {
+ for (VertexType i = 0; i < 25; i++)
+ if (edges[i])
+ hotVertices.hotVerts[hotVertices.numHotVerts++] = i;
+ } else {
+ VertexType numEdges = getNumEdges(edges);
+ VertexType *anEdge = getFirstEdge(edges);
+ hotVertices.hotVerts[hotVertices.numHotVerts++] = fromVertex;
+
+ while (numEdges--) {
+ if (vertexOnEdge(anEdge, fromVertex)) {
+ VertexType *p = anEdge + 1;
+ VertexType numVerts = *p;
+
+ while (numVerts--)
+ if (*++p != fromVertex)
+ hotVertices.hotVerts[hotVertices.numHotVerts++] = *p;
+ }
+
+ anEdge = getNextEdge(anEdge);
+ }
+ }
+}
+
+// Set all edges in the edge list to the value passed in "edgeVal".
+// For drawing purposes, 0 can mean don't draw, and 1 and higher can
+// represent different colors.
+void setAllEdgesUsed(BombEdgeList edges, VertexType used) {
+ VertexType numEdges = getNumEdges(edges);
+ VertexType *anEdge = getFirstEdge(edges);
+
+ while (numEdges--) {
+ VertexType *p1 = anEdge + 1;
+ VertexType numVerts = *p1;
+ p1 += numVerts + 1;
+
+ while (--numVerts)
+ *p1++ = used;
+
+ anEdge = getNextEdge(anEdge);
+ }
+
+ VertexType *p1 = edges;
+ VertexType *p2 = getUsedVertices(edges);
+
+ for (VertexType i = 0; i < 25; i++, p1++, p2++)
+ if (*p1)
+ *p2 = used;
+}
+
+// Same as setAllEdgesUsed, but only affects edges that are already set
+// to a non-zero value.
+void setAllUsedEdgesUsed(BombEdgeList edges, VertexType used) {
+ VertexType numEdges = getNumEdges(edges);
+ VertexType *anEdge = getFirstEdge(edges);
+
+ while (numEdges--) {
+ VertexType *p = anEdge + 1;
+ VertexType numVerts = *p;
+ p += numVerts + 1;
+
+ while (--numVerts) {
+ if (*p)
+ *p = used;
+ ++p;
+ }
+
+ anEdge = getNextEdge(anEdge);
+ }
+
+ VertexType *p = getUsedVertices(edges);
+ for (VertexType i = 0; i < 25; i++, p++)
+ if (*p)
+ *p = used;
+}
+
+// Replace all edges with value "value" with the new value "used".
+void replaceUsedEdges(BombEdgeList edges, VertexType value, VertexType used) {
+ VertexType numEdges = getNumEdges(edges);
+ VertexType *anEdge = getFirstEdge(edges);
+
+ while (numEdges--) {
+ VertexType *p = anEdge + 1;
+ VertexType numVerts = *p;
+ p += numVerts + 1;
+
+ while (--numVerts) {
+ if (*p == value)
+ *p = used;
+
+ p++;
+ }
+
+ anEdge = getNextEdge(anEdge);
+ }
+
+ VertexType *p = getUsedVertices(edges);
+ for (VertexType i = 0; i < 25; i++, p++)
+ if (*p == value)
+ *p = used;
+}
+
+// Set a vertex's value to "used".
+void setVertexUsed(BombEdgeList edges, VertexType whichVertex, VertexType value) {
+ *(getUsedVertices(edges) + whichVertex) = value;
+}
+
+// Mark an edge in the given list between the two vertices as "used". This marks
+// all inbetween vertices as well, even if the vertex is not marked as a "hot"
+// vertex in the hot vertex section. Returns true if doing this operation
+// crosses an already marked edge.
+bool setEdgeUsed(BombEdgeList edges, VertexType fromVertex, VertexType toVertex) {
+ VertexType numEdges = getNumEdges(edges);
+ VertexType *anEdge = getFirstEdge(edges);
+ bool crossed = false;
+
+ while (numEdges--) {
+ VertexType *p = anEdge;
+ VertexType numVerts = *++p;
+ VertexType *fromPtr = 0;
+ VertexType *toPtr = 0;
+ VertexType i = numVerts;
+ p++;
+
+ while (i--) {
+ if (*p == fromVertex)
+ fromPtr = p;
+ else if (*p == toVertex)
+ toPtr = p;
+
+ if (fromPtr && toPtr) {
+ // Found the edge...
+ if (fromPtr > toPtr) {
+ p = fromPtr;
+ fromPtr = toPtr;
+ toPtr = p;
+ }
+
+ p = fromPtr + numVerts;
+
+ for (i = toPtr - fromPtr; i > 0; i--, p++) {
+ ++(*p);
+
+ if (*p == 2)
+ crossed = true;
+ }
+
+ VertexType *verts = getVertices(edges);
+ VertexType *usedVerts = getUsedVertices(edges);
+ *(usedVerts + *fromPtr) = 1;
+
+ for (p = fromPtr + 1; p != toPtr; p++)
+ if (*(verts + *p))
+ *(usedVerts + *p) = 1;
+
+ *(usedVerts + *toPtr) = 1;
+ return crossed;
+ }
+
+ p++;
+ }
+
+ anEdge = getNextEdge(anEdge);
+ }
+
+ return false;
+}
+
+// Return true if all edges are used. Can be used to determine when the bomb
+// game is over.
+bool allEdgesUsed(BombEdgeList edges) {
+ VertexType numEdges = getNumEdges(edges);
+ VertexType *anEdge = getFirstEdge(edges);
+
+ while (numEdges--) {
+ VertexType *p = anEdge + 1;
+ VertexType numVerts = *p;
+ p += numVerts + 1;
+
+ while (--numVerts) {
+ if (!*p)
+ return false;
+
+ ++p;
+ }
+
+ anEdge = getNextEdge(anEdge);
+ }
+
+ return true;
+}
+
+BombGrid::BombGrid(const DisplayElementID id) : Picture(id) {
+ Common::Rect bounds(0, 0, kBombGridWidth, kBombGridHeight);
+
+ allocateSurface(bounds);
+ setBounds(bounds);
+ _surface->fillRect(bounds, g_system->getScreenFormat().RGBToColor(0xff, 0xff, 0xff));
+
+ _transparent = true;
+
+ _yellowDot.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kYellowBombPICTBaseID, true);
+ _yellowOneSixteenth.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kYellowBombPICTBaseID + 1, true);
+ _yellowOneEighth.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kYellowBombPICTBaseID + 2, true);
+ _yellowThreeSixteenths.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kYellowBombPICTBaseID + 3, true);
+ _yellowOneFourth.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kYellowBombPICTBaseID + 4, true);
+ _yellowFiveSixteenths.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kYellowBombPICTBaseID + 5, true);
+ _yellowThreeEighths.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kYellowBombPICTBaseID + 6, true);
+ _yellowSevenSixteenths.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kYellowBombPICTBaseID + 7, true);
+ _yellowOneHalf.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kYellowBombPICTBaseID + 8, true);
+
+ _redDot.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kRedBombPICTBaseID, true);
+ _redOneSixteenth.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kRedBombPICTBaseID + 1, true);
+ _redOneEighth.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kRedBombPICTBaseID + 2, true);
+ _redThreeSixteenths.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kRedBombPICTBaseID + 3, true);
+ _redOneFourth.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kRedBombPICTBaseID + 4, true);
+ _redFiveSixteenths.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kRedBombPICTBaseID + 5, true);
+ _redThreeEighths.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kRedBombPICTBaseID + 6, true);
+ _redSevenSixteenths.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kRedBombPICTBaseID + 7, true);
+ _redOneHalf.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kRedBombPICTBaseID + 8, true);
+}
+
+void BombGrid::drawEdges(BombEdgeList edges) {
+ GraphicsManager *gfx = ((PegasusEngine *)g_engine)->_gfx;
+ gfx->setCurSurface(_surface);
+
+ _surface->fillRect(Common::Rect(0, 0, kBombGridWidth, kBombGridHeight), g_system->getScreenFormat().RGBToColor(0xff, 0xff, 0xff));
+
+ Frame *yellowStuff = &_yellowDot;
+ Frame *redStuff = &_redDot;
+ VertexType numEdges = getNumEdges(edges);
+ VertexType *anEdge = getFirstEdge(edges);
+ VertexType i, *p;
+
+ Common::Rect bounds;
+ getSurfaceBounds(bounds);
+
+ while (numEdges--) {
+ p = anEdge;
+ VertexType edgeDirection = *p++;
+ VertexType numVerts = *p++;
+ VertexType numSegs = numVerts - 1;
+
+ for (i = 0; i < numSegs; i++, p++) {
+ if (*(p + numVerts) > 0 && *(p + numVerts) < 4) {
+ Frame *drawStuff;
+
+ if (*(p + numVerts) == 2)
+ drawStuff = redStuff;
+ else
+ drawStuff = yellowStuff;
+
+ int x = vertToX(*p) + g_originsX[edgeDirection];
+ int y = vertToY(*p) + g_originsY[edgeDirection];
+
+ Common::Rect r1;
+ drawStuff[edgeDirection + 1].getSurfaceBounds(r1);
+ Common::Rect r2 = r1;
+ r2.moveTo(x, y);
+ drawStuff[edgeDirection + 1].drawImage(r1, r2);
+ }
+ }
+
+ anEdge = getNextEdge(anEdge);
+ }
+
+ for (i = 0, p = getUsedVertices(edges); i < 25; i++, p++) {
+ if (*p > 0 && *p < 4) {
+ Frame *drawStuff;
+
+ if (*p == 2)
+ drawStuff = redStuff;
+ else
+ drawStuff = yellowStuff;
+
+ int x = vertToX(i) + kDotOriginX;
+ int y = vertToY(i) + kDotOriginY;
+
+ Common::Rect r1;
+ drawStuff->getSurfaceBounds(r1);
+ Common::Rect r2 = r1;
+ r2.moveTo(x, y);
+ drawStuff->drawImage(r1, r2);
+ }
+ }
+
+ triggerRedraw();
+ gfx->setCurSurface(gfx->getWorkArea());
+}
+
+BombTimer::BombTimer(const DisplayElementID id) : IdlerAnimation(id) {
+ _middle = -1;
+ _leftImage.getImageFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kTimerLeftPICTID);
+ _rightImage.getImageFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kTimerRightPICTID);
+
+ Common::Rect r;
+ _leftImage.getSurfaceBounds(r);
+ setBounds(r);
+}
+
+void BombTimer::draw(const Common::Rect &updateRect) {
+ Common::Rect bounds;
+ getBounds(bounds);
+
+ Common::Rect r1 = bounds;
+ r1.right = _middle;
+ r1 = r1.findIntersectingRect(updateRect);
+
+ if (!r1.isEmpty()) {
+ Common::Rect r2 = r1;
+ r2.moveTo(r1.left - bounds.left, r1.top - bounds.top);
+ _leftImage.copyToCurrentPort(r2, r1);
+ }
+
+ r1 = bounds;
+ r1.left = _middle;
+ r1 = r1.findIntersectingRect(updateRect);
+
+ if (!r1.isEmpty()) {
+ Common::Rect r2 = r1;
+ r2.moveTo(r1.left - bounds.left, r1.top - bounds.top);
+ _rightImage.copyToCurrentPort(r2, r1);
+ }
+}
+
+void BombTimer::timeChanged(const TimeValue newTime) {
+ Common::Rect bounds;
+ getBounds(bounds);
+
+ int newMiddle = bounds.right - bounds.width() * newTime / getDuration();
+ if (newMiddle != _middle) {
+ _middle = newMiddle;
+ triggerRedraw();
+ }
+}
+
+#define CREATE_BOMB_LEVEL(num, data) \
+ _bombLevel[num] = new VertexType[sizeof(data)]; \
+ memcpy(_bombLevel[num], data, sizeof(data))
+
+CaldoriaBomb::CaldoriaBomb(Neighborhood *owner, NotificationManager *manager) :
+ GameInteraction(kCaldoriaBombInteractionID, owner), _grid(kCaldoriaBombGridID),
+ _timer(kCaldoriaBombTimerID), _timerNotification(kCaldoriaBombTimerNotificationID, manager) {
+ CREATE_BOMB_LEVEL(0, kBombLevelOne);
+ CREATE_BOMB_LEVEL(1, kBombLevelTwo);
+ CREATE_BOMB_LEVEL(2, kBombLevelThree);
+ CREATE_BOMB_LEVEL(3, kBombLevelFour);
+ CREATE_BOMB_LEVEL(4, kBombLevelFive);
+ CREATE_BOMB_LEVEL(5, kBombLevelSix);
+ _currentLevel = 0;
+}
+
+#undef CREATE_BOMB_LEVEL
+
+CaldoriaBomb::~CaldoriaBomb() {
+ for (int i = 0; i < 6; i++)
+ delete[] _bombLevel[i];
+}
+
+void CaldoriaBomb::openInteraction() {
+ _grid.moveElementTo(kCaldoriaBombGridLeft, kCaldoriaBombGridTop);
+ _grid.setDisplayOrder(kCaldoriaBombGridOrder);
+ _grid.startDisplaying();
+
+ _timer.moveElementTo(kCaldoriaBombTimerLeft, kCaldoriaBombTimerTop);
+ _timer.setDisplayOrder(kCaldoriaBombTimerOrder);
+ _timer.startDisplaying();
+ _timer.setSegment(0, kTenMinutesPerFifteenTicks, kFifteenTicksPerSecond);
+ _timer.setTime(0);
+
+ _timerNotification.notifyMe(this, kBombTimerExpiredFlag, kBombTimerExpiredFlag);
+ _timerCallBack.setNotification(&_timerNotification);
+ _timerCallBack.initCallBack(&_timer, kCallBackAtExtremes);
+ _timerCallBack.setCallBackFlag(kBombTimerExpiredFlag);
+
+ Common::Rect r(0, 0, kVertextHotSpotWidth, kVertextHotSpotHeight);
+
+ for (VertexType i = 0; i < 25; i++) {
+ _vertexHotspot[i] = new Hotspot(i + kVertextHotSpotBaseID);
+ r.moveTo(vertToX(i) + kCaldoriaBombGridLeft - kVertextHotSpotWidth / 2 + 6,
+ vertToY(i) + kCaldoriaBombGridTop - kVertextHotSpotHeight / 2 + 6);
+ _vertexHotspot[i]->setArea(r);
+ _vertexHotspot[i]->setHotspotFlags(kNeighborhoodSpotFlag | kClickSpotFlag);
+ g_allHotspots.push_back(_vertexHotspot[i]);
+ }
+
+ _neighborhoodNotification = _owner->getNeighborhoodNotification();
+ _neighborhoodNotification->notifyMe(this, kExtraCompletedFlag, kExtraCompletedFlag);
+}
+
+void CaldoriaBomb::initInteraction() {
+ _owner->loadLoopSound1("");
+ _owner->startExtraSequence(kCaldoria56BombStage1, kExtraCompletedFlag, kFilterNoInput);
+}
+
+void CaldoriaBomb::closeInteraction() {
+ _timer.stop();
+ _timer.hide();
+ _timer.stopDisplaying();
+ _grid.hide();
+ _grid.stopDisplaying();
+
+ // The original did not do this, but we need it here
+ // Not sure why the original worked without this; probably
+ // related to the way the List code worked in CodeWarrior.
+ // If this is not here, the notifications will later attempt
+ // to remove itself from this receiver causing a very nasty
+ // crash.
+ _timerNotification.cancelNotification(this);
+ _neighborhoodNotification->cancelNotification(this);
+}
+
+void CaldoriaBomb::startBombAmbient(Common::String ambient) {
+ _owner->loadLoopSound1(ambient);
+}
+
+void CaldoriaBomb::receiveNotification(Notification *notification, const NotificationFlags) {
+ if (notification == _neighborhoodNotification) {
+ switch (_owner->getLastExtra()) {
+ case kCaldoria56BombStage1:
+ _grid.show();
+ _timer.show();
+ _timerCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ _timer.start();
+ _currentLevel = 0;
+ _lastVertex = -1;
+ startBombAmbient("Sounds/Caldoria/BmbLoop1.22K.AIFF");
+ break;
+ case kCaldoria56BombStage2:
+ case kCaldoria56BombStage3:
+ case kCaldoria56BombStage4:
+ case kCaldoria56BombStage5:
+ case kCaldoria56BombStage6:
+ _grid.show();
+ _currentLevel++;
+ _grid.drawEdges(_bombLevel[_currentLevel]);
+ _lastVertex = -1;
+ startBombAmbient(Common::String::format("Sounds/Caldoria/BmbLoop%d.22K.AIFF", _owner->getLastExtra() - kCaldoria56BombStage1 + 1));
+ break;
+ case kCaldoria56BombStage7:
+ _owner->requestDeleteCurrentInteraction();
+ GameState.setCaldoriaBombDisarmed(true);
+ GameState.setScoringDisarmedNuke(true);
+ _owner->loadAmbientLoops();
+ break;
+ }
+ } else if (notification == &_timerNotification) {
+ _grid.hide();
+ _timer.stop();
+ _timer.hide();
+ _owner->loadLoopSound1("");
+ _owner->playDeathExtra(kCaldoria56BombExplodes, kDeathNuclearExplosion);
+ }
+}
+
+void CaldoriaBomb::activateHotspots() {
+ GameInteraction::activateHotspots();
+
+ if (_currentLevel != -1 && _lastVertex >= -1) {
+ HotVerticesList hotVertices;
+ makeHotVertexList(_bombLevel[_currentLevel], _lastVertex, hotVertices);
+
+ for (VertexType i = 0; i < hotVertices.numHotVerts; i++)
+ g_allHotspots.activateOneHotspot(hotVertices.hotVerts[i] + kVertextHotSpotBaseID);
+ }
+}
+
+void CaldoriaBomb::clickInHotspot(const Input &input, const Hotspot *hotspot) {
+ int clickedVertex = (int)hotspot->getObjectID() - (int)kVertextHotSpotBaseID;
+
+ if (clickedVertex >= 0 && clickedVertex < 25) {
+ if (_lastVertex != -1 && setEdgeUsed(_bombLevel[_currentLevel], _lastVertex, clickedVertex)) {
+ clickedVertex = -2;
+ _flashTime = tickCount();
+ } else if (allEdgesUsed(_bombLevel[_currentLevel])) {
+ setVertexUsed(_bombLevel[_currentLevel], clickedVertex, 1);
+ clickedVertex = -20;
+ _flashTime = tickCount();
+ } else {
+ setVertexUsed(_bombLevel[_currentLevel], clickedVertex, 2);
+ }
+
+ _grid.drawEdges(_bombLevel[_currentLevel]);
+ _lastVertex = clickedVertex;
+ } else {
+ GameInteraction::clickInHotspot(input, hotspot);
+ }
+}
+
+InputBits CaldoriaBomb::getInputFilter() {
+ // Disallow arrow buttons.
+ return GameInteraction::getInputFilter() & kFilterAllButtons;
+}
+
+void CaldoriaBomb::handleInput(const Input &input, const Hotspot *hotspot) {
+ GameInteraction::handleInput(input, hotspot);
+
+ switch (_lastVertex) {
+ case -2: // Flash back to yellow.
+ if (tickCount() > _flashTime + kOnTime1) {
+ replaceUsedEdges(_bombLevel[_currentLevel], 2, 3);
+ _grid.drawEdges(_bombLevel[_currentLevel]);
+ _lastVertex = -3;
+ }
+ break;
+ case -3: // Flash back to red.
+ if (tickCount() > _flashTime + kOffTime1) {
+ replaceUsedEdges(_bombLevel[_currentLevel], 3, 2);
+ _grid.drawEdges(_bombLevel[_currentLevel]);
+ _lastVertex = -4;
+ }
+ break;
+ case -4: // Flash all to yellow.
+ if (tickCount() > _flashTime + kOnTime2) {
+ setAllUsedEdgesUsed(_bombLevel[_currentLevel], 1);
+ _grid.drawEdges(_bombLevel[_currentLevel]);
+ _lastVertex = -5;
+ }
+ break;
+ case -5: // Flash all to red.
+ if (tickCount() > _flashTime + kOffTime2) {
+ setAllUsedEdgesUsed(_bombLevel[_currentLevel], 2);
+ _grid.drawEdges(_bombLevel[_currentLevel]);
+ _lastVertex = -6;
+ }
+ break;
+ case -6: // Flash all to yellow.
+ if (tickCount() > _flashTime + kOnTime3) {
+ setAllUsedEdgesUsed(_bombLevel[_currentLevel], 1);
+ _grid.drawEdges(_bombLevel[_currentLevel]);
+ _lastVertex = -7;
+ }
+ break;
+ case -7: // Flash all to red.
+ if (tickCount() > _flashTime + kOffTime3) {
+ setAllUsedEdgesUsed(_bombLevel[_currentLevel], 2);
+ _grid.drawEdges(_bombLevel[_currentLevel]);
+ _lastVertex = -8;
+ }
+ break;
+ case -8: // Restore to normal.
+ if (tickCount() > _flashTime + kOnTime4) {
+ setAllEdgesUsed(_bombLevel[_currentLevel], 0);
+ _grid.drawEdges(_bombLevel[_currentLevel]);
+ _lastVertex = -1;
+ }
+ break;
+
+ // Flash grid after success.
+ case -20: // Flash off.
+ if (tickCount() > _flashTime + kOnTime1) {
+ setAllEdgesUsed(_bombLevel[_currentLevel], 4);
+ _grid.drawEdges(_bombLevel[_currentLevel]);
+ _lastVertex = -21;
+ }
+ break;
+ case -21: // Flash on.
+ if (tickCount() > _flashTime + kOffTime1) {
+ setAllEdgesUsed(_bombLevel[_currentLevel], 1);
+ _grid.drawEdges(_bombLevel[_currentLevel]);
+ _lastVertex = -22;
+ }
+ break;
+ case -22: // Flash off.
+ if (tickCount() > _flashTime + kOnTime2) {
+ setAllEdgesUsed(_bombLevel[_currentLevel], 4);
+ _grid.drawEdges(_bombLevel[_currentLevel]);
+ _lastVertex = -23;
+ }
+ break;
+ case -23: // Flash on.
+ if (tickCount() > _flashTime + kOffTime2) {
+ setAllEdgesUsed(_bombLevel[_currentLevel], 1);
+ _grid.drawEdges(_bombLevel[_currentLevel]);
+ _lastVertex = -24;
+ }
+ break;
+ case -24:
+ if (tickCount() > _flashTime + kOnTime3) {
+ _grid.hide();
+ _lastVertex = -1;
+ _owner->loadLoopSound1("");
+
+ switch (_currentLevel) {
+ case 0:
+ _owner->startExtraSequence(kCaldoria56BombStage2, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case 1:
+ _owner->startExtraSequence(kCaldoria56BombStage3, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case 2:
+ _owner->startExtraSequence(kCaldoria56BombStage4, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case 3:
+ _owner->startExtraSequence(kCaldoria56BombStage5, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case 4:
+ _owner->startExtraSequence(kCaldoria56BombStage6, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case 5:
+ _timer.stop();
+ _grid.hide();
+ _timer.hide();
+ _owner->startExtraSequence(kCaldoria56BombStage7, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ }
+ }
+ break;
+ }
+}
+
+long CaldoriaBomb::getNumHints() {
+ return 2;
+}
+
+Common::String CaldoriaBomb::getHintMovie(uint hintNum) {
+ return (hintNum == 1) ? "Images/AI/Caldoria/X56EH2" : "Images/AI/Caldoria/X56EH3";
+}
+
+bool CaldoriaBomb::canSolve() {
+ return true;
+}
+
+void CaldoriaBomb::doSolve() {
+ _timer.stop();
+ _grid.hide();
+ _timer.hide();
+ _owner->loadLoopSound1("");
+ _owner->startExtraSequence(kCaldoria56BombStage7, kExtraCompletedFlag, kFilterNoInput);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/caldoria/caldoriabomb.h b/engines/pegasus/neighborhood/caldoria/caldoriabomb.h
new file mode 100644
index 0000000000..5bb39b4122
--- /dev/null
+++ b/engines/pegasus/neighborhood/caldoria/caldoriabomb.h
@@ -0,0 +1,156 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_CALDORIA_CALDORIABOMB_H
+#define PEGASUS_NEIGHBORHOOD_CALDORIA_CALDORIABOMB_H
+
+#include "pegasus/interaction.h"
+#include "pegasus/notification.h"
+#include "pegasus/surface.h"
+
+namespace Pegasus {
+
+/*
+ Edge list is arranged as follows:
+
+ all values in the edge list are bytes.
+
+ all vertices are numbers between 0 and 24. x coordinate of vertex is vertex % 5,
+ and y coordinate is vertex / 5.
+
+ an edge is
+ a direction code
+ a number of vertices in the edge
+ an array of vertices -- all vertices along the edge, whether or not they're
+ clickable.
+ an array of bools (bytes) indicating that a portion of the edge is
+ traversed (and should be drawn). the number of bools is one less than
+ the number of vertices.
+
+ an edge list is
+ an array of 25 bools indicating which vertex is clickable.
+ an array of 25 bools indicating which vertex is used (drawn).
+ a number of edges
+ an array of edges.
+
+ a hot vertex list is
+ a number of vertices
+ an array of 25 vertices
+
+*/
+
+typedef int8 VertexType;
+typedef VertexType *BombEdgeList;
+
+static const VertexType kEdgeOneSixteenth = 0;
+static const VertexType kEdgeOneEighth = 1;
+static const VertexType kEdgeThreeSixteenths = 2;
+static const VertexType kEdgeOneFourth = 3;
+static const VertexType kEdgeFiveSixteenths = 4;
+static const VertexType kEdgeThreeEighths = 5;
+static const VertexType kEdgeSevenSixteenths = 6;
+static const VertexType kEdgeOneHalf = 7;
+
+class BombTimer : public IdlerAnimation {
+public:
+ BombTimer(const DisplayElementID);
+ virtual ~BombTimer() {}
+
+ void draw(const Common::Rect &);
+
+protected:
+ void timeChanged(const TimeValue);
+
+ int _middle;
+ Surface _leftImage, _rightImage;
+};
+
+class BombGrid : public Picture {
+public:
+ BombGrid(const DisplayElementID);
+ virtual ~BombGrid() {}
+
+ void drawEdges(BombEdgeList);
+
+protected:
+ Frame _yellowDot;
+ Frame _yellowOneSixteenth;
+ Frame _yellowOneEighth;
+ Frame _yellowThreeSixteenths;
+ Frame _yellowOneFourth;
+ Frame _yellowFiveSixteenths;
+ Frame _yellowThreeEighths;
+ Frame _yellowSevenSixteenths;
+ Frame _yellowOneHalf;
+ Frame _redDot;
+ Frame _redOneSixteenth;
+ Frame _redOneEighth;
+ Frame _redThreeSixteenths;
+ Frame _redOneFourth;
+ Frame _redFiveSixteenths;
+ Frame _redThreeEighths;
+ Frame _redSevenSixteenths;
+ Frame _redOneHalf;
+};
+
+class Hotspot;
+
+class CaldoriaBomb : public GameInteraction, public NotificationReceiver {
+public:
+ CaldoriaBomb(Neighborhood *, NotificationManager *);
+ virtual ~CaldoriaBomb();
+
+ long getNumHints();
+ Common::String getHintMovie(uint);
+ void doSolve();
+ bool canSolve();
+
+protected:
+ void openInteraction();
+ void initInteraction();
+ void closeInteraction();
+ void receiveNotification(Notification *, const NotificationFlags);
+ void activateHotspots();
+ void clickInHotspot(const Input &, const Hotspot *);
+ void handleInput(const Input &, const Hotspot *);
+ InputBits getInputFilter();
+ void startBombAmbient(Common::String);
+
+ Notification *_neighborhoodNotification;
+ BombGrid _grid;
+ BombTimer _timer;
+ BombEdgeList _bombLevel[6];
+ int _currentLevel, _flashTime;
+ Hotspot *_vertexHotspot[25];
+ VertexType _lastVertex;
+ Notification _timerNotification;
+ NotificationCallBack _timerCallBack;
+
+ TimeValue _readTime;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/caldoria/caldoriamessages.cpp b/engines/pegasus/neighborhood/caldoria/caldoriamessages.cpp
new file mode 100644
index 0000000000..a3ce97d438
--- /dev/null
+++ b/engines/pegasus/neighborhood/caldoria/caldoriamessages.cpp
@@ -0,0 +1,115 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/gamestate.h"
+#include "pegasus/neighborhood/neighborhood.h"
+#include "pegasus/neighborhood/caldoria/caldoria.h"
+#include "pegasus/neighborhood/caldoria/caldoriamessages.h"
+
+namespace Pegasus {
+
+static const NotificationFlags kMessageDoneFlag = 1;
+
+CaldoriaMessages::CaldoriaMessages(Neighborhood *owner, const NotificationID id, NotificationManager *manager) :
+ GameInteraction(kCaldoriaMessagesInteractionID, owner), Notification(id, manager), _messageMovie(kCaldoriaMessagesID) {
+}
+
+void CaldoriaMessages::openInteraction() {
+ _neighborhoodNotification = GameInteraction::_owner->getNeighborhoodNotification();
+ _neighborhoodNotification->notifyMe(this, kExtraCompletedFlag, kExtraCompletedFlag);
+ _messageCallBack.setNotification(this);
+ notifyMe(this, kMessageDoneFlag, kMessageDoneFlag);
+ _messageCallBack.setCallBackFlag(kMessageDoneFlag);
+ _messageNumber = 1;
+}
+
+void CaldoriaMessages::initInteraction() {
+ GameInteraction::_owner->startExtraSequence(kCaBedroomVidPhone, kExtraCompletedFlag, kFilterNoInput);
+}
+
+void CaldoriaMessages::closeInteraction() {
+ cancelNotification(this);
+ _neighborhoodNotification->cancelNotification(this);
+}
+
+void CaldoriaMessages::receiveNotification(Notification *notification, const NotificationFlags) {
+ if (notification == _neighborhoodNotification) {
+ switch (GameInteraction::_owner->getLastExtra()) {
+ case kCaBedroomVidPhone:
+ GameInteraction::_owner->showExtraView(kCaBedroomMessage1);
+ break;
+ case kCaBedroomMessage1:
+ play1Message(1);
+ break;
+ case kCaBedroomMessage2:
+ play1Message(2);
+ break;
+ }
+ } else {
+ _messageCallBack.releaseCallBack();
+ _messageMovie.releaseMovie();
+
+ uint32 extraID = (_messageNumber == 1) ? kCaBedroomMessage1 : kCaBedroomMessage2;
+ GameInteraction::_owner->showExtraView(extraID);
+ allowInput(true);
+ }
+}
+
+void CaldoriaMessages::clickInHotspot(const Input &input, const Hotspot *spot) {
+ uint32 extraID;
+
+ switch (spot->getObjectID()) {
+ case kCaBedroomVidPhoneActivationSpotID:
+ extraID = (_messageNumber == 1) ? kCaBedroomMessage1 : kCaBedroomMessage2;
+ GameInteraction::_owner->startExtraSequence(extraID, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ default:
+ GameInteraction::clickInHotspot(input, spot);
+ break;
+ }
+}
+
+void CaldoriaMessages::play1Message(uint messageNumber) {
+ if (messageNumber == 1) {
+ _messageMovie.initFromMovieFile("Images/Caldoria/A12NVA.movie");
+ _messageNumber = 2;
+ } else {
+ _messageMovie.initFromMovieFile("Images/Caldoria/A12NVB.movie");
+ _messageNumber = 1;
+ GameState.setCaldoriaSeenMessages(true);
+ }
+
+ _messageMovie.moveElementTo(kCaldoriaMessageLeft, kCaldoriaMessageTop);
+ _messageMovie.setDisplayOrder(kCaldoriaMessagesOrder);
+ _messageMovie.startDisplaying();
+ _messageCallBack.initCallBack(&_messageMovie, kCallBackAtExtremes);
+ _messageCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ allowInput(false);
+ _messageMovie.show();
+ _messageMovie.redrawMovieWorld();
+ _messageMovie.start();
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/caldoria/caldoriamessages.h b/engines/pegasus/neighborhood/caldoria/caldoriamessages.h
new file mode 100644
index 0000000000..955fe10ce9
--- /dev/null
+++ b/engines/pegasus/neighborhood/caldoria/caldoriamessages.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.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_CALDORIA_CALDORIAMESSAGES_H
+#define PEGASUS_NEIGHBORHOOD_CALDORIA_CALDORIAMESSAGES_H
+
+#include "pegasus/input.h"
+#include "pegasus/interaction.h"
+#include "pegasus/movie.h"
+#include "pegasus/notification.h"
+#include "pegasus/timers.h"
+
+namespace Pegasus {
+
+class Neighborhood;
+
+class CaldoriaMessages : public GameInteraction, public Notification, public NotificationReceiver {
+public:
+ CaldoriaMessages(Neighborhood *, const NotificationID, NotificationManager *);
+ virtual ~CaldoriaMessages() {}
+
+protected:
+ void openInteraction();
+ void initInteraction();
+ void closeInteraction();
+ void receiveNotification(Notification *, const NotificationFlags);
+ void clickInHotspot(const Input &, const Hotspot *);
+ void play1Message(uint);
+
+ Movie _messageMovie;
+ NotificationCallBack _messageCallBack;
+ Notification *_neighborhoodNotification;
+ uint _messageNumber;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/caldoria/caldoriamirror.cpp b/engines/pegasus/neighborhood/caldoria/caldoriamirror.cpp
new file mode 100644
index 0000000000..ff4d1811d0
--- /dev/null
+++ b/engines/pegasus/neighborhood/caldoria/caldoriamirror.cpp
@@ -0,0 +1,135 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/gamestate.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/neighborhood/neighborhood.h"
+#include "pegasus/neighborhood/caldoria/caldoria.h"
+#include "pegasus/neighborhood/caldoria/caldoriamirror.h"
+
+namespace Pegasus {
+
+CaldoriaMirror::CaldoriaMirror(Neighborhood *owner) : GameInteraction(kCaldoriaMirrorInteractionID, owner) {
+}
+
+void CaldoriaMirror::openInteraction() {
+ _neighborhoodNotification = _owner->getNeighborhoodNotification();
+ _neighborhoodNotification->notifyMe(this, kExtraCompletedFlag, kExtraCompletedFlag);
+}
+
+void CaldoriaMirror::initInteraction() {
+ _owner->setCurrentActivation(kActivateMirrorReady);
+ _owner->startExtraSequence(kCaBathroomGreeting, kExtraCompletedFlag, kFilterNoInput);
+}
+
+void CaldoriaMirror::closeInteraction() {
+ _neighborhoodNotification->cancelNotification(this);
+}
+
+void CaldoriaMirror::handleInput(const Input &input, const Hotspot *cursorSpot) {
+ if (_owner->getLastExtra() == (uint32)kCaBathroomAgencyStandard || !input.anyDirectionInput())
+ GameInteraction::handleInput(input, cursorSpot);
+}
+
+void CaldoriaMirror::activateHotspots() {
+ GameInteraction::activateHotspots();
+
+ switch (_owner->getLastExtra()) {
+ case kCaBathroomGreeting:
+ case kCaBathroomBodyFat:
+ case kCaBathroomRetrothrash:
+ case kCaBathroomGeoWave:
+ g_allHotspots.activateOneHotspot(kCaBathroomMirrorSpotID);
+ g_allHotspots.deactivateOneHotspot(kCaHairStyle1SpotID);
+ g_allHotspots.deactivateOneHotspot(kCaHairStyle2SpotID);
+ g_allHotspots.deactivateOneHotspot(kCaHairStyle3SpotID);
+ break;
+ case kCaBathroomStylistIntro:
+ case kCaBathroomRetrothrashReturn:
+ case kCaBathroomGeoWaveReturn:
+ g_allHotspots.activateOneHotspot(kCaHairStyle1SpotID);
+ g_allHotspots.activateOneHotspot(kCaHairStyle2SpotID);
+ g_allHotspots.activateOneHotspot(kCaHairStyle3SpotID);
+ g_allHotspots.deactivateOneHotspot(kCaBathroomMirrorSpotID);
+ break;
+ }
+}
+
+void CaldoriaMirror::clickInHotspot(const Input &input, const Hotspot *spot) {
+ switch (spot->getObjectID()) {
+ case kCaBathroomMirrorSpotID:
+ switch (_owner->getLastExtra()) {
+ case kCaBathroomGreeting:
+ _owner->startExtraSequence(kCaBathroomBodyFat, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaBathroomBodyFat:
+ _owner->startExtraSequence(kCaBathroomStylistIntro, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaBathroomRetrothrash:
+ _owner->startExtraSequence(kCaBathroomRetrothrashReturn, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaBathroomGeoWave:
+ _owner->startExtraSequence(kCaBathroomGeoWaveReturn, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ }
+ break;
+ case kCaHairStyle1SpotID:
+ _owner->startExtraSequence(kCaBathroomRetrothrash, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaHairStyle2SpotID:
+ _owner->startExtraSequence(kCaBathroomAgencyStandard, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCaHairStyle3SpotID:
+ _owner->startExtraSequence(kCaBathroomGeoWave, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ default:
+ GameInteraction::clickInHotspot(input, spot);
+ break;
+ }
+}
+
+void CaldoriaMirror::receiveNotification(Notification *, const NotificationFlags) {
+ switch (_owner->getLastExtra()) {
+ case kCaBathroomRetrothrash:
+ case kCaBathroomGeoWave:
+ _owner->setCurrentActivation(kActivateMirrorReady);
+ break;
+ case kCaBathroomStylistIntro:
+ case kCaBathroomRetrothrashReturn:
+ case kCaBathroomGeoWaveReturn:
+ _owner->setCurrentActivation(kActivateStylistReady);
+ break;
+ case kCaBathroomAgencyStandard:
+ _owner->setCurrentActivation(kActivateHotSpotAlways);
+ _owner->requestDeleteCurrentInteraction();
+ GameState.setScoringFixedHair(true);
+ GameState.setCaldoriaDoneHygiene(true);
+ break;
+ }
+
+ allowInput(true);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/caldoria/caldoriamirror.h b/engines/pegasus/neighborhood/caldoria/caldoriamirror.h
new file mode 100644
index 0000000000..1ca47ec774
--- /dev/null
+++ b/engines/pegasus/neighborhood/caldoria/caldoriamirror.h
@@ -0,0 +1,54 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_CALDORIA_CALDORIAMIRROR_H
+#define PEGASUS_NEIGHBORHOOD_CALDORIA_CALDORIAMIRROR_H
+
+#include "pegasus/interaction.h"
+#include "pegasus/notification.h"
+
+namespace Pegasus {
+
+class CaldoriaMirror : public GameInteraction, public NotificationReceiver {
+public:
+ CaldoriaMirror(Neighborhood *);
+ virtual ~CaldoriaMirror() {}
+
+protected:
+ void openInteraction();
+ void initInteraction();
+ void closeInteraction();
+
+ void handleInput(const Input &, const Hotspot *);
+ void activateHotspots();
+ void clickInHotspot(const Input &, const Hotspot *);
+ void receiveNotification(Notification *, const NotificationFlags);
+
+ Notification *_neighborhoodNotification;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/door.cpp b/engines/pegasus/neighborhood/door.cpp
new file mode 100644
index 0000000000..f7ec7559fc
--- /dev/null
+++ b/engines/pegasus/neighborhood/door.cpp
@@ -0,0 +1,64 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/debug.h"
+#include "common/stream.h"
+#include "common/textconsole.h"
+
+#include "pegasus/neighborhood/door.h"
+
+namespace Pegasus {
+
+void DoorTable::loadFromStream(Common::SeekableReadStream *stream) {
+ uint32 count = stream->readUint32BE();
+ _entries.resize(count);
+
+ for (uint32 i = 0; i < count; i++) {
+ _entries[i].room = stream->readUint16BE();
+ _entries[i].direction = stream->readByte();
+ _entries[i].altCode = stream->readByte();
+ _entries[i].movieStart = stream->readUint32BE();
+ _entries[i].movieEnd = stream->readUint32BE();
+ _entries[i].flags = stream->readByte();
+ stream->readByte(); // alignment
+ debug(0, "Door[%d]: %d %d %d %d %d %d", i, _entries[i].room, _entries[i].direction,
+ _entries[i].altCode, _entries[i].movieStart, _entries[i].movieEnd,
+ _entries[i].flags);
+ }
+}
+
+void DoorTable::clear() {
+ _entries.clear();
+}
+
+DoorTable::Entry DoorTable::findEntry(RoomID room, DirectionConstant direction, AlternateID altCode) {
+ for (uint32 i = 0; i < _entries.size(); i++)
+ if (_entries[i].room == room && _entries[i].direction == direction && _entries[i].altCode == altCode)
+ return _entries[i];
+
+ return Entry();
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/door.h b/engines/pegasus/neighborhood/door.h
new file mode 100644
index 0000000000..8ea757559a
--- /dev/null
+++ b/engines/pegasus/neighborhood/door.h
@@ -0,0 +1,90 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_DOOR_H
+#define PEGASUS_NEIGHBORHOOD_DOOR_H
+
+#include "common/array.h"
+#include "common/endian.h"
+
+#include "pegasus/constants.h"
+
+namespace Common {
+ class SeekableReadStream;
+}
+
+namespace Pegasus {
+
+typedef byte DoorFlags;
+
+enum {
+ kDoorPresentBit, // Bit set if there is a door here.
+ kDoorLockedBit // Bit set if door is locked, clear if unlocked.
+};
+
+static const DoorFlags kNoDoorFlags = 0;
+static const DoorFlags kDoorPresentMask = 1 << kDoorPresentBit;
+static const DoorFlags kDoorLockedMask = 1 << kDoorLockedBit;
+
+class DoorTable {
+public:
+ DoorTable() {}
+ ~DoorTable() {}
+
+ static uint32 getResTag() { return MKTAG('D', 'o', 'o', 'r'); }
+
+ void loadFromStream(Common::SeekableReadStream *stream);
+ void clear();
+
+ struct Entry {
+ Entry() { clear(); }
+ bool isEmpty() { return movieStart == 0xffffffff; }
+ void clear() {
+ room = kNoRoomID;
+ direction = kNoDirection;
+ altCode = kNoAlternateID;
+ movieStart = 0xffffffff;
+ movieEnd = 0xffffffff;
+ flags = kNoDoorFlags;
+ }
+
+ RoomID room;
+ DirectionConstant direction;
+ AlternateID altCode;
+ TimeValue movieStart;
+ TimeValue movieEnd;
+ DoorFlags flags;
+ };
+
+ Entry findEntry(RoomID room, DirectionConstant direction, AlternateID altCode);
+
+private:
+ Common::Array<Entry> _entries;
+};
+
+} // End of namespace Pegasus
+
+#endif
+
diff --git a/engines/pegasus/neighborhood/exit.cpp b/engines/pegasus/neighborhood/exit.cpp
new file mode 100644
index 0000000000..f0dfff12d3
--- /dev/null
+++ b/engines/pegasus/neighborhood/exit.cpp
@@ -0,0 +1,70 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/debug.h"
+#include "common/stream.h"
+#include "common/textconsole.h"
+
+#include "pegasus/neighborhood/exit.h"
+
+namespace Pegasus {
+
+void ExitTable::loadFromStream(Common::SeekableReadStream *stream) {
+ uint32 count = stream->readUint32BE();
+ _entries.resize(count);
+
+ for (uint32 i = 0; i < count; i++) {
+ _entries[i].room = stream->readUint16BE();
+ _entries[i].direction = stream->readByte();
+ _entries[i].altCode = stream->readByte();
+ _entries[i].movieStart = stream->readUint32BE();
+ _entries[i].movieEnd = stream->readUint32BE();
+ _entries[i].exitEnd = stream->readUint32BE();
+ _entries[i].exitLoop = stream->readUint32BE();
+ _entries[i].exitRoom = stream->readUint16BE();
+ _entries[i].exitDirection = stream->readByte();
+ stream->readByte(); // alignment
+
+ _entries[i].originalEnd = _entries[i].exitEnd;
+
+ debug(0, "Exit[%d]: %d %d %d %d %d %d %d %d %d", i, _entries[i].room, _entries[i].direction,
+ _entries[i].altCode, _entries[i].movieStart, _entries[i].movieEnd, _entries[i].exitEnd,
+ _entries[i].exitLoop, _entries[i].exitRoom, _entries[i].exitDirection);
+ }
+}
+
+void ExitTable::clear() {
+ _entries.clear();
+}
+
+ExitTable::Entry ExitTable::findEntry(RoomID room, DirectionConstant direction, AlternateID altCode) {
+ for (uint32 i = 0; i < _entries.size(); i++)
+ if (_entries[i].room == room && _entries[i].direction == direction && _entries[i].altCode == altCode)
+ return _entries[i];
+
+ return Entry();
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/exit.h b/engines/pegasus/neighborhood/exit.h
new file mode 100644
index 0000000000..17150892f9
--- /dev/null
+++ b/engines/pegasus/neighborhood/exit.h
@@ -0,0 +1,93 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_EXIT_H
+#define PEGASUS_NEIGHBORHOOD_EXIT_H
+
+#include "common/array.h"
+#include "common/endian.h"
+
+#include "pegasus/constants.h"
+
+namespace Common {
+ class SeekableReadStream;
+}
+
+namespace Pegasus {
+
+class ExitTable {
+public:
+ ExitTable() {}
+ ~ExitTable() {}
+
+ static uint32 getResTag() { return MKTAG('E', 'x', 'i', 't'); }
+
+ void loadFromStream(Common::SeekableReadStream *stream);
+ void clear();
+
+ struct Entry {
+ Entry() { clear(); }
+ bool isEmpty() { return movieStart == 0xffffffff; }
+ void clear() {
+ room = kNoRoomID;
+ direction = kNoDirection;
+ altCode = kNoAlternateID;
+ movieStart = 0xffffffff;
+ movieEnd = 0xffffffff;
+ exitEnd = 0xffffffff;
+ originalEnd = 0xffffffff;
+ exitLoop = 0xffffffff;
+ exitRoom = kNoRoomID;
+ exitDirection = kNoDirection;
+ }
+
+ RoomID room;
+ DirectionConstant direction;
+ AlternateID altCode;
+ TimeValue movieStart;
+ TimeValue movieEnd;
+ // exitEnd is the end of the optimized run of walks.
+ TimeValue exitEnd;
+ TimeValue originalEnd;
+ // exitLoop is the loop start time of the optimized run of walks if the run
+ // loops back on itself (so far, only in TSA).
+ TimeValue exitLoop;
+ RoomID exitRoom;
+ DirectionConstant exitDirection;
+ };
+
+ Entry findEntry(RoomID room, DirectionConstant direction, AlternateID altCode);
+
+ typedef Common::Array<Entry>::iterator iterator;
+ iterator begin() { return _entries.begin(); }
+ iterator end() { return _entries.end(); }
+
+private:
+ Common::Array<Entry> _entries;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/extra.cpp b/engines/pegasus/neighborhood/extra.cpp
new file mode 100644
index 0000000000..b8c4e5b510
--- /dev/null
+++ b/engines/pegasus/neighborhood/extra.cpp
@@ -0,0 +1,58 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/debug.h"
+#include "common/stream.h"
+#include "common/textconsole.h"
+
+#include "pegasus/neighborhood/extra.h"
+
+namespace Pegasus {
+
+void ExtraTable::loadFromStream(Common::SeekableReadStream *stream) {
+ uint32 count = stream->readUint32BE();
+ _entries.resize(count);
+
+ for (uint32 i = 0; i < count; i++) {
+ _entries[i].extra = stream->readUint32BE();
+ _entries[i].movieStart = stream->readUint32BE();
+ _entries[i].movieEnd = stream->readUint32BE();
+ debug(0, "Extra[%d]: %d %d %d", i, _entries[i].extra, _entries[i].movieStart, _entries[i].movieEnd);
+ }
+}
+
+void ExtraTable::clear() {
+ _entries.clear();
+}
+
+ExtraTable::Entry ExtraTable::findEntry(ExtraID extra) {
+ for (uint32 i = 0; i < _entries.size(); i++)
+ if (_entries[i].extra == extra)
+ return _entries[i];
+
+ return Entry();
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/extra.h b/engines/pegasus/neighborhood/extra.h
new file mode 100644
index 0000000000..14fcff1009
--- /dev/null
+++ b/engines/pegasus/neighborhood/extra.h
@@ -0,0 +1,67 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_EXTRA_H
+#define PEGASUS_NEIGHBORHOOD_EXTRA_H
+
+#include "common/array.h"
+#include "common/endian.h"
+
+#include "pegasus/constants.h"
+
+namespace Common {
+ class SeekableReadStream;
+}
+
+namespace Pegasus {
+
+class ExtraTable {
+public:
+ ExtraTable() {}
+ ~ExtraTable() {}
+
+ static uint32 getResTag() { return MKTAG('X', 't', 'r', 'a'); }
+
+ void loadFromStream(Common::SeekableReadStream *stream);
+ void clear();
+
+ struct Entry {
+ Entry() { movieStart = 0xffffffff; }
+ bool isEmpty() { return movieStart == 0xffffffff; }
+
+ ExtraID extra;
+ TimeValue movieStart;
+ TimeValue movieEnd;
+ };
+
+ Entry findEntry(ExtraID extra);
+
+private:
+ Common::Array<Entry> _entries;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/hotspotinfo.cpp b/engines/pegasus/neighborhood/hotspotinfo.cpp
new file mode 100644
index 0000000000..c7524f3a0f
--- /dev/null
+++ b/engines/pegasus/neighborhood/hotspotinfo.cpp
@@ -0,0 +1,65 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/debug.h"
+#include "common/stream.h"
+#include "common/textconsole.h"
+
+#include "pegasus/neighborhood/hotspotinfo.h"
+
+namespace Pegasus {
+
+void HotspotInfoTable::loadFromStream(Common::SeekableReadStream *stream) {
+ uint32 count = stream->readUint32BE();
+ _entries.resize(count);
+
+ for (uint32 i = 0; i < count; i++) {
+ _entries[i].hotspot = stream->readUint16BE();
+ _entries[i].hotspotActivation = stream->readSByte();
+ stream->readByte(); // alignment
+ _entries[i].hotspotRoom = stream->readUint16BE();
+ _entries[i].hotspotDirection = stream->readByte();
+ stream->readByte(); // alignment
+ _entries[i].hotspotExtra = stream->readUint32BE();
+ _entries[i].hotspotItem = stream->readUint16BE();
+ debug(0, "Hotspot[%d]: %d %d %d %d %d %d", i, _entries[i].hotspot, _entries[i].hotspotActivation,
+ _entries[i].hotspotRoom, _entries[i].hotspotDirection, _entries[i].hotspotExtra,
+ _entries[i].hotspotItem);
+ }
+}
+
+void HotspotInfoTable::clear() {
+ _entries.clear();
+}
+
+HotspotInfoTable::Entry HotspotInfoTable::findEntry(HotSpotID hotspot) {
+ for (uint32 i = 0; i < _entries.size(); i++)
+ if (_entries[i].hotspot == hotspot)
+ return _entries[i];
+
+ return Entry();
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/hotspotinfo.h b/engines/pegasus/neighborhood/hotspotinfo.h
new file mode 100644
index 0000000000..965f445ba8
--- /dev/null
+++ b/engines/pegasus/neighborhood/hotspotinfo.h
@@ -0,0 +1,77 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_HOTSPOTINFO_H
+#define PEGASUS_NEIGHBORHOOD_HOTSPOTINFO_H
+
+#include "common/array.h"
+#include "common/endian.h"
+
+#include "pegasus/constants.h"
+
+namespace Common {
+ class SeekableReadStream;
+}
+
+namespace Pegasus {
+
+class HotspotInfoTable {
+public:
+ HotspotInfoTable() {}
+ ~HotspotInfoTable() {}
+
+ static uint32 getResTag() { return MKTAG('H', 'S', 'I', 'n'); }
+
+ void loadFromStream(Common::SeekableReadStream *stream);
+ void clear();
+
+ struct Entry {
+ Entry() { hotspotRoom = kNoRoomID; }
+ bool isEmpty() { return hotspotRoom == kNoRoomID; }
+
+ HotSpotID hotspot;
+ HotSpotActivationID hotspotActivation;
+ // Location hot spot lives in:
+ RoomID hotspotRoom;
+ DirectionConstant hotspotDirection;
+ // Extra to play if this is a "play extra" hot spot.
+ ExtraID hotspotExtra;
+ // Item corresponding to this hot spot if it is an item-related hot spot.
+ ItemID hotspotItem;
+ };
+
+ Entry findEntry(HotSpotID hotspot);
+
+ typedef Common::Array<Entry>::iterator iterator;
+ iterator begin() { return _entries.begin(); }
+ iterator end() { return _entries.end(); }
+
+private:
+ Common::Array<Entry> _entries;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/mars/constants.h b/engines/pegasus/neighborhood/mars/constants.h
new file mode 100644
index 0000000000..82a7f03b68
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/constants.h
@@ -0,0 +1,941 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_MARS_CONSTANTS_H
+#define PEGASUS_NEIGHBORHOOD_MARS_CONSTANTS_H
+
+#include "pegasus/constants.h"
+
+namespace Pegasus {
+
+// Element Coordinates
+
+static const CoordType kUndoHiliteLeft = kNavAreaLeft + 140;
+static const CoordType kUndoHiliteTop = kNavAreaTop + 36;
+
+static const CoordType kCurrentGuessLeft = kNavAreaLeft + 146;
+static const CoordType kCurrentGuessTop = kNavAreaTop + 90;
+
+static const CoordType kReactorChoiceHiliteLeft = kNavAreaLeft + 116;
+static const CoordType kReactorChoiceHiliteTop = kNavAreaTop + 158;
+
+static const CoordType kReactorHistoryLeft = kNavAreaLeft + 302;
+static const CoordType kReactorHistoryTop = kNavAreaTop + 39;
+
+static const CoordType kAnswerLeft = kNavAreaLeft + 304;
+static const CoordType kAnswerTop = kNavAreaTop + 180;
+
+static const CoordType kShuttle1Left = 0;
+static const CoordType kShuttle1Top = 0;
+
+static const CoordType kShuttle2Left = 0;
+static const CoordType kShuttle2Top = 96;
+
+static const CoordType kShuttle3Left = 500;
+static const CoordType kShuttle3Top = 96;
+
+static const CoordType kShuttle4Left = 0;
+static const CoordType kShuttle4Top = 320;
+
+static const CoordType kShuttleWindowLeft = 140;
+static const CoordType kShuttleWindowTop = 96;
+static const CoordType kShuttleWindowWidth = 360;
+static const CoordType kShuttleWindowHeight = 224;
+
+static const CoordType kShuttleWindowMidH = (kShuttleWindowLeft * 2 + kShuttleWindowWidth) / 2;
+static const CoordType kShuttleWindowMidV = (kShuttleWindowTop * 2 + kShuttleWindowHeight) / 2;
+
+static const CoordType kShuttleLeftLeft = 0;
+static const CoordType kShuttleLeftTop = 128;
+
+static const CoordType kShuttleRightLeft = 506;
+static const CoordType kShuttleRightTop = 128;
+
+static const CoordType kShuttleLowerLeftLeft = 74;
+static const CoordType kShuttleLowerLeftTop = 358;
+
+static const CoordType kShuttleLowerRightLeft = 486;
+static const CoordType kShuttleLowerRightTop = 354;
+
+static const CoordType kShuttleCenterLeft = 260;
+static const CoordType kShuttleCenterTop = 336;
+
+static const CoordType kShuttleUpperLeftLeft = 30;
+static const CoordType kShuttleUpperLeftTop = 32;
+
+static const CoordType kShuttleUpperRightLeft = 506;
+static const CoordType kShuttleUpperRightTop = 52;
+
+static const CoordType kShuttleLeftEnergyLeft = 110;
+static const CoordType kShuttleLeftEnergyTop = 186;
+
+static const CoordType kShuttleRightEnergyLeft = 510;
+static const CoordType kShuttleRightEnergyTop = 186;
+
+static const CoordType kShuttleEnergyLeft = 186;
+static const CoordType kShuttleEnergyTop = 60;
+static const CoordType kShuttleEnergyWidth = 252;
+static const CoordType kShuttleEnergyHeight = 22;
+
+static const CoordType kPlanetStartLeft = kShuttleWindowLeft;
+static const CoordType kPlanetStartTop = kShuttleWindowTop + kShuttleWindowHeight;
+
+static const CoordType kPlanetStopLeft = kShuttleWindowLeft;
+static const CoordType kPlanetStopTop = kShuttleWindowTop + kShuttleWindowHeight - 100;
+
+static const CoordType kShuttleTractorLeft = kShuttleWindowLeft + 6;
+static const CoordType kShuttleTractorTop = kShuttleWindowTop + 56;
+static const CoordType kShuttleTractorWidth = 348;
+static const CoordType kShuttleTractorHeight = 112;
+
+static const CoordType kShuttleJunkLeft = kShuttleWindowLeft + 6;
+static const CoordType kShuttleJunkTop = kShuttleWindowTop + 6;
+
+static const DisplayOrder kShuttlePlanetOrder = kInterfaceLayer;
+static const DisplayOrder kShuttleAlienShipOrder = kShuttlePlanetOrder + 1;
+static const DisplayOrder kShuttleRobotShipOrder = kShuttleAlienShipOrder + 1;
+static const DisplayOrder kShuttleTractorBeamMovieOrder = kShuttleRobotShipOrder + 1;
+static const DisplayOrder kShuttleWeaponBackOrder = kShuttleTractorBeamMovieOrder + 1;
+static const DisplayOrder kShuttleJunkOrder = kShuttleWeaponBackOrder + 1;
+static const DisplayOrder kShuttleWeaponFrontOrder = kShuttleJunkOrder + 1;
+static const DisplayOrder kShuttleTractorBeamOrder = kShuttleWeaponFrontOrder + 1;
+static const DisplayOrder kShuttleHUDOrder = kShuttleTractorBeamOrder + 1;
+static const DisplayOrder kShuttleBackgroundOrder = kShuttleHUDOrder + 1;
+static const DisplayOrder kShuttleMonitorOrder = kShuttleBackgroundOrder + 1;
+static const DisplayOrder kShuttleStatusOrder = kShuttleMonitorOrder + 1;
+
+static const TimeValue kShuttleSwingStart = 0;
+static const TimeValue kShuttleSwingStop = 5 * 600;
+
+static const TimeValue kCanyonChaseStart = kShuttleSwingStop;
+static const TimeValue kCanyonChaseStop = 60 * 600 + 43 * 600 + 14 * 40;
+
+static const TimeValue kLaunchTubeReachedTime = 60 * 600 + 38 * 600 - kCanyonChaseStart;
+static const TimeValue kCanyonChaseFinishedTime = kCanyonChaseStop - kCanyonChaseStart -
+ kLaunchTubeReachedTime;
+
+// Left shuttle.
+
+static const TimeValue kShuttleLeftIntroStart = 0;
+static const TimeValue kShuttleLeftIntroStop = 400;
+
+static const TimeValue kShuttleLeftBlankTime = 400;
+
+static const TimeValue kShuttleLeftNormalTime = 440;
+
+static const TimeValue kShuttleLeftAutoTestTime = 480;
+
+static const TimeValue kShuttleLeftDamagedTime = 520;
+
+static const TimeValue kShuttleLeftDampingTime = 560;
+
+static const TimeValue kShuttleLeftGravitonTime = 600;
+
+static const TimeValue kShuttleLeftTractorTime = 640;
+
+// Right shuttle.
+
+static const TimeValue kShuttleRightIntroStart = 0;
+static const TimeValue kShuttleRightIntroStop = 400;
+
+static const TimeValue kShuttleRightDestroyedStart = 400;
+static const TimeValue kShuttleRightDestroyedStop = 840;
+
+static const TimeValue kShuttleRightBlankTime = 840;
+
+static const TimeValue kShuttleRightNormalTime = 880;
+
+static const TimeValue kShuttleRightDamagedTime = 920;
+
+static const TimeValue kShuttleRightTargetLockTime = 960;
+
+static const TimeValue kShuttleRightGravitonTime = 1000;
+
+static const TimeValue kShuttleRightOverloadTime = 1040;
+
+// Lower Left shuttle.
+
+static const TimeValue kShuttleLowerLeftCollisionTime = 0;
+
+static const TimeValue kShuttleLowerLeftTubeTime = 40;
+
+static const TimeValue kShuttleLowerLeftAutopilotTime = 80;
+
+// Lower Right shuttle.
+
+static const TimeValue kShuttleLowerRightOffTime = 0;
+
+static const TimeValue kShuttleLowerRightTrackingTime = 40;
+
+static const TimeValue kShuttleLowerRightTransportTime = 80;
+
+static const TimeValue kShuttleLowerRightTransportHiliteTime = 120;
+
+// Center shuttle.
+
+static const TimeValue kShuttleCenterBoardingTime = 0;
+
+static const TimeValue kShuttleCenterCheckTime = 40;
+
+static const TimeValue kShuttleCenterNavCompTime = 80;
+
+static const TimeValue kShuttleCenterCommTime = 120;
+
+static const TimeValue kShuttleCenterWeaponsTime = 160;
+
+static const TimeValue kShuttleCenterAllSystemsTime = 200;
+
+static const TimeValue kShuttleCenterSecureLooseTime = 240;
+
+static const TimeValue kShuttleCenterAutoTestTime = 280;
+
+static const TimeValue kShuttleCenterLaunchTime = 320;
+
+static const TimeValue kShuttleCenterEnterTubeTime = 360;
+
+static const TimeValue kShuttleCenterTargetSightedTime = 400;
+
+static const TimeValue kShuttleCenterVerifyingTime = 440;
+
+static const TimeValue kShuttleCenterScanningTime = 480;
+
+static const TimeValue kShuttleCenterSafeTime = 520;
+
+// Upper Left shuttle.
+
+static const TimeValue kShuttleUpperLeftDimTime = 0;
+
+static const TimeValue kShuttleUpperLeftDampingTime = 40;
+
+static const TimeValue kShuttleUpperLeftGravitonTime = 80;
+
+static const TimeValue kShuttleUpperLeftTractorTime = 120;
+
+// Upper Right shuttle.
+
+static const TimeValue kShuttleUpperRightLockedTime = 0;
+
+static const TimeValue kShuttleUpperRightArmedTime = 40;
+
+static const TimeValue kShuttleUpperRightAlienDestroyedTime = 80;
+
+static const TimeValue kShuttleUpperRightOverloadTime = 120;
+
+static const TimeValue kShuttleUpperRightTargetDestroyedTime = 160;
+
+// Shuttle distance
+
+static const int kShuttleDistance = 500;
+
+static const int kJunkMaxDistance = kShuttleDistance;
+static const int kJunkMinDistance = 40;
+
+static const int kEnergyBeamMaxDistance = kShuttleDistance;
+static const int kEnergyBeamMinDistance = 40;
+
+static const int kGravitonMaxDistance = kShuttleDistance;
+static const int kGravitonMinDistance = 40;
+
+static const TimeValue kMarsOxyMaskOnIn = 0;
+static const TimeValue kMarsOxyMaskOnOut = 1560;
+
+static const TimeValue kMarsAirlockButtonBeepIn = 1560;
+static const TimeValue kMarsAirlockButtonBeepOut = 1620;
+
+static const TimeValue kMarsColorMatchingButtonBeepIn = 1620;
+static const TimeValue kMarsColorMatchingButtonBeepOut = 1680;
+
+static const TimeValue kMarsKioskBeepIn = 1680;
+static const TimeValue kMarsKioskBeepOut = 1740;
+
+static const TimeValue kMarsBumpIntoWallIn = 1740;
+static const TimeValue kMarsBumpIntoWallOut = 1888;
+
+static const TimeValue kMarsGantryDoorCloseIn = 1888;
+static const TimeValue kMarsGantryDoorCloseOut = 2866;
+
+static const TimeValue kMarsTransportDoorCloseIn = 2866;
+static const TimeValue kMarsTransportDoorCloseOut = 3593;
+
+static const TimeValue kMarsAirlockPressurizeIn = 3593;
+static const TimeValue kMarsAirlockPressurizeOut = 4766;
+
+static const TimeValue kMarsBigAirlockDoorCloseIn = 4766;
+static const TimeValue kMarsBigAirlockDoorCloseOut = 7872;
+
+static const TimeValue kMarsSmallAirlockDoorCloseIn = 7872;
+static const TimeValue kMarsSmallAirlockDoorCloseOut = 10000;
+
+static const TimeValue kMarsMazeDoorCloseIn = 10000;
+static const TimeValue kMarsMazeDoorCloseOut = 10969;
+
+static const TimeValue kMarsRobotTakesTransportIn = 10969;
+static const TimeValue kMarsRobotTakesTransportOut = 12802;
+
+static const TimeValue kMarsPodDepartedUpperPlatformIn = 12802;
+static const TimeValue kMarsPodDepartedUpperPlatformOut = 15783;
+
+static const TimeValue kMarsPodDepartedLowerPlatformIn = 15783;
+static const TimeValue kMarsPodDepartedLowerPlatformOut = 18736;
+
+static const TimeValue kMarsPodArrivedUpperPlatformIn = 18736;
+static const TimeValue kMarsPodArrivedUpperPlatformOut = 21605;
+
+static const TimeValue kMarsCheckInRequiredIn = 21605;
+static const TimeValue kMarsCheckInRequiredOut = 27463;
+
+static const TimeValue kMarsCantOpenShuttleIn = 27463;
+static const TimeValue kMarsCantOpenShuttleOut = 29214;
+
+static const TimeValue kMarsShuttleLockOverrideIn = 29214;
+static const TimeValue kMarsShuttleLockOverrideOut = 30330;
+
+static const TimeValue kMarsNoShuttleIn = 30330;
+static const TimeValue kMarsNoShuttleOut = 31502;
+
+static const TimeValue kMustBeUnlockedIn = 31502;
+static const TimeValue kMustBeUnlockedOut = 33960;
+
+static const TimeValue kColorMatchBlueIn = 33960;
+static const TimeValue kColorMatchBlueOut = 34240;
+
+static const TimeValue kColorMatchRedIn = 34240;
+static const TimeValue kColorMatchRedOut = 34538;
+
+static const TimeValue kColorMatchGreenIn = 34538;
+static const TimeValue kColorMatchGreenOut = 34827;
+
+static const TimeValue kColorMatchYellowIn = 34827;
+static const TimeValue kColorMatchYellowOut = 35162;
+
+static const TimeValue kColorMatchPurpleIn = 35162;
+static const TimeValue kColorMatchPurpleOut = 35426;
+
+static const TimeValue kColorMatchZeroNodesIn = 35426;
+static const TimeValue kColorMatchZeroNodesOut = 36376;
+
+static const TimeValue kColorMatchOneNodeIn = 36376;
+static const TimeValue kColorMatchOneNodeOut = 37209;
+
+static const TimeValue kColorMatchTwoNodesIn = 37209;
+static const TimeValue kColorMatchTwoNodesOut = 37983;
+
+static const TimeValue kColorMatchThreeNodesIn = 37983;
+static const TimeValue kColorMatchThreeNodesOut = 38784;
+
+static const TimeValue kMarsShuttle1DepartedIn = 38784;
+static const TimeValue kMarsShuttle1DepartedOut = 40323;
+
+static const TimeValue kMarsShuttle2DepartedIn = 40323;
+static const TimeValue kMarsShuttle2DepartedOut = 41824;
+
+static const TimeValue kShuttleCockpitIn = 41824;
+static const TimeValue kShuttleCockpitOut = 43126;
+
+static const TimeValue kShuttleOnboardIn = 43126;
+static const TimeValue kShuttleOnboardOut = 44284;
+
+static const TimeValue kShuttleNavigationIn = 44284;
+static const TimeValue kShuttleNavigationOut = 46049;
+
+static const TimeValue kShuttleCommunicationIn = 46049;
+static const TimeValue kShuttleCommunicationOut = 47288;
+
+static const TimeValue kShuttleAutoTestingIn = 47288;
+static const TimeValue kShuttleAutoTestingOut = 48179;
+
+static const TimeValue kMarsThrusterAutoTestIn = 48179;
+static const TimeValue kMarsThrusterAutoTestOut = 49979;
+
+static const TimeValue kShuttleAllSystemsIn = 49979;
+static const TimeValue kShuttleAllSystemsOut = 51065;
+
+static const TimeValue kShuttleSecureLooseIn = 51065;
+static const TimeValue kShuttleSecureLooseOut = 52346;
+
+static const TimeValue kShuttlePrepareForDropIn = 52346;
+static const TimeValue kShuttlePrepareForDropOut = 53216;
+
+static const TimeValue kShuttleAllClearIn = 53216;
+static const TimeValue kShuttleAllClearOut = 54031;
+
+static const TimeValue kShuttleConfiguringIn = 54031;
+static const TimeValue kShuttleConfiguringOut = 54994;
+
+static const TimeValue kShuttleGeneratingIn = 54994;
+static const TimeValue kShuttleGeneratingOut = 56033;
+
+static const TimeValue kShuttleBreakawayIn = 56033;
+static const TimeValue kShuttleBreakawayOut = 57346;
+
+static const TimeValue kMarsAtmosphericBreakawayIn = 57346;
+static const TimeValue kMarsAtmosphericBreakawayOut = 59237;
+
+static const TimeValue kMarsCockpitChatterIn = 59237;
+static const TimeValue kMarsCockpitChatterOut = 70344;
+
+static const TimeValue kShuttleDamperDescIn = 70344;
+static const TimeValue kShuttleDamperDescOut = 73262;
+
+static const TimeValue kShuttleGravitonDescIn = 73262;
+static const TimeValue kShuttleGravitonDescOut = 75296;
+
+static const TimeValue kShuttleTractorDescIn = 75296;
+static const TimeValue kShuttleTractorDescOut = 78381;
+
+static const TimeValue kShuttleTargetSightedIn = 78381;
+static const TimeValue kShuttleTargetSightedOut = 79074;
+
+static const TimeValue kShuttleAutopilotEngagedIn = 79074;
+static const TimeValue kShuttleAutopilotEngagedOut = 80414;
+
+static const TimeValue kMarsEDBBlastIn = 80414;
+static const TimeValue kMarsEDBBlastOut = 80705;
+
+static const TimeValue kMarsGravitonBlastIn = 80705;
+static const TimeValue kMarsGravitonBlastOut = 81199;
+
+static const TimeValue kMarsJunkCollisionIn = 81199;
+static const TimeValue kMarsJunkCollisionOut = 81961;
+
+static const TimeValue kShuttleGravitonIn = 81961;
+static const TimeValue kShuttleGravitonOut = 82587;
+
+static const TimeValue kShuttleDampingBeamIn = 82587;
+static const TimeValue kShuttleDampingBeamOut = 83331;
+
+static const TimeValue kShuttleTractorBeamIn = 83331;
+static const TimeValue kShuttleTractorBeamOut = 83802;
+
+static const TimeValue kShuttleHullBreachIn = 83802;
+static const TimeValue kShuttleHullBreachOut = 84721;
+
+static const TimeValue kShuttleWingDamageIn = 84721;
+static const TimeValue kShuttleWingDamageOut = 85640;
+
+static const TimeValue kShuttleHullDamageIn = 85640;
+static const TimeValue kShuttleHullDamageOut = 86513;
+
+static const TimeValue kShuttleEnergyTooLowIn = 86513;
+static const TimeValue kShuttleEnergyTooLowOut = 87578;
+
+static const TimeValue kShuttleTractorLimitedIn = 87578;
+static const TimeValue kShuttleTractorLimitedOut = 89164;
+
+static const TimeValue kShuttleCantHoldIn = 89164;
+static const TimeValue kShuttleCantHoldOut = 90945;
+
+static const TimeValue kShuttleBrokeFreeIn = 90945;
+static const TimeValue kShuttleBrokeFreeOut = 92322;
+
+static const TimeValue kShuttleDestroyedIn = 92322;
+static const TimeValue kShuttleDestroyedOut = 93189;
+
+static const TimeValue kShuttleCoordinatesIn = 93189;
+static const TimeValue kShuttleCoordinatesOut = 94018;
+
+static const TimeValue kShuttleScanningIn = 94018;
+static const TimeValue kShuttleScanningOut = 94975;
+
+static const TimeValue kShuttleSafeIn = 94975;
+static const TimeValue kShuttleSafeOut = 96176;
+
+static const TimeValue kShuttleOverloadedIn = 96176;
+static const TimeValue kShuttleOverloadedOut = 101308;
+
+static const TimeScale kMarsMovieScale = 600;
+static const TimeScale kMarsFramesPerSecond = 15;
+static const TimeScale kMarsFrameDuration = 40;
+
+// Alternate IDs.
+
+static const AlternateID kAltMarsNormal = 0;
+static const AlternateID kAltMarsPodAtMars34 = 1;
+static const AlternateID kAltMarsTookCard = 2;
+static const AlternateID kAltMars35AirlockEast = 3;
+static const AlternateID kAltMars35AirlockWest = 4;
+static const AlternateID kAltMarsPodAtMars45 = 5;
+static const AlternateID kAltMarsTookMask = 6;
+static const AlternateID kAltMarsMaskOnFiller = 7;
+static const AlternateID kAltMars60AirlockEast = 8;
+static const AlternateID kAltMars60AirlockWest = 9;
+
+// Room IDs.
+
+static const RoomID kMars0A = 0;
+static const RoomID kMars00 = 1;
+static const RoomID kMars01 = 2;
+static const RoomID kMars02 = 3;
+static const RoomID kMars03 = 4;
+static const RoomID kMars04 = 5;
+static const RoomID kMars05 = 6;
+static const RoomID kMars06 = 7;
+static const RoomID kMars07 = 8;
+static const RoomID kMars08 = 9;
+static const RoomID kMars09 = 10;
+static const RoomID kMars10 = 11;
+static const RoomID kMars11 = 12;
+static const RoomID kMars12 = 13;
+static const RoomID kMars13 = 14;
+static const RoomID kMars14 = 15;
+static const RoomID kMars15 = 16;
+static const RoomID kMars16 = 17;
+static const RoomID kMars17 = 18;
+static const RoomID kMars18 = 19;
+static const RoomID kMars19 = 20;
+static const RoomID kMars20 = 21;
+static const RoomID kMars21 = 22;
+static const RoomID kMars22 = 23;
+static const RoomID kMars23 = 24;
+static const RoomID kMars24 = 25;
+static const RoomID kMars25 = 26;
+static const RoomID kMars26 = 27;
+static const RoomID kMars27 = 28;
+static const RoomID kMars28 = 29;
+static const RoomID kMars29 = 30;
+static const RoomID kMars30 = 31;
+static const RoomID kMars31 = 32;
+static const RoomID kMars31South = 33;
+static const RoomID kMars32 = 34;
+static const RoomID kMars33 = 35;
+static const RoomID kMars33North = 36;
+static const RoomID kMars34 = 37;
+static const RoomID kMars35 = 38;
+static const RoomID kMars36 = 39;
+static const RoomID kMars37 = 40;
+static const RoomID kMars38 = 41;
+static const RoomID kMars39 = 42;
+static const RoomID kMars41 = 43;
+static const RoomID kMars42 = 44;
+static const RoomID kMars43 = 45;
+static const RoomID kMars44 = 46;
+static const RoomID kMars45 = 47;
+static const RoomID kMars46 = 48;
+static const RoomID kMars47 = 49;
+static const RoomID kMars48 = 50;
+static const RoomID kMars49 = 51;
+static const RoomID kMars50 = 52;
+static const RoomID kMars51 = 53;
+static const RoomID kMars52 = 54;
+static const RoomID kMars54 = 55;
+static const RoomID kMars56 = 56;
+static const RoomID kMars58 = 57;
+static const RoomID kMars60 = 58;
+static const RoomID kMarsRobotShuttle = 59;
+static const RoomID kMarsMaze004 = 60;
+static const RoomID kMarsMaze005 = 61;
+static const RoomID kMarsMaze006 = 62;
+static const RoomID kMarsMaze007 = 63;
+static const RoomID kMarsMaze008 = 64;
+static const RoomID kMarsMaze009 = 65;
+static const RoomID kMarsMaze010 = 66;
+static const RoomID kMarsMaze011 = 67;
+static const RoomID kMarsMaze012 = 68;
+static const RoomID kMarsMaze015 = 69;
+static const RoomID kMarsMaze016 = 70;
+static const RoomID kMarsMaze017 = 71;
+static const RoomID kMarsMaze018 = 72;
+static const RoomID kMarsMaze019 = 73;
+static const RoomID kMarsMaze020 = 74;
+static const RoomID kMarsMaze021 = 75;
+static const RoomID kMarsMaze022 = 76;
+static const RoomID kMarsMaze023 = 77;
+static const RoomID kMarsMaze024 = 78;
+static const RoomID kMarsMaze025 = 79;
+static const RoomID kMarsMaze026 = 80;
+static const RoomID kMarsMaze027 = 81;
+static const RoomID kMarsMaze028 = 82;
+static const RoomID kMarsMaze031 = 83;
+static const RoomID kMarsMaze032 = 84;
+static const RoomID kMarsMaze033 = 85;
+static const RoomID kMarsMaze034 = 86;
+static const RoomID kMarsMaze035 = 87;
+static const RoomID kMarsMaze036 = 88;
+static const RoomID kMarsMaze037 = 89;
+static const RoomID kMarsMaze038 = 90;
+static const RoomID kMarsMaze039 = 91;
+static const RoomID kMarsMaze042 = 92;
+static const RoomID kMarsMaze043 = 93;
+static const RoomID kMarsMaze044 = 94;
+static const RoomID kMarsMaze045 = 95;
+static const RoomID kMarsMaze046 = 96;
+static const RoomID kMarsMaze047 = 97;
+static const RoomID kMarsMaze049 = 98;
+static const RoomID kMarsMaze050 = 99;
+static const RoomID kMarsMaze051 = 100;
+static const RoomID kMarsMaze052 = 101;
+static const RoomID kMarsMaze053 = 102;
+static const RoomID kMarsMaze054 = 103;
+static const RoomID kMarsMaze055 = 104;
+static const RoomID kMarsMaze056 = 105;
+static const RoomID kMarsMaze057 = 106;
+static const RoomID kMarsMaze058 = 107;
+static const RoomID kMarsMaze059 = 108;
+static const RoomID kMarsMaze060 = 109;
+static const RoomID kMarsMaze061 = 110;
+static const RoomID kMarsMaze063 = 111;
+static const RoomID kMarsMaze064 = 112;
+static const RoomID kMarsMaze065 = 113;
+static const RoomID kMarsMaze066 = 114;
+static const RoomID kMarsMaze067 = 115;
+static const RoomID kMarsMaze068 = 116;
+static const RoomID kMarsMaze069 = 117;
+static const RoomID kMarsMaze070 = 118;
+static const RoomID kMarsMaze071 = 119;
+static const RoomID kMarsMaze072 = 120;
+static const RoomID kMarsMaze074 = 121;
+static const RoomID kMarsMaze076 = 122;
+static const RoomID kMarsMaze078 = 123;
+static const RoomID kMarsMaze079 = 124;
+static const RoomID kMarsMaze081 = 125;
+static const RoomID kMarsMaze083 = 126;
+static const RoomID kMarsMaze084 = 127;
+static const RoomID kMarsMaze085 = 128;
+static const RoomID kMarsMaze086 = 129;
+static const RoomID kMarsMaze087 = 130;
+static const RoomID kMarsMaze088 = 131;
+static const RoomID kMarsMaze089 = 132;
+static const RoomID kMarsMaze090 = 133;
+static const RoomID kMarsMaze091 = 134;
+static const RoomID kMarsMaze092 = 135;
+static const RoomID kMarsMaze093 = 136;
+static const RoomID kMarsMaze098 = 137;
+static const RoomID kMarsMaze099 = 138;
+static const RoomID kMarsMaze100 = 139;
+static const RoomID kMarsMaze101 = 140;
+static const RoomID kMarsMaze104 = 141;
+static const RoomID kMarsMaze105 = 142;
+static const RoomID kMarsMaze106 = 143;
+static const RoomID kMarsMaze107 = 144;
+static const RoomID kMarsMaze108 = 145;
+static const RoomID kMarsMaze111 = 146;
+static const RoomID kMarsMaze113 = 147;
+static const RoomID kMarsMaze114 = 148;
+static const RoomID kMarsMaze115 = 149;
+static const RoomID kMarsMaze116 = 150;
+static const RoomID kMarsMaze117 = 151;
+static const RoomID kMarsMaze118 = 152;
+static const RoomID kMarsMaze119 = 153;
+static const RoomID kMarsMaze120 = 154;
+static const RoomID kMarsMaze121 = 155;
+static const RoomID kMarsMaze122 = 156;
+static const RoomID kMarsMaze123 = 157;
+static const RoomID kMarsMaze124 = 158;
+static const RoomID kMarsMaze125 = 159;
+static const RoomID kMarsMaze126 = 160;
+static const RoomID kMarsMaze127 = 161;
+static const RoomID kMarsMaze128 = 162;
+static const RoomID kMarsMaze129 = 163;
+static const RoomID kMarsMaze130 = 164;
+static const RoomID kMarsMaze131 = 165;
+static const RoomID kMarsMaze132 = 166;
+static const RoomID kMarsMaze133 = 167;
+static const RoomID kMarsMaze136 = 168;
+static const RoomID kMarsMaze137 = 169;
+static const RoomID kMarsMaze138 = 170;
+static const RoomID kMarsMaze139 = 171;
+static const RoomID kMarsMaze140 = 172;
+static const RoomID kMarsMaze141 = 173;
+static const RoomID kMarsMaze142 = 174;
+static const RoomID kMarsMaze143 = 175;
+static const RoomID kMarsMaze144 = 176;
+static const RoomID kMarsMaze145 = 177;
+static const RoomID kMarsMaze146 = 178;
+static const RoomID kMarsMaze147 = 179;
+static const RoomID kMarsMaze148 = 180;
+static const RoomID kMarsMaze149 = 181;
+static const RoomID kMarsMaze152 = 182;
+static const RoomID kMarsMaze153 = 183;
+static const RoomID kMarsMaze154 = 184;
+static const RoomID kMarsMaze155 = 185;
+static const RoomID kMarsMaze156 = 186;
+static const RoomID kMarsMaze157 = 187;
+static const RoomID kMarsMaze159 = 188;
+static const RoomID kMarsMaze160 = 189;
+static const RoomID kMarsMaze161 = 190;
+static const RoomID kMarsMaze162 = 191;
+static const RoomID kMarsMaze163 = 192;
+static const RoomID kMarsMaze164 = 193;
+static const RoomID kMarsMaze165 = 194;
+static const RoomID kMarsMaze166 = 195;
+static const RoomID kMarsMaze167 = 196;
+static const RoomID kMarsMaze168 = 197;
+static const RoomID kMarsMaze169 = 198;
+static const RoomID kMarsMaze170 = 199;
+static const RoomID kMarsMaze171 = 200;
+static const RoomID kMarsMaze172 = 201;
+static const RoomID kMarsMaze173 = 202;
+static const RoomID kMarsMaze174 = 203;
+static const RoomID kMarsMaze175 = 204;
+static const RoomID kMarsMaze177 = 205;
+static const RoomID kMarsMaze178 = 206;
+static const RoomID kMarsMaze179 = 207;
+static const RoomID kMarsMaze180 = 208;
+static const RoomID kMarsMaze181 = 209;
+static const RoomID kMarsMaze182 = 210;
+static const RoomID kMarsMaze183 = 211;
+static const RoomID kMarsMaze184 = 212;
+static const RoomID kMarsMaze187 = 213;
+static const RoomID kMarsMaze188 = 214;
+static const RoomID kMarsMaze189 = 215;
+static const RoomID kMarsMaze190 = 216;
+static const RoomID kMarsMaze191 = 217;
+static const RoomID kMarsMaze192 = 218;
+static const RoomID kMarsMaze193 = 219;
+static const RoomID kMarsMaze194 = 220;
+static const RoomID kMarsMaze195 = 221;
+static const RoomID kMarsMaze198 = 222;
+static const RoomID kMarsMaze199 = 223;
+static const RoomID kMarsMaze200 = 224;
+static const RoomID kMarsDeathRoom = 225;
+
+// Hot Spot Activation IDs.
+
+static const HotSpotActivationID kActivationReadyForKiosk = 1;
+static const HotSpotActivationID kActivationKioskChoice = 2;
+static const HotSpotActivationID kActivationTunnelMapReady = 3;
+static const HotSpotActivationID kActivateMarsPodClosed = 4;
+static const HotSpotActivationID kActivateMarsPodOpen = 5;
+static const HotSpotActivationID kActivateReadyToPressurizeAirlock = 6;
+static const HotSpotActivationID kActivateAirlockPressurized = 7;
+static const HotSpotActivationID kActivateMaskOnHolder = 8;
+static const HotSpotActivationID kActivateMaskOnFiller = 9;
+static const HotSpotActivationID kActivateReactorPlatformOut = 10;
+static const HotSpotActivationID kActivateReactorPlatformIn = 11;
+static const HotSpotActivationID kActivateReactorAskLowerScreen = 12;
+static const HotSpotActivationID kActivateReactorReadyForNitrogen = 13;
+static const HotSpotActivationID kActivateReactorReadyForCrowBar = 14;
+static const HotSpotActivationID kActivateReactorAskOperation = 15;
+static const HotSpotActivationID kActivateReactorRanEvaluation = 16;
+static const HotSpotActivationID kActivateReactorRanDiagnostics = 17;
+static const HotSpotActivationID kActivateReactorAnalyzed = 18;
+static const HotSpotActivationID kActivateReactorInstructions = 19;
+static const HotSpotActivationID kActivateReactorInGame = 20;
+static const HotSpotActivationID kActivateReactorBombSafe = 21;
+static const HotSpotActivationID kActivateReactorBombExposed = 22;
+static const HotSpotActivationID kActivationRobotHeadClosed = 23;
+static const HotSpotActivationID kActivationRobotHeadOpen = 24;
+
+// Hot Spot IDs.
+
+static const HotSpotID kMars11NorthKioskSpotID = 5000;
+static const HotSpotID kMars11NorthKioskSightsSpotID = 5001;
+static const HotSpotID kMars11NorthKioskColonySpotID = 5002;
+static const HotSpotID kMars12NorthKioskSpotID = 5003;
+static const HotSpotID kMars12NorthKioskSightsSpotID = 5004;
+static const HotSpotID kMars12NorthKioskColonySpotID = 5005;
+static const HotSpotID kMars31SouthSpotID = 5006;
+static const HotSpotID kMars31SouthOutSpotID = 5007;
+static const HotSpotID kMars31SouthCardSpotID = 5008;
+static const HotSpotID kMars33NorthSpotID = 5009;
+static const HotSpotID kMars33NorthOutSpotID = 5010;
+static const HotSpotID kMars33NorthMonitorSpotID = 5011;
+static const HotSpotID kMars34NorthCardDropSpotID = 5012;
+static const HotSpotID kMars34SouthOpenStorageSpotID = 5013;
+static const HotSpotID kMars34SouthCloseStorageSpotID = 5014;
+static const HotSpotID kMars34SouthCrowbarSpotID = 5015;
+static const HotSpotID kMars35EastPressurizeSpotID = 5016;
+static const HotSpotID kMars35EastSpinSpotID = 5017;
+static const HotSpotID kMars35WestPressurizeSpotID = 5018;
+static const HotSpotID kMars35WestSpinSpotID = 5019;
+static const HotSpotID kMars45NorthOpenStorageSpotID = 5020;
+static const HotSpotID kMars45NorthCloseStorageSpotID = 5021;
+static const HotSpotID kMars45NorthCrowbarSpotID = 5022;
+static const HotSpotID kAttackRobotHotSpotID = 5023;
+static const HotSpotID kMars49AirMaskSpotID = 5024;
+static const HotSpotID kMars49AirMaskFilledSpotID = 5025;
+static const HotSpotID kMars49AirFillingDropSpotID = 5026;
+static const HotSpotID kMars52MoveLeftSpotID = 5027;
+static const HotSpotID kMars52MoveRightSpotID = 5028;
+static const HotSpotID kMars52ExtractSpotID = 5029;
+static const HotSpotID kMars53RetractSpotID = 5030;
+static const HotSpotID kMars54MoveLeftSpotID = 5031;
+static const HotSpotID kMars54MoveRightSpotID = 5032;
+static const HotSpotID kMars54ExtractSpotID = 5033;
+static const HotSpotID kMars55RetractSpotID = 5034;
+static const HotSpotID kMars56MoveLeftSpotID = 5035;
+static const HotSpotID kMars56MoveRightSpotID = 5036;
+static const HotSpotID kMars56ExtractSpotID = 5037;
+static const HotSpotID kMars57RetractSpotID = 5038;
+static const HotSpotID kMars57LowerScreenSpotID = 5039;
+static const HotSpotID kMars57Retract2SpotID = 5040;
+static const HotSpotID kMars57DropNitrogenSpotID = 5041;
+static const HotSpotID kMars57DropCrowBarSpotID = 5042;
+static const HotSpotID kMars57CantOpenPanelSpotID = 5043;
+static const HotSpotID kMars57ShieldEvaluationSpotID = 5044;
+static const HotSpotID kMars57MeasureOutputSpotID = 5045;
+static const HotSpotID kMars57RunDiagnosticsSpotID = 5046;
+static const HotSpotID kMars57BackToOperationMenuSpotID = 5047;
+static const HotSpotID kMars57AnalyzeObjectSpotID = 5048;
+static const HotSpotID kMars57RemoveObjectMenuSpotID = 5049;
+static const HotSpotID kMars57CircuitLinkSpotID = 5050;
+static const HotSpotID kMars57CancelCircuitLinkSpotID = 5051;
+static const HotSpotID kMars57GameInstructionsSpotID = 5052;
+static const HotSpotID kMars57UndoMoveSpotID = 5053;
+static const HotSpotID kMars57RedMoveSpotID = 5054;
+static const HotSpotID kMars57YellowMoveSpotID = 5055;
+static const HotSpotID kMars57GreenMoveSpotID = 5056;
+static const HotSpotID kMars57BlueMoveSpotID = 5057;
+static const HotSpotID kMars57PurpleMoveSpotID = 5058;
+static const HotSpotID kMars57LowerScreenSafelySpotID = 5059;
+static const HotSpotID kMars57GrabBombSpotID = 5060;
+static const HotSpotID kMars58MoveLeftSpotID = 5061;
+static const HotSpotID kMars58MoveRightSpotID = 5062;
+static const HotSpotID kMars58ExtractSpotID = 5063;
+static const HotSpotID kMars59RetractSpotID = 5064;
+static const HotSpotID kMars60EastPressurizeSpotID = 5065;
+static const HotSpotID kMars60EastSpinSpotID = 5066;
+static const HotSpotID kMars60WestPressurizeSpotID = 5067;
+static const HotSpotID kMars60WestSpinSpotID = 5068;
+static const HotSpotID kRobotShuttleOpenHeadSpotID = 5069;
+static const HotSpotID kRobotShuttleMapChipSpotID = 5070;
+static const HotSpotID kRobotShuttleOpticalChipSpotID = 5071;
+static const HotSpotID kRobotShuttleShieldChipSpotID = 5072;
+
+// Extra sequence IDs.
+
+static const ExtraID kMarsArrivalFromTSA = 0;
+static const ExtraID kMars0AWatchShuttleDepart = 1;
+static const ExtraID kRobotThrowsPlayer = 2;
+static const ExtraID kMarsInfoKioskIntro = 3;
+static const ExtraID kMarsColonyInfo = 4;
+static const ExtraID kMarsSightsInfo = 5;
+static const ExtraID kRobotOnWayToShuttle = 6;
+static const ExtraID kMars31SouthZoomInNoCard = 7;
+static const ExtraID kMars31SouthViewNoCard = 8;
+static const ExtraID kMars31SouthZoomOutNoCard = 9;
+static const ExtraID kMars31SouthZoomViewNoCard = 10;
+static const ExtraID kMars33SlideShow1 = 11;
+static const ExtraID kMars33SlideShow2 = 12;
+static const ExtraID kMars33SlideShow3 = 13;
+static const ExtraID kMars33SlideShow4 = 14;
+static const ExtraID kMars34SpotOpenWithBar = 15;
+static const ExtraID kMars34SpotCloseWithBar = 16;
+static const ExtraID kMars34SpotOpenNoBar = 17;
+static const ExtraID kMars34SpotCloseNoBar = 18;
+static const ExtraID kMars34ViewOpenWithBar = 19;
+static const ExtraID kMars34ViewOpenNoBar = 20;
+static const ExtraID kMars34NorthPodGreeting = 21;
+static const ExtraID kMarsTurnOnPod = 22;
+static const ExtraID kMarsTakePodToMars45 = 23;
+static const ExtraID kMars35WestSpinAirlockToEast = 24;
+static const ExtraID kMars35EastSpinAirlockToWest = 25;
+static const ExtraID kMars45SpotOpenWithBar = 26;
+static const ExtraID kMars45SpotCloseWithBar = 27;
+static const ExtraID kMars45SpotOpenNoBar = 28;
+static const ExtraID kMars45SpotCloseNoBar = 29;
+static const ExtraID kMars45ViewOpenWithBar = 30;
+static const ExtraID kMars45ViewOpenNoBar = 31;
+static const ExtraID kMars48RobotApproaches = 32;
+static const ExtraID kMars48RobotKillsPlayer = 33;
+static const ExtraID kMars48RobotLoops = 34;
+static const ExtraID kMars48RobotView = 35;
+static const ExtraID kMars48RobotDefends = 36;
+static const ExtraID kMars49SouthViewMaskFilling = 37;
+static const ExtraID kMars52SpinLeft = 38;
+static const ExtraID kMars52SpinRight = 39;
+static const ExtraID kMars52Extend = 40;
+static const ExtraID kMars53Retract = 41;
+static const ExtraID kMars54SpinLeft = 42;
+static const ExtraID kMars54SpinRight = 43;
+static const ExtraID kMars54Extend = 44;
+static const ExtraID kMars55Retract = 45;
+static const ExtraID kMars56SpinLeft = 46;
+static const ExtraID kMars56SpinRight = 47;
+static const ExtraID kMars56ExtendWithBomb = 48;
+static const ExtraID kMars56ExtendNoBomb = 49;
+static const ExtraID kMars57RetractWithBomb = 50;
+static const ExtraID kMars57RetractNoBomb = 51;
+static const ExtraID kMars57LowerScreenClosed = 52;
+static const ExtraID kMars57CantOpenPanel = 53;
+static const ExtraID kMars57FreezeLock = 54;
+static const ExtraID kMars57BreakLock = 55;
+static const ExtraID kMars57LockFrozenView = 56;
+static const ExtraID kMars57ThawLock = 57;
+static const ExtraID kMars57OpenPanel = 58;
+static const ExtraID kMars57OpenPanelChoices = 59;
+static const ExtraID kMars57ShieldEvaluation = 60;
+static const ExtraID kMars57MeasureOutput = 61;
+static const ExtraID kMars57ShieldOkayLoop = 62;
+static const ExtraID kMars57RunDiagnostics = 63;
+static const ExtraID kMars57BombExplodes = 64;
+static const ExtraID kMars57BombAnalysis = 65;
+static const ExtraID kMars57DontLink = 66;
+static const ExtraID kMars57CircuitLink = 67;
+static const ExtraID kMars57GameLevel1 = 68;
+static const ExtraID kMars57GameLevel2 = 69;
+static const ExtraID kMars57GameLevel3 = 70;
+static const ExtraID kMars57BombExplodesInGame = 71;
+static const ExtraID kMars57GameSolved = 72;
+static const ExtraID kMars57ExposeBomb = 73;
+static const ExtraID kMars57BackToNormal = 74;
+static const ExtraID kMars57ViewOpenNoBomb = 75;
+static const ExtraID kMars58SpinLeft = 76;
+static const ExtraID kMars58SpinRight = 77;
+static const ExtraID kMars58Extend = 78;
+static const ExtraID kMars59Retract = 79;
+static const ExtraID kMars60WestSpinAirlockToEast = 80;
+static const ExtraID kMars60EastSpinAirlockToWest = 81;
+static const ExtraID kMarsRobotHeadOpen = 82;
+static const ExtraID kMarsRobotHeadClose = 83;
+static const ExtraID kMarsRobotHead000 = 84;
+static const ExtraID kMarsRobotHead001 = 85;
+static const ExtraID kMarsRobotHead010 = 86;
+static const ExtraID kMarsRobotHead011 = 87;
+static const ExtraID kMarsRobotHead100 = 88;
+static const ExtraID kMarsRobotHead101 = 89;
+static const ExtraID kMarsRobotHead110 = 90;
+static const ExtraID kMarsRobotHead111 = 91;
+static const ExtraID kMarsMaze007RobotApproach = 92;
+static const ExtraID kMarsMaze007RobotLoop = 93;
+static const ExtraID kMarsMaze007RobotDeath = 94;
+static const ExtraID kMarsMaze015SouthRobotApproach = 95;
+static const ExtraID kMarsMaze015SouthRobotLoop = 96;
+static const ExtraID kMarsMaze015SouthRobotDeath = 97;
+static const ExtraID kMarsMaze101EastRobotApproach = 98;
+static const ExtraID kMarsMaze101EastRobotLoop = 99;
+static const ExtraID kMarsMaze101EastRobotDeath = 100;
+static const ExtraID kMarsMaze104WestLoop = 101;
+static const ExtraID kMarsMaze104WestDeath = 102;
+static const ExtraID kMarsMaze133SouthApproach = 103;
+static const ExtraID kMarsMaze133SouthLoop = 104;
+static const ExtraID kMarsMaze133SouthDeath = 105;
+static const ExtraID kMarsMaze136NorthApproach = 106;
+static const ExtraID kMarsMaze136NorthLoop = 107;
+static const ExtraID kMarsMaze136NorthDeath = 108;
+static const ExtraID kMarsMaze184WestLoop = 109;
+static const ExtraID kMarsMaze184WestDeath = 110;
+static const ExtraID kMars200DeathInBucket = 111;
+
+static const ResIDType kReactorUndoHilitePICTID = 900;
+
+static const int16 kMars52Compass = 90;
+static const int16 kMars54Compass = 180;
+static const int16 kMars56Compass = 270;
+static const int16 kMars58Compass = 0;
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/mars/energybeam.cpp b/engines/pegasus/neighborhood/mars/energybeam.cpp
new file mode 100644
index 0000000000..964c8ba381
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/energybeam.cpp
@@ -0,0 +1,70 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/pegasus.h"
+#include "pegasus/neighborhood/mars/energybeam.h"
+
+namespace Pegasus {
+
+static const TimeValue kEnergyBeamTime = kOneSecond * kShuttleWeaponScale / 2;
+
+static const CoordType kEnergyBeamOriginH = kShuttleWindowMidH;
+static const CoordType kEnergyBeamOriginV = kShuttleWindowTop + kShuttleWindowHeight;
+
+static const float kBeamXOrigin = convertScreenHToSpaceX(kEnergyBeamOriginH, kEnergyBeamMinDistance);
+static const float kBeamYOrigin = convertScreenVToSpaceY(kEnergyBeamOriginV, kEnergyBeamMinDistance);
+static const float kBeamZOrigin = kEnergyBeamMinDistance;
+
+EnergyBeam::EnergyBeam() {
+ _weaponDuration = kEnergyBeamTime;
+ setSegment(0, kEnergyBeamTime);
+ _weaponOrigin = Point3D(kBeamXOrigin, kBeamYOrigin, kBeamZOrigin);
+}
+
+void EnergyBeam::draw(const Common::Rect &) {
+ static const int kBeamColorRed1 = 224;
+ static const int kBeamColorRed2 = 64;
+
+ Graphics::Surface *surface = ((PegasusEngine *)g_engine)->_gfx->getWorkArea();
+
+ byte red = linearInterp(0, kEnergyBeamTime, _lastTime, kBeamColorRed1, kBeamColorRed2);
+ uint32 color = surface->format.RGBToColor(red, 0, 0);
+
+ Point3D startPoint;
+ if (_weaponTime < 0.1)
+ startPoint = _weaponOrigin;
+ else
+ linearInterp(_weaponOrigin, _weaponTarget, _weaponTime - 0.1, startPoint);
+
+ Common::Point lineStart;
+ project3DTo2D(startPoint, lineStart);
+
+ Common::Point lineEnd;
+ project3DTo2D(_weaponLocation, lineEnd);
+
+ surface->drawThickLine(lineStart.x, lineStart.y, lineEnd.x, lineEnd.y, 2, 1, color);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/mars/energybeam.h b/engines/pegasus/neighborhood/mars/energybeam.h
new file mode 100644
index 0000000000..715ed4b01d
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/energybeam.h
@@ -0,0 +1,43 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_MARS_ENERGYBEAM_H
+#define PEGASUS_NEIGHBORHOOD_MARS_ENERGYBEAM_H
+
+#include "pegasus/neighborhood/mars/shuttleweapon.h"
+
+namespace Pegasus {
+
+class EnergyBeam : public ShuttleWeapon {
+public:
+ EnergyBeam();
+ virtual ~EnergyBeam() {}
+
+ void draw(const Common::Rect &);
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/mars/gravitoncannon.cpp b/engines/pegasus/neighborhood/mars/gravitoncannon.cpp
new file mode 100644
index 0000000000..d04b3d08b2
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/gravitoncannon.cpp
@@ -0,0 +1,134 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/neighborhood/mars/gravitoncannon.h"
+#include "pegasus/neighborhood/mars/robotship.h"
+#include "pegasus/neighborhood/mars/spacejunk.h"
+
+namespace Pegasus {
+
+static const TimeValue kGravitonTime = kOneSecond * kShuttleWeaponScale;
+
+static const CoordType kGravitonOriginH = kShuttleWindowLeft - 1;
+static const CoordType kGravitonOriginV = kShuttleWindowMidV;
+
+static const float kGravitonXOrigin = convertScreenHToSpaceX(kGravitonOriginH, kGravitonMinDistance);
+static const float kGravitonYOrigin = convertScreenVToSpaceY(kGravitonOriginV, kGravitonMinDistance);
+static const float kGravitonZOrigin = kGravitonMinDistance;
+
+// Width of graviton sprite...
+static const CoordType kGravitonMaxScreenWidth = 78;
+static const CoordType kGravitonMaxScreenHeight = 46;
+
+static const float kGravitonWidth = convertScreenHToSpaceX(kShuttleWindowMidH + kGravitonMaxScreenWidth / 2, kGravitonMinDistance)
+ - convertScreenHToSpaceX(kShuttleWindowMidH - kGravitonMaxScreenWidth / 2, kGravitonMinDistance);
+static const float kGravitonHeight = convertScreenVToSpaceY(kShuttleWindowMidV - kGravitonMaxScreenHeight / 2, kGravitonMinDistance)
+ - convertScreenVToSpaceY(kShuttleWindowMidV + kGravitonMaxScreenHeight / 2, kGravitonMinDistance);
+
+GravitonCannon::GravitonCannon() {
+ _weaponDuration = kGravitonTime;
+ setSegment(0, kGravitonTime);
+ _weaponOrigin = Point3D(kGravitonXOrigin, kGravitonYOrigin, kGravitonZOrigin);
+ _rightOrigin = Point3D(-kGravitonXOrigin, kGravitonYOrigin, kGravitonZOrigin);
+}
+
+void GravitonCannon::initShuttleWeapon() {
+ ShuttleWeapon::initShuttleWeapon();
+ _gravitonImage.getImageFromPICTFile("Images/Mars/Graviton Cannon");
+ _gravitonImage.getSurfaceBounds(_gravitonBounds);
+}
+
+void GravitonCannon::cleanUpShuttleWeapon() {
+ _gravitonImage.deallocateSurface();
+ ShuttleWeapon::cleanUpShuttleWeapon();
+}
+
+void GravitonCannon::draw(const Common::Rect &) {
+ // Left graviton...
+ Point3D pt3D = _weaponLocation;
+ pt3D.translate(-kGravitonWidth / 2, kGravitonHeight / 2, 0);
+ Common::Point pt2D;
+ project3DTo2D(pt3D, pt2D);
+ Common::Rect gravitonRect;
+ gravitonRect.left = pt2D.x;
+ gravitonRect.top = pt2D.y;
+
+ pt3D.translate(kGravitonWidth, -kGravitonHeight, 0);
+ project3DTo2D(pt3D, pt2D);
+ gravitonRect.right = pt2D.x;
+ gravitonRect.bottom = pt2D.y;
+
+ _gravitonImage.scaleTransparentCopy(_gravitonBounds, gravitonRect);
+
+ // Right graviton...
+ pt3D = _rightLocation;
+ pt3D.translate(-kGravitonWidth / 2, kGravitonHeight / 2, 0);
+ project3DTo2D(pt3D, pt2D);
+ gravitonRect.left = pt2D.x;
+ gravitonRect.top = pt2D.y;
+
+ pt3D.translate(kGravitonWidth, -kGravitonHeight, 0);
+ project3DTo2D(pt3D, pt2D);
+ gravitonRect.right = pt2D.x;
+ gravitonRect.bottom = pt2D.y;
+
+ _gravitonImage.scaleTransparentCopy(_gravitonBounds, gravitonRect);
+}
+
+void GravitonCannon::updateWeaponPosition() {
+ ShuttleWeapon::updateWeaponPosition();
+ if (_weaponTime != 1.0)
+ linearInterp(_rightOrigin, _weaponTarget, _weaponTime, _rightLocation);
+}
+
+bool GravitonCannon::collisionWithJunk(Common::Point &impactPoint) {
+ if (getDisplayOrder() == kShuttleWeaponFrontOrder) {
+ Point3D junkPosition;
+ g_spaceJunk->getJunkPosition(junkPosition);
+
+ if (junkPosition.z < _weaponLocation.z) {
+ setDisplayOrder(kShuttleWeaponBackOrder);
+ project3DTo2D(_weaponLocation, impactPoint);
+
+ if (g_spaceJunk->pointInJunk(impactPoint))
+ return true;
+
+ project3DTo2D(_rightLocation, impactPoint);
+ return g_spaceJunk->pointInJunk(impactPoint);
+ }
+ }
+
+ return false;
+}
+
+void GravitonCannon::hitJunk(Common::Point impactPoint) {
+ g_spaceJunk->hitByGravitonCannon(impactPoint);
+}
+
+void GravitonCannon::hitShuttle(Common::Point impactPoint) {
+ g_robotShip->hitByGravitonCannon(impactPoint);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/mars/gravitoncannon.h b/engines/pegasus/neighborhood/mars/gravitoncannon.h
new file mode 100644
index 0000000000..b94fd55e5b
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/gravitoncannon.h
@@ -0,0 +1,57 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_MARS_GRAVITONCANNON_H
+#define PEGASUS_NEIGHBORHOOD_MARS_GRAVITONCANNON_H
+
+#include "pegasus/surface.h"
+#include "pegasus/neighborhood/mars/shuttleweapon.h"
+
+namespace Pegasus {
+
+class GravitonCannon : public ShuttleWeapon {
+public:
+ GravitonCannon();
+ virtual ~GravitonCannon() {}
+
+ void initShuttleWeapon();
+ void cleanUpShuttleWeapon();
+
+ void draw(const Common::Rect &);
+
+protected:
+ virtual void updateWeaponPosition();
+ virtual bool collisionWithJunk(Common::Point &impactPoint);
+ virtual void hitJunk(Common::Point impactPoint);
+ virtual void hitShuttle(Common::Point impactPoint);
+
+ Surface _gravitonImage;
+ Common::Rect _gravitonBounds;
+ Point3D _rightOrigin, _rightLocation;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/mars/hermite.cpp b/engines/pegasus/neighborhood/mars/hermite.cpp
new file mode 100644
index 0000000000..7f631b369d
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/hermite.cpp
@@ -0,0 +1,76 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/neighborhood/mars/hermite.h"
+
+namespace Pegasus {
+
+CoordType hermite(CoordType p1, CoordType p4, CoordType r1, CoordType r4, int32 time, int32 duration) {
+ float t = (float)time / duration;
+ float tsq = t * t;
+ float tcu = t * tsq;
+ float tcu2 = tcu + tcu;
+ float tsq2 = tsq + tsq;
+ float tsq3 = tsq2 + tsq;
+ return (CoordType)((tcu2 - tsq3 + 1) * p1 + (tsq3 - tcu2) * p4 + (tcu - tsq2 + t) * r1 + (tcu - tsq) * r4);
+}
+
+CoordType dHermite(CoordType p1, CoordType p4, CoordType r1, CoordType r4, int32 time, int32 duration) {
+ float t = (float)time / duration;
+ float t2 = t + t;
+ float t4 = t2 + t2;
+ float t6 = t4 + t2;
+ float tsq = t * t;
+ float tsq3 = tsq + tsq + tsq;
+ float tsq6 = tsq3 + tsq3;
+ return (CoordType)((tsq6 - t6) * p1 + (t6 - tsq6) * p4 + (tsq3 - t4 + 1) * r1 + (tsq3 - t2) * r4);
+}
+
+void hermite(Common::Point p1, Common::Point p4, Common::Point r1, Common::Point r4, int32 time, int32 duration, Common::Point &result) {
+ float t = (float)time / duration;
+ float tsq = t * t;
+ float tcu = t * tsq;
+ float tcu2 = tcu + tcu;
+ float tsq2 = tsq + tsq;
+ float tsq3 = tsq2 + tsq;
+
+ result.x = (int16)((tcu2 - tsq3 + 1) * p1.x + (tsq3 - tcu2) * p4.x + (tcu - tsq2 + t) * r1.x + (tcu - tsq) * r4.x);
+ result.y = (int16)((tcu2 - tsq3 + 1) * p1.y + (tsq3 - tcu2) * p4.y + (tcu - tsq2 + t) * r1.y + (tcu - tsq) * r4.y);
+}
+
+void dHermite(Common::Point p1, Common::Point p4, Common::Point r1, Common::Point r4, int32 time, int32 duration, Common::Point &result) {
+ float t = (float)time / duration;
+ float t2 = t + t;
+ float t4 = t2 + t2;
+ float t6 = t4 + t2;
+ float tsq = t * t;
+ float tsq3 = tsq + tsq + tsq;
+ float tsq6 = tsq3 + tsq3;
+
+ result.x = (int16)((tsq6 - t6) * p1.x + (t6 - tsq6) * p4.x + (tsq3 - t4 + 1) * r1.x + (tsq3 - t2) * r4.x);
+ result.y = (int16)((tsq6 - t6) * p1.y + (t6 - tsq6) * p4.y + (tsq3 - t4 + 1) * r1.y + (tsq3 - t2) * r4.y);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/mars/hermite.h b/engines/pegasus/neighborhood/mars/hermite.h
new file mode 100644
index 0000000000..44cb3a5a11
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/hermite.h
@@ -0,0 +1,41 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_MARS_HERMITE_H
+#define PEGASUS_NEIGHBORHOOD_MARS_HERMITE_H
+
+#include "common/rect.h"
+#include "pegasus/types.h"
+
+namespace Pegasus {
+
+CoordType hermite(CoordType p1, CoordType p4, CoordType r1, CoordType r4, int32 t, int32 duration);
+CoordType dHermite(CoordType p1, CoordType p4, CoordType r1, CoordType r4, int32 t, int32 duration);
+void hermite(Common::Point p1, Common::Point p4, Common::Point r1, Common::Point r4, int32 t, int32 duration, Common::Point &result);
+void dHermite(Common::Point p1, Common::Point p4, Common::Point r1, Common::Point r4, int32 t, int32 duration, Common::Point &result);
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/mars/mars.cpp b/engines/pegasus/neighborhood/mars/mars.cpp
new file mode 100644
index 0000000000..34c9e3d0f8
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/mars.cpp
@@ -0,0 +1,3735 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/events.h"
+#include "video/qt_decoder.h"
+
+#include "pegasus/cursor.h"
+#include "pegasus/energymonitor.h"
+#include "pegasus/gamestate.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/biochips/opticalchip.h"
+#include "pegasus/items/biochips/shieldchip.h"
+#include "pegasus/items/inventory/airmask.h"
+#include "pegasus/neighborhood/mars/mars.h"
+
+namespace Pegasus {
+
+// This should really be 22.5.
+// Probably no one will know the difference.
+static const int16 kMarsShieldPanelOffsetAngle = 22;
+
+static const CanMoveForwardReason kCantMoveRobotBlocking = kCantMoveLastReason + 1;
+
+static const NotificationFlags kTimeForCanyonChaseFlag = kLastNeighborhoodNotificationFlag << 1;
+static const NotificationFlags kExplosionFinishedFlag = kTimeForCanyonChaseFlag << 1;
+static const NotificationFlags kTimeToTransportFlag = kExplosionFinishedFlag << 1;
+
+static const NotificationFlags kMarsNotificationFlags = kTimeForCanyonChaseFlag |
+ kExplosionFinishedFlag |
+ kTimeToTransportFlag;
+
+static const TimeValue kLittleExplosionStart = 0 * 40;
+static const TimeValue kLittleExplosionStop = 24 * 40;
+
+static const TimeValue kBigExplosionStart = 24 * 40;
+static const TimeValue kBigExplosionStop = 62 * 40;
+
+enum {
+ kMaze007RobotLoopingEvent,
+ kMaze015RobotLoopingEvent,
+ kMaze101RobotLoopingEvent,
+ kMaze104RobotLoopingEvent,
+ kMaze133RobotLoopingEvent,
+ kMaze136RobotLoopingEvent,
+ kMaze184RobotLoopingEvent
+};
+
+enum {
+ kMaze007RobotLoopingTime = (64 + 96) * kMarsFrameDuration,
+ kMaze015RobotLoopingTime = (64 + 93) * kMarsFrameDuration,
+ kMaze101RobotLoopingTime = (64 + 45) * kMarsFrameDuration,
+ kMaze104RobotLoopingTime = 96 * kMarsFrameDuration,
+ kMaze133RobotLoopingTime = (64 + 96) * kMarsFrameDuration,
+ kMaze136RobotLoopingTime = (64 + 96) * kMarsFrameDuration,
+ kMaze184RobotLoopingTime = 96 * kMarsFrameDuration
+};
+
+// I've made a couple macros for these rects so we don't
+// have to globally construct them or whatnot
+#define kShuttleEnergyBeamBounds Common::Rect(24, 27, 24 + 112, 27 + 46)
+#define kShuttleGravitonBounds Common::Rect(24, 73, 24 + 112, 73 + 30)
+#define kShuttleTractorBounds Common::Rect(24, 103, 24 + 112, 103 + 30)
+#define kShuttleTransportBounds Common::Rect(484, 353, 89 + 484, 79 + 353)
+
+void MarsTimerEvent::fire() {
+ mars->marsTimerExpired(*this);
+}
+
+Mars::Mars(InputHandler *nextHandler, PegasusEngine *owner) : Neighborhood(nextHandler, owner, "Mars", kMarsID),
+ _guessObject(kNoDisplayElement), _undoPict(kNoDisplayElement), _guessHistory(kNoDisplayElement),
+ _choiceHighlight(kNoDisplayElement), _shuttleInterface1(kNoDisplayElement), _shuttleInterface2(kNoDisplayElement),
+ _shuttleInterface3(kNoDisplayElement), _shuttleInterface4(kNoDisplayElement), _canyonChaseMovie(kNoDisplayElement),
+ _leftShuttleMovie(kNoDisplayElement), _rightShuttleMovie(kNoDisplayElement), _lowerLeftShuttleMovie(kNoDisplayElement),
+ _lowerRightShuttleMovie(kNoDisplayElement), _centerShuttleMovie(kNoDisplayElement),
+ _upperLeftShuttleMovie(kNoDisplayElement), _upperRightShuttleMovie(kNoDisplayElement),
+ _leftDamageShuttleMovie(kNoDisplayElement), _rightDamageShuttleMovie(kNoDisplayElement), _explosions(kNoDisplayElement),
+ _planetMovie(kNoDisplayElement), _junk(kNoDisplayElement), _energyChoiceSpot(kShuttleEnergySpotID),
+ _gravitonChoiceSpot(kShuttleGravitonSpotID), _tractorChoiceSpot(kShuttleTractorSpotID),
+ _shuttleViewSpot(kShuttleViewSpotID), _shuttleTransportSpot(kShuttleTransportSpotID) {
+ _noAirFuse.setFunctor(new Common::Functor0Mem<void, Mars>(this, &Mars::airStageExpired));
+ setIsItemTaken(kMarsCard);
+ setIsItemTaken(kAirMask);
+ setIsItemTaken(kCrowbar);
+ setIsItemTaken(kCardBomb);
+}
+
+Mars::~Mars() {
+ _vm->getAllHotspots().remove(&_energyChoiceSpot);
+ _vm->getAllHotspots().remove(&_gravitonChoiceSpot);
+ _vm->getAllHotspots().remove(&_tractorChoiceSpot);
+ _vm->getAllHotspots().remove(&_shuttleViewSpot);
+ _vm->getAllHotspots().remove(&_shuttleTransportSpot);
+}
+
+void Mars::init() {
+ Neighborhood::init();
+
+ Hotspot *attackSpot = _vm->getAllHotspots().findHotspotByID(kAttackRobotHotSpotID);
+ attackSpot->setMaskedHotspotFlags(kDropItemSpotFlag, kDropItemSpotFlag);
+ _attackingItem = NULL;
+
+ forceStridingStop(kMars08, kNorth, kAltMarsNormal);
+
+ _neighborhoodNotification.notifyMe(this, kMarsNotificationFlags, kMarsNotificationFlags);
+
+ _explosionCallBack.setNotification(&_neighborhoodNotification);
+ _explosionCallBack.setCallBackFlag(kExplosionFinishedFlag);
+
+ _weaponSelection = kNoWeapon;
+}
+
+void Mars::flushGameState() {
+ g_energyMonitor->saveCurrentEnergyValue();
+}
+
+void Mars::start() {
+ g_energyMonitor->stopEnergyDraining();
+ g_energyMonitor->restoreLastEnergyValue();
+ _vm->resetEnergyDeathReason();
+ g_energyMonitor->startEnergyDraining();
+ Neighborhood::start();
+}
+
+class AirMaskCondition : public AICondition {
+public:
+ AirMaskCondition(const uint32);
+
+ virtual bool fireCondition();
+
+protected:
+ uint32 _airThreshold;
+ uint32 _lastAirLevel;
+};
+
+AirMaskCondition::AirMaskCondition(const uint32 airThreshold) {
+ _airThreshold = airThreshold;
+ _lastAirLevel = g_airMask->getAirLeft();
+}
+
+bool AirMaskCondition::fireCondition() {
+ bool result = g_airMask && g_airMask->isAirMaskOn() &&
+ g_airMask->getAirLeft() <= _airThreshold && _lastAirLevel > _airThreshold;
+
+ _lastAirLevel = g_airMask->getAirLeft();
+ return result;
+}
+
+void Mars::setUpAIRules() {
+ Neighborhood::setUpAIRules();
+
+ // Don't add these rules if we're going to the robot's shuttle...
+ if (g_AIArea && !GameState.getMarsReadyForShuttleTransport()) {
+ AIPlayMessageAction *messageAction = new AIPlayMessageAction("Images/AI/Globals/XGLOB1E", false);
+ AILocationCondition *locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kMars47, kSouth));
+ AIRule *rule = new AIRule(locCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Mars/XM27NB", false);
+ locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kMars27, kNorth));
+ rule = new AIRule(locCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Mars/XM27NB", false);
+ locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kMars28, kNorth));
+ rule = new AIRule(locCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Mars/XM41ED", false);
+ locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kMars19, kEast));
+ rule = new AIRule(locCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ AIDeactivateRuleAction *deactivate = new AIDeactivateRuleAction(rule);
+ locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kMars35, kWest));
+ rule = new AIRule(locCondition, deactivate);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Mars/XM41ED", false);
+ locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kMars48, kWest));
+ rule = new AIRule(locCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ AirMaskCondition *airMask50Condition = new AirMaskCondition(50);
+ messageAction = new AIPlayMessageAction("Images/AI/Mars/XMMAZB1", false);
+ AIRule *rule50 = new AIRule(airMask50Condition, messageAction);
+
+ AirMaskCondition *airMask25Condition = new AirMaskCondition(25);
+ AICompoundAction *compound = new AICompoundAction();
+ messageAction = new AIPlayMessageAction("Images/AI/Mars/XMMAZB2", false);
+ compound->addAction(messageAction);
+ deactivate = new AIDeactivateRuleAction(rule50);
+ compound->addAction(deactivate);
+ AIRule *rule25 = new AIRule(airMask25Condition, compound);
+
+ AirMaskCondition *airMask5Condition = new AirMaskCondition(5);
+ compound = new AICompoundAction;
+ messageAction = new AIPlayMessageAction("Images/AI/Mars/XMMAZB3", false);
+ compound->addAction(messageAction);
+ deactivate = new AIDeactivateRuleAction(rule50);
+ compound->addAction(deactivate);
+ deactivate = new AIDeactivateRuleAction(rule25);
+ compound->addAction(deactivate);
+ AIRule *rule5 = new AIRule(airMask5Condition, compound);
+
+ g_AIArea->addAIRule(rule5);
+ g_AIArea->addAIRule(rule25);
+ g_AIArea->addAIRule(rule50);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Mars/XM51ND", false);
+ AIDoorOpenedCondition *doorOpen = new AIDoorOpenedCondition(MakeRoomView(kMars51, kEast));
+ rule = new AIRule(doorOpen, messageAction);
+ g_AIArea->addAIRule(rule);
+ }
+}
+
+uint16 Mars::getDateResID() const {
+ return kDate2185ID;
+}
+
+TimeValue Mars::getViewTime(const RoomID room, const DirectionConstant direction) {
+ ExtraTable::Entry extra;
+ SpotTable::Entry spotEntry;
+ uint32 extraID = 0xffffffff;
+
+ switch (MakeRoomView(room, direction)) {
+ case MakeRoomView(kMars0A, kNorth):
+ if (!GameState.getMarsSeenTimeStream()) {
+ getExtraEntry(kMarsArrivalFromTSA, extra);
+ return extra.movieStart;
+ }
+ break;
+ case MakeRoomView(kMars31South, kSouth):
+ if (GameState.isTakenItemID(kMarsCard))
+ extraID = kMars31SouthZoomViewNoCard;
+ break;
+ case MakeRoomView(kMars31, kSouth):
+ if (GameState.isTakenItemID(kMarsCard))
+ extraID = kMars31SouthViewNoCard;
+ break;
+ case MakeRoomView(kMars34, kSouth):
+ if (_privateFlags.getFlag(kMarsPrivatePodStorageOpenFlag)) {
+ if (GameState.isTakenItemID(kCrowbar))
+ extraID = kMars34ViewOpenNoBar;
+ else
+ extraID = kMars34ViewOpenWithBar;
+ }
+ break;
+ case MakeRoomView(kMars36, kSouth):
+ case MakeRoomView(kMars37, kSouth):
+ case MakeRoomView(kMars38, kSouth):
+ findSpotEntry(room, direction, kSpotOnTurnMask | kSpotLoopsMask, spotEntry);
+ return spotEntry.movieStart;
+ case MakeRoomView(kMars45, kNorth):
+ if (_privateFlags.getFlag(kMarsPrivatePodStorageOpenFlag)) {
+ if (GameState.isTakenItemID(kCrowbar))
+ extraID = kMars45ViewOpenNoBar;
+ else
+ extraID = kMars45ViewOpenWithBar;
+ }
+ break;
+ case MakeRoomView(kMars48, kEast):
+ if (GameState.getMarsSeenRobotAtReactor() && !GameState.getMarsAvoidedReactorRobot())
+ extraID = kMars48RobotView;
+ break;
+ case MakeRoomView(kMars56, kEast):
+ if (_privateFlags.getFlag(kMarsPrivateBombExposedFlag)) {
+ if (_privateFlags.getFlag(kMarsPrivateDraggingBombFlag))
+ extraID = kMars57ViewOpenNoBomb;
+ else
+ extraID = kMars57ExposeBomb;
+ } else if (GameState.getMarsLockBroken()) {
+ extraID = kMars57OpenPanelChoices;
+ } else if (GameState.getMarsLockFrozen()) {
+ extraID = kMars57LockFrozenView;
+ }
+ break;
+ case MakeRoomView(kMarsRobotShuttle, kEast):
+ if (getCurrentActivation() == kActivationRobotHeadOpen) {
+ extraID = kMarsRobotHead111;
+
+ if (_privateFlags.getFlag(kMarsPrivateGotMapChipFlag))
+ extraID -= 1;
+ if (_privateFlags.getFlag(kMarsPrivateGotOpticalChipFlag))
+ extraID -= 2;
+ if (_privateFlags.getFlag(kMarsPrivateGotShieldChipFlag))
+ extraID -= 4;
+ }
+ break;
+ }
+
+ if (extraID == 0xffffffff)
+ return Neighborhood::getViewTime(room, direction);
+
+ getExtraEntry(extraID, extra);
+ return extra.movieEnd - 1;
+}
+
+void Mars::getZoomEntry(const HotSpotID spotID, ZoomTable::Entry &entry) {
+ Neighborhood::getZoomEntry(spotID, entry);
+
+ uint32 extraID = 0xffffffff;
+
+ switch (spotID) {
+ case kMars31SouthSpotID:
+ if (GameState.getCurrentDirection() == kSouth && GameState.isTakenItemID(kMarsCard))
+ extraID = kMars31SouthZoomInNoCard;
+ break;
+ case kMars31SouthOutSpotID:
+ if (GameState.getCurrentDirection() == kSouth && GameState.isTakenItemID(kMarsCard))
+ extraID = kMars31SouthZoomOutNoCard;
+ break;
+ }
+
+ if (extraID != 0xffffffff) {
+ ExtraTable::Entry extra;
+ getExtraEntry(extraID, extra);
+ entry.movieStart = extra.movieStart;
+ entry.movieEnd = extra.movieEnd;
+ }
+}
+
+void Mars::findSpotEntry(const RoomID room, const DirectionConstant direction, SpotFlags flags, SpotTable::Entry &entry) {
+ Neighborhood::findSpotEntry(room, direction, flags, entry);
+
+ if ((flags & (kSpotOnArrivalMask | kSpotOnTurnMask)) != 0) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kMars27, kNorth):
+ if (GameState.getMarsSeenThermalScan())
+ entry.clear();
+ else
+ GameState.setMarsSeenThermalScan(true);
+ break;
+ case MakeRoomView(kMars28, kNorth):
+ if (GameState.getMarsSeenThermalScan())
+ entry.clear();
+ else
+ GameState.setMarsSeenThermalScan(true);
+ break;
+ }
+ }
+}
+
+CanMoveForwardReason Mars::canMoveForward(ExitTable::Entry &entry) {
+ CanMoveForwardReason reason = Neighborhood::canMoveForward(entry);
+
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kMars48, kEast):
+ if (GameState.getMarsSeenRobotAtReactor() && !GameState.getMarsAvoidedReactorRobot())
+ reason = kCantMoveRobotBlocking;
+ break;
+ case MakeRoomView(kMars48, kSouth):
+ if (GameState.getMarsSeenRobotAtReactor() && !GameState.getMarsAvoidedReactorRobot())
+ _utilityFuse.stopFuse();
+ break;
+ }
+
+ return reason;
+}
+
+void Mars::cantMoveThatWay(CanMoveForwardReason reason) {
+ if (reason == kCantMoveRobotBlocking) {
+ startExtraSequence(kMars48RobotKillsPlayer, kExtraCompletedFlag, kFilterNoInput);
+ loadLoopSound2("");
+ } else {
+ Neighborhood::cantMoveThatWay(reason);
+ }
+}
+
+void Mars::moveForward() {
+ if (GameState.getCurrentRoom() == kMars02 || (GameState.getCurrentRoom() >= kMars05 && GameState.getCurrentRoom() <= kMars08))
+ loadLoopSound2("");
+
+ Neighborhood::moveForward();
+}
+
+void Mars::bumpIntoWall() {
+ requestSpotSound(kMarsBumpIntoWallIn, kMarsBumpIntoWallOut, kFilterNoInput, 0);
+ Neighborhood::bumpIntoWall();
+}
+
+CanOpenDoorReason Mars::canOpenDoor(DoorTable::Entry &entry) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kMars05, kEast):
+ case MakeRoomView(kMars06, kEast):
+ case MakeRoomView(kMars07, kEast):
+ if (!GameState.getMarsSecurityDown())
+ return kCantOpenLocked;
+ break;
+ case MakeRoomView(kMarsMaze037, kWest):
+ case MakeRoomView(kMarsMaze038, kEast):
+ if (GameState.getMarsMazeDoorPair1())
+ return kCantOpenLocked;
+ break;
+ case MakeRoomView(kMarsMaze050, kNorth):
+ case MakeRoomView(kMarsMaze058, kSouth):
+ if (!GameState.getMarsMazeDoorPair1())
+ return kCantOpenLocked;
+ break;
+ case MakeRoomView(kMarsMaze047, kNorth):
+ case MakeRoomView(kMarsMaze142, kSouth):
+ if (GameState.getMarsMazeDoorPair2())
+ return kCantOpenLocked;
+ break;
+ case MakeRoomView(kMarsMaze057, kNorth):
+ case MakeRoomView(kMarsMaze136, kSouth):
+ if (!GameState.getMarsMazeDoorPair2())
+ return kCantOpenLocked;
+ break;
+ case MakeRoomView(kMarsMaze120, kWest):
+ case MakeRoomView(kMarsMaze121, kEast):
+ if (GameState.getMarsMazeDoorPair3())
+ return kCantOpenLocked;
+ break;
+ case MakeRoomView(kMarsMaze081, kNorth):
+ case MakeRoomView(kMarsMaze083, kSouth):
+ if (!GameState.getMarsMazeDoorPair3())
+ return kCantOpenLocked;
+ break;
+ }
+
+ return Neighborhood::canOpenDoor(entry);
+}
+
+void Mars::cantOpenDoor(CanOpenDoorReason reason) {
+ switch (GameState.getCurrentRoom()) {
+ case kMars05:
+ case kMars06:
+ case kMars07:
+ playSpotSoundSync(kMarsCantOpenShuttleIn, kMarsCantOpenShuttleOut);
+ break;
+ default:
+ Neighborhood::cantOpenDoor(reason);
+ break;
+ }
+}
+
+void Mars::openDoor() {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kMars06, kEast):
+ case MakeRoomView(kMars07, kEast):
+ if (GameState.getMarsSecurityDown())
+ playSpotSoundSync(kMarsNoShuttleIn, kMarsNoShuttleOut);
+ break;
+ case MakeRoomView(kMars47, kSouth):
+ if (GameState.isTakenItemID(kAirMask))
+ setCurrentAlternate(kAltMarsTookMask);
+ else
+ setCurrentAlternate(kAltMarsNormal);
+ break;
+ case MakeRoomView(kMars48, kNorth):
+ if (GameState.getMarsPodAtUpperPlatform())
+ setCurrentAlternate(kAltMarsNormal);
+ else
+ setCurrentAlternate(kAltMarsPodAtMars45);
+ break;
+ case MakeRoomView(kMars48, kEast):
+ if (GameState.getMarsSeenRobotAtReactor() && !GameState.getMarsAvoidedReactorRobot()) {
+ die(kDeathDidntGetOutOfWay);
+ return;
+ }
+ break;
+ }
+
+ Neighborhood::openDoor();
+}
+
+void Mars::doorOpened() {
+ switch (GameState.getCurrentRoom()) {
+ case kMars27:
+ case kMars28:
+ if (GameState.getCurrentDirection() == kNorth)
+ _vm->die(kDeathArrestedInMars);
+ else
+ Neighborhood::doorOpened();
+ break;
+ case kMars41:
+ case kMars42:
+ if (GameState.getCurrentDirection() == kEast)
+ _vm->die(kDeathWrongShuttleLock);
+ else
+ Neighborhood::doorOpened();
+ break;
+ case kMars51:
+ Neighborhood::doorOpened();
+ setUpReactorEnergyDrain();
+
+ if (g_AIArea)
+ g_AIArea->checkRules();
+ break;
+ case kMars19:
+ if (GameState.getCurrentDirection() == kEast)
+ GameState.setMarsAirlockOpen(true);
+
+ Neighborhood::doorOpened();
+ break;
+ case kMars48:
+ if (GameState.getCurrentDirection() == kWest)
+ GameState.setMarsAirlockOpen(true);
+
+ Neighborhood::doorOpened();
+ break;
+ default:
+ Neighborhood::doorOpened();
+ break;
+ }
+}
+
+void Mars::setUpReactorEnergyDrain() {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kMars51, kEast):
+ if (GameState.isCurrentDoorOpen()) {
+ if (g_energyMonitor->getEnergyDrainRate() == kEnergyDrainNormal) {
+ if (GameState.getShieldOn()) {
+ g_shield->setItemState(kShieldRadiation);
+ g_energyMonitor->setEnergyDrainRate(kMarsReactorEnergyDrainWithShield);
+ } else {
+ g_energyMonitor->setEnergyDrainRate(kMarsReactorEnergyDrainNoShield);
+ }
+ _vm->setEnergyDeathReason(kDeathReactorBurn);
+ }
+ } else {
+ if (g_energyMonitor->getEnergyDrainRate() != kEnergyDrainNormal) {
+ if (GameState.getShieldOn())
+ g_shield->setItemState(kShieldNormal);
+ g_energyMonitor->setEnergyDrainRate(kEnergyDrainNormal);
+ _vm->resetEnergyDeathReason();
+ }
+ }
+ break;
+ case MakeRoomView(kMars52, kNorth):
+ case MakeRoomView(kMars52, kSouth):
+ case MakeRoomView(kMars52, kEast):
+ case MakeRoomView(kMars52, kWest):
+ case MakeRoomView(kMars54, kNorth):
+ case MakeRoomView(kMars54, kSouth):
+ case MakeRoomView(kMars54, kEast):
+ case MakeRoomView(kMars54, kWest):
+ case MakeRoomView(kMars56, kNorth):
+ case MakeRoomView(kMars56, kSouth):
+ case MakeRoomView(kMars56, kEast):
+ case MakeRoomView(kMars56, kWest):
+ case MakeRoomView(kMars58, kNorth):
+ case MakeRoomView(kMars58, kSouth):
+ case MakeRoomView(kMars58, kEast):
+ case MakeRoomView(kMars58, kWest):
+ if (g_energyMonitor->getEnergyDrainRate() == kEnergyDrainNormal) {
+ if (GameState.getShieldOn()) {
+ g_shield->setItemState(kShieldRadiation);
+ g_energyMonitor->setEnergyDrainRate(kMarsReactorEnergyDrainWithShield);
+ } else {
+ g_energyMonitor->setEnergyDrainRate(kMarsReactorEnergyDrainNoShield);
+ }
+ _vm->setEnergyDeathReason(kDeathReactorBurn);
+ }
+ break;
+ default:
+ if (g_energyMonitor->getEnergyDrainRate() != kEnergyDrainNormal) {
+ if (GameState.getShieldOn())
+ g_shield->setItemState(kShieldNormal);
+ g_energyMonitor->setEnergyDrainRate(kEnergyDrainNormal);
+ _vm->resetEnergyDeathReason();
+ }
+ break;
+ }
+}
+
+void Mars::closeDoorOffScreen(const RoomID room, const DirectionConstant direction) {
+ switch (room) {
+ case kMars51:
+ playSpotSoundSync(kMarsGantryDoorCloseIn, kMarsGantryDoorCloseOut);
+ if (GameState.getShieldOn())
+ g_shield->setItemState(kShieldNormal);
+ g_energyMonitor->setEnergyDrainRate(kEnergyDrainNormal);
+ _vm->resetEnergyDeathReason();
+ break;
+ case kMars05:
+ case kMars06:
+ case kMars07:
+ case kMars13:
+ case kMars22:
+ case kMars47:
+ case kMars52:
+ playSpotSoundSync(kMarsGantryDoorCloseIn, kMarsGantryDoorCloseOut);
+ break;
+ case kMars18:
+ case kMars32:
+ playSpotSoundSync(kMarsTransportDoorCloseIn, kMarsTransportDoorCloseOut);
+ break;
+ case kMars19:
+ if (GameState.getCurrentRoom() != kMars35) {
+ playSpotSoundSync(kMarsBigAirlockDoorCloseIn, kMarsBigAirlockDoorCloseOut);
+ GameState.setMarsAirlockOpen(false);
+ }
+ break;
+ case kMars36:
+ if (GameState.getCurrentRoom() != kMars35)
+ playSpotSoundSync(kMarsSmallAirlockDoorCloseIn, kMarsSmallAirlockDoorCloseOut);
+ break;
+ case kMars48:
+ if (direction == kWest) {
+ if (GameState.getCurrentRoom() != kMars60) {
+ playSpotSoundSync(kMarsSmallAirlockDoorCloseIn, kMarsSmallAirlockDoorCloseOut);
+ GameState.setMarsAirlockOpen(false);
+ }
+ } else {
+ playSpotSoundSync(kMarsGantryDoorCloseIn, kMarsGantryDoorCloseOut);
+ }
+ break;
+ case kMars41:
+ case kMars42:
+ case kMars43:
+ if (direction == kWest)
+ playSpotSoundSync(kMarsGantryDoorCloseIn, kMarsGantryDoorCloseOut);
+ break;
+ case kMarsMaze037:
+ case kMarsMaze038:
+ case kMarsMaze012:
+ case kMarsMaze066:
+ case kMarsMaze050:
+ case kMarsMaze058:
+ case kMarsMaze057:
+ case kMarsMaze136:
+ case kMarsMaze047:
+ case kMarsMaze142:
+ case kMarsMaze133:
+ case kMarsMaze132:
+ case kMarsMaze113:
+ case kMarsMaze114:
+ case kMarsMaze120:
+ case kMarsMaze121:
+ case kMarsMaze081:
+ case kMarsMaze083:
+ case kMarsMaze088:
+ case kMarsMaze089:
+ case kMarsMaze179:
+ case kMarsMaze180:
+ playSpotSoundSync(kMarsMazeDoorCloseIn, kMarsMazeDoorCloseOut);
+ break;
+ }
+}
+
+void Mars::checkAirlockDoors() {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kMars19, kWest):
+ case MakeRoomView(kMars18, kWest):
+ case MakeRoomView(kMars17, kWest):
+ case MakeRoomView(kMars16, kWest):
+ case MakeRoomView(kMars15, kWest):
+ case MakeRoomView(kMars14, kWest):
+ case MakeRoomView(kMars12, kWest):
+ case MakeRoomView(kMars11, kWest):
+ case MakeRoomView(kMars10, kWest):
+ if (GameState.getMarsInAirlock()) {
+ playSpotSoundSync(kMarsBigAirlockDoorCloseIn, kMarsBigAirlockDoorCloseOut);
+ GameState.setMarsInAirlock(false);
+ }
+ break;
+ case MakeRoomView(kMars36, kEast):
+ case MakeRoomView(kMars37, kEast):
+ case MakeRoomView(kMars38, kEast):
+ case MakeRoomView(kMars39, kEast):
+ case MakeRoomView(kMars48, kEast):
+ case MakeRoomView(kMars50, kEast):
+ case MakeRoomView(kMars51, kEast):
+ case MakeRoomView(kMars52, kEast):
+ if (GameState.getMarsInAirlock()) {
+ playSpotSoundSync(kMarsSmallAirlockDoorCloseIn, kMarsSmallAirlockDoorCloseOut);
+ GameState.setMarsInAirlock(false);
+ }
+ break;
+ case MakeRoomView(kMars35, kWest):
+ case MakeRoomView(kMars35, kEast):
+ case MakeRoomView(kMars60, kWest):
+ case MakeRoomView(kMars60, kEast):
+ GameState.setMarsInAirlock(true);
+ break;
+ default:
+ GameState.setMarsInAirlock(false);
+ break;
+ }
+}
+
+int16 Mars::getStaticCompassAngle(const RoomID room, const DirectionConstant dir) {
+ int16 angle = Neighborhood::getStaticCompassAngle(room, dir);
+
+ switch (MakeRoomView(room, dir)) {
+ case MakeRoomView(kMars0A, kNorth):
+ angle -= 20;
+ break;
+ case MakeRoomView(kMars23, kNorth):
+ case MakeRoomView(kMars23, kSouth):
+ case MakeRoomView(kMars23, kEast):
+ case MakeRoomView(kMars23, kWest):
+ case MakeRoomView(kMars26, kNorth):
+ case MakeRoomView(kMars26, kSouth):
+ case MakeRoomView(kMars26, kEast):
+ case MakeRoomView(kMars26, kWest):
+ angle += 30;
+ break;
+ case MakeRoomView(kMars24, kNorth):
+ case MakeRoomView(kMars24, kSouth):
+ case MakeRoomView(kMars24, kEast):
+ case MakeRoomView(kMars24, kWest):
+ case MakeRoomView(kMars25, kNorth):
+ case MakeRoomView(kMars25, kSouth):
+ case MakeRoomView(kMars25, kEast):
+ case MakeRoomView(kMars25, kWest):
+ angle -= 30;
+ break;
+ case MakeRoomView(kMars54, kNorth):
+ case MakeRoomView(kMars54, kSouth):
+ case MakeRoomView(kMars54, kEast):
+ case MakeRoomView(kMars54, kWest):
+ angle += 90;
+ break;
+ case MakeRoomView(kMars56, kNorth):
+ case MakeRoomView(kMars56, kSouth):
+ case MakeRoomView(kMars56, kEast):
+ case MakeRoomView(kMars56, kWest):
+ angle += 180;
+ break;
+ case MakeRoomView(kMars58, kNorth):
+ case MakeRoomView(kMars58, kSouth):
+ case MakeRoomView(kMars58, kEast):
+ case MakeRoomView(kMars58, kWest):
+ angle -= 90;
+ break;
+ }
+
+ return angle;
+}
+
+void Mars::getExitCompassMove(const ExitTable::Entry &exitEntry, FaderMoveSpec &compassMove) {
+ Neighborhood::getExitCompassMove(exitEntry, compassMove);
+
+ if (exitEntry.room == kMars43 && exitEntry.direction == kEast) {
+ compassMove.insertFaderKnot(exitEntry.movieStart + 16 * kMarsFrameDuration, 90);
+ compassMove.insertFaderKnot(exitEntry.movieStart + 32 * kMarsFrameDuration, 270);
+ } else if (exitEntry.room == kMars46 && exitEntry.direction == kWest && exitEntry.altCode != kAltMarsPodAtMars45) {
+ compassMove.makeTwoKnotFaderSpec(kMarsMovieScale, exitEntry.movieStart, 270, exitEntry.movieEnd, 360);
+ compassMove.insertFaderKnot(exitEntry.movieStart + 43 * kMarsFrameDuration, 270);
+ compassMove.insertFaderKnot(exitEntry.movieStart + 58 * kMarsFrameDuration, 360);
+ }
+}
+
+void Mars::getExtraCompassMove(const ExtraTable::Entry &entry, FaderMoveSpec &compassMove) {
+ switch (entry.extra) {
+ case kMarsTakePodToMars45:
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), entry.movieStart, 0, entry.movieEnd, 180);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * (kMarsFramesPerSecond * 3), 30);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * (kMarsFramesPerSecond * 11), 10);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * (kMarsFramesPerSecond * 14), 40);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * (kMarsFramesPerSecond * 16), 30);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * (kMarsFramesPerSecond * 23), 100);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * (kMarsFramesPerSecond * 31), 70);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * (kMarsFramesPerSecond * 34), 100);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * (kMarsFramesPerSecond * 37), 85);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * (kMarsFramesPerSecond * 42), 135);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * (kMarsFramesPerSecond * 44), 125);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * (kMarsFramesPerSecond * 46), 145);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * (kMarsFramesPerSecond * 49), 160);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * (kMarsFramesPerSecond * 51), 180);
+ break;
+ case kMars35WestSpinAirlockToEast:
+ case kMars60WestSpinAirlockToEast:
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), entry.movieStart, 90, entry.movieEnd, 270);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsMovieScale, 90);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsMovieScale * 3, 270);
+ break;
+ case kMars35EastSpinAirlockToWest:
+ case kMars60EastSpinAirlockToWest:
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), entry.movieStart, 270, entry.movieEnd, 90);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsMovieScale, 270);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsMovieScale * 3, 90);
+ break;
+ case kMars52SpinLeft:
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), entry.movieStart, kMars52Compass, entry.movieEnd, kMars54Compass);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * 10, kMars52Compass);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * 110, kMars54Compass);
+ break;
+ case kMars52SpinRight:
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), entry.movieStart, kMars52Compass, entry.movieEnd, kMars58Compass);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * 10, kMars52Compass);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * 110, kMars58Compass);
+ break;
+ case kMars52Extend:
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), entry.movieStart, kMars52Compass,
+ entry.movieEnd, kMars52Compass + kMarsShieldPanelOffsetAngle);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * 10, kMars52Compass);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * 60, kMars52Compass + kMarsShieldPanelOffsetAngle);
+ break;
+ case kMars53Retract:
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), entry.movieStart,
+ kMars52Compass + kMarsShieldPanelOffsetAngle, entry.movieEnd, kMars52Compass);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * 10, kMars52Compass + kMarsShieldPanelOffsetAngle);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * 60, kMars52Compass);
+ break;
+ case kMars56ExtendWithBomb:
+ case kMars56ExtendNoBomb:
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), entry.movieStart, kMars56Compass,
+ entry.movieEnd, kMars56Compass - kMarsShieldPanelOffsetAngle);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * 10, kMars56Compass);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * 60, kMars56Compass - kMarsShieldPanelOffsetAngle);
+ break;
+ case kMars57RetractWithBomb:
+ case kMars57RetractNoBomb:
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), entry.movieStart,
+ kMars56Compass - kMarsShieldPanelOffsetAngle, entry.movieEnd, kMars56Compass);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * 10, kMars56Compass - kMarsShieldPanelOffsetAngle);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * 60, kMars56Compass);
+ break;
+ case kMars54SpinLeft:
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), entry.movieStart, kMars54Compass, entry.movieEnd, kMars56Compass);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * 10, kMars54Compass);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * 110, kMars56Compass);
+ break;
+ case kMars54SpinRight:
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), entry.movieStart, kMars54Compass, entry.movieEnd, kMars52Compass);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * 10, kMars54Compass);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * 110, kMars52Compass);
+ break;
+ case kMars56SpinLeft:
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), entry.movieStart, kMars56Compass,
+ entry.movieEnd, kMars58Compass + 360);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * 10, kMars56Compass);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * 110, kMars58Compass + 360);
+ break;
+ case kMars56SpinRight:
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), entry.movieStart, kMars56Compass, entry.movieEnd, kMars54Compass);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * 10, kMars56Compass);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * 110, kMars54Compass);
+ break;
+ case kMars58SpinLeft:
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), entry.movieStart, kMars58Compass,
+ entry.movieEnd, kMars52Compass);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * 10, kMars58Compass);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * 110, kMars52Compass);
+ break;
+ case kMars58SpinRight:
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), entry.movieStart,
+ kMars58Compass + 360, entry.movieEnd, kMars56Compass);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * 10, kMars58Compass + 360);
+ compassMove.insertFaderKnot(entry.movieStart + kMarsFrameDuration * 110, kMars56Compass);
+ break;
+ default:
+ Neighborhood::getExtraCompassMove(entry, compassMove);
+ }
+}
+
+void Mars::loadAmbientLoops() {
+ RoomID room = GameState.getCurrentRoom();
+
+ if ((room >= kMars0A && room <= kMars21) || (room >= kMars41 && room <= kMars43)) {
+ if (GameState.getMarsSeenTimeStream())
+ loadLoopSound1("Sounds/Mars/Gantry Ambient.22K.8.AIFF");
+ } else if (room >= kMars22 && room <= kMars31South) {
+ loadLoopSound1("Sounds/Mars/Reception.02.22K.8.AIFF", 0x100 / 4);
+ } else if (room >= kMars32 && room <= kMars34) {
+ loadLoopSound1("Sounds/Mars/Pod Room Ambient.22K.8.AIFF");
+ } else if (room == kMars35) {
+ if (getAirQuality(room) == kAirQualityVacuum)
+ loadLoopSound1("Sounds/Mars/Gear Room Ambient.22K.8.AIFF");
+ else
+ loadLoopSound1("Sounds/Mars/Gantry Ambient.22K.8.AIFF", 0x100 / 2);
+ } else if (room >= kMars36 && room <= kMars39) {
+ loadLoopSound1("Sounds/Mars/Gear Room Ambient.22K.8.AIFF");
+ } else if (room >= kMars45 && room <= kMars51) {
+ loadLoopSound1("Sounds/Mars/Lower Mars Ambient.22K.8.AIFF");
+ } else if (room >= kMars52 && room <= kMars58) {
+ loadLoopSound1("Sounds/Mars/ReactorLoop.22K.8.AIFF");
+ } else if (room == kMars60) {
+ if (getAirQuality(room) == kAirQualityVacuum)
+ loadLoopSound1("Sounds/Mars/Mars Maze Ambient.22K.8.AIFF");
+ else
+ loadLoopSound1("Sounds/Mars/Lower Mars Ambient.22K.8.AIFF", 0x100 / 2);
+ } else if (room >= kMarsMaze004 && room <= kMarsMaze200) {
+ loadLoopSound1("Sounds/Mars/Mars Maze Ambient.22K.8.AIFF");
+ } else if (room == kMarsRobotShuttle) {
+ loadLoopSound1("Sounds/Mars/Robot Shuttle.22K.8.AIFF");
+ }
+
+ if (!_noAirFuse.isFuseLit()) {
+ switch (room) {
+ case kMars02:
+ case kMars05:
+ case kMars06:
+ case kMars07:
+ case kMars08:
+ loadLoopSound2("Sounds/Mars/Gantry Loop.aiff", 0x100, 0, 0);
+ break;
+ // Robot at maze 48
+ case kMarsMaze037:
+ if (GameState.isCurrentDoorOpen())
+ loadLoopSound2("Sounds/Mars/Maze Sparks.22K.AIFF", 0x100 / 2);
+ else
+ loadLoopSound2("");
+ break;
+ case kMarsMaze038:
+ case kMarsMaze039:
+ case kMarsMaze049:
+ loadLoopSound2("Sounds/Mars/Maze Sparks.22K.AIFF", 0x100);
+ break;
+ case kMarsMaze050:
+ loadLoopSound2("Sounds/Mars/Maze Sparks.22K.AIFF", 0x100 * 3 / 4);
+ break;
+ case kMarsMaze051:
+ loadLoopSound2("Sounds/Mars/Maze Sparks.22K.AIFF", 0x100 / 2);
+ break;
+ case kMarsMaze052:
+ loadLoopSound2("Sounds/Mars/Maze Sparks.22K.AIFF", 0x100 / 4);
+ break;
+ case kMarsMaze042:
+ case kMarsMaze053:
+ loadLoopSound2("Sounds/Mars/Maze Sparks.22K.AIFF", 0x100 / 8);
+ break;
+ case kMarsMaze058:
+ if (GameState.isCurrentDoorOpen())
+ loadLoopSound2("Sounds/Mars/Maze Sparks.22K.AIFF", 0x100 / 4);
+ else
+ loadLoopSound2("");
+ break;
+ // Robot at 151
+ case kMarsMaze148:
+ loadLoopSound2("Sounds/Mars/Maze Sparks.22K.AIFF", 0x100);
+ break;
+ case kMarsMaze147:
+ case kMarsMaze149:
+ loadLoopSound2("Sounds/Mars/Maze Sparks.22K.AIFF", 0x100 * 3 / 4);
+ break;
+ case kMarsMaze146:
+ case kMarsMaze152:
+ loadLoopSound2("Sounds/Mars/Maze Sparks.22K.AIFF", 0x100 / 2);
+ break;
+ case kMarsMaze145:
+ case kMarsMaze153:
+ loadLoopSound2("Sounds/Mars/Maze Sparks.22K.AIFF", 0x100 / 4);
+ break;
+ // Robots at 80 and 82.
+ case kMarsMaze079:
+ case kMarsMaze081:
+ loadLoopSound2("Sounds/Mars/Maze Sparks.22K.AIFF", 0x100);
+ break;
+ case kMarsMaze078:
+ loadLoopSound2("Sounds/Mars/Maze Sparks.22K.AIFF", 0x100 * 3 / 4);
+ break;
+ case kMarsMaze083:
+ if (GameState.isCurrentDoorOpen())
+ loadLoopSound2("Sounds/Mars/Maze Sparks.22K.AIFF", 0x100 * 3 / 4);
+ else
+ loadLoopSound2("");
+ break;
+ case kMarsMaze118:
+ case kMarsMaze076:
+ loadLoopSound2("Sounds/Mars/Maze Sparks.22K.AIFF", 0x100 / 2);
+ break;
+ case kMarsMaze074:
+ case kMarsMaze117:
+ loadLoopSound2("Sounds/Mars/Maze Sparks.22K.AIFF", 0x100 / 4);
+ break;
+ // Robot at 94
+ case kMarsMaze093:
+ loadLoopSound2("Sounds/Mars/Maze Sparks.22K.AIFF", 0x100);
+ break;
+ case kMarsMaze091:
+ case kMarsMaze092:
+ case kMarsMaze098:
+ case kMarsMaze101:
+ case kMarsMaze100:
+ loadLoopSound2("Sounds/Mars/Maze Sparks.22K.AIFF", 0x100 * 3 / 4);
+ break;
+ case kMarsMaze090:
+ case kMarsMaze099:
+ loadLoopSound2("Sounds/Mars/Maze Sparks.22K.AIFF", 0x100 / 2);
+ break;
+ case kMarsMaze089:
+ if (GameState.isCurrentDoorOpen())
+ loadLoopSound2("Sounds/Mars/Maze Sparks.22K.AIFF", 0x100 / 2);
+ break;
+ case kMarsMaze178:
+ loadLoopSound2("Sounds/Mars/Maze Sparks.22K.AIFF", 0x100 / 4);
+ break;
+ // Robot at 197
+ case kMarsMaze191:
+ loadLoopSound2("Sounds/Mars/Maze Sparks.22K.AIFF", 0x100);
+ break;
+ case kMarsMaze190:
+ loadLoopSound2("Sounds/Mars/Maze Sparks.22K.AIFF", 0x100 * 3 / 4);
+ break;
+ case kMarsMaze198:
+ case kMarsMaze189:
+ loadLoopSound2("Sounds/Mars/Maze Sparks.22K.AIFF", 0x100 / 2);
+ break;
+ default:
+ loadLoopSound2("");
+ break;
+ }
+ }
+}
+
+void Mars::checkContinuePoint(const RoomID room, const DirectionConstant direction) {
+ switch (MakeRoomView(room, direction)) {
+ case MakeRoomView(kMars02, kSouth):
+ case MakeRoomView(kMars19, kEast):
+ case MakeRoomView(kMars22, kNorth):
+ case MakeRoomView(kMars43, kEast):
+ case MakeRoomView(kMars51, kEast):
+ case MakeRoomView(kMars56, kEast):
+ case MakeRoomView(kMars60, kWest):
+ case MakeRoomView(kMarsMaze004, kWest):
+ case MakeRoomView(kMarsMaze009, kWest):
+ case MakeRoomView(kMarsMaze012, kWest):
+ case MakeRoomView(kMarsMaze037, kWest):
+ case MakeRoomView(kMarsMaze047, kNorth):
+ case MakeRoomView(kMarsMaze052, kWest):
+ case MakeRoomView(kMarsMaze057, kNorth):
+ case MakeRoomView(kMarsMaze071, kWest):
+ case MakeRoomView(kMarsMaze081, kNorth):
+ case MakeRoomView(kMarsMaze088, kWest):
+ case MakeRoomView(kMarsMaze093, kWest):
+ case MakeRoomView(kMarsMaze115, kNorth):
+ case MakeRoomView(kMarsMaze120, kWest):
+ case MakeRoomView(kMarsMaze126, kEast):
+ case MakeRoomView(kMarsMaze133, kNorth):
+ case MakeRoomView(kMarsMaze144, kNorth):
+ case MakeRoomView(kMarsMaze156, kEast):
+ case MakeRoomView(kMarsMaze162, kNorth):
+ case MakeRoomView(kMarsMaze177, kWest):
+ case MakeRoomView(kMarsMaze180, kNorth):
+ case MakeRoomView(kMarsMaze187, kWest):
+ case MakeRoomView(kMarsMaze199, kWest):
+ makeContinuePoint();
+ break;
+ case MakeRoomView(kMars05, kEast):
+ case MakeRoomView(kMars06, kEast):
+ case MakeRoomView(kMars07, kEast):
+ if (GameState.getMarsSecurityDown())
+ makeContinuePoint();
+ break;
+ case MakeRoomView(kMars46, kSouth):
+ if (!GameState.getMarsSeenRobotAtReactor())
+ makeContinuePoint();
+ break;
+ case MakeRoomView(kMars46, kWest):
+ if (GameState.getMarsAvoidedReactorRobot())
+ makeContinuePoint();
+ break;
+ }
+}
+
+void Mars::launchMaze007Robot() {
+ startExtraLongSequence(kMarsMaze007RobotApproach, kMarsMaze007RobotDeath, kExtraCompletedFlag, kFilterAllInput);
+ scheduleEvent(kMaze007RobotLoopingTime, kMarsMovieScale, kMaze007RobotLoopingEvent);
+}
+
+void Mars::launchMaze015Robot() {
+ startExtraLongSequence(kMarsMaze015SouthRobotApproach, kMarsMaze015SouthRobotDeath, kExtraCompletedFlag, kFilterAllInput);
+ scheduleEvent(kMaze015RobotLoopingTime, kMarsMovieScale, kMaze015RobotLoopingEvent);
+}
+
+void Mars::launchMaze101Robot() {
+ startExtraLongSequence(kMarsMaze101EastRobotApproach, kMarsMaze101EastRobotDeath, kExtraCompletedFlag, kFilterAllInput);
+ scheduleEvent(kMaze101RobotLoopingTime, kMarsMovieScale, kMaze101RobotLoopingEvent);
+}
+
+void Mars::launchMaze104Robot() {
+ startExtraLongSequence(kMarsMaze104WestLoop, kMarsMaze104WestDeath, kExtraCompletedFlag, kFilterAllInput);
+ scheduleEvent(kMaze104RobotLoopingTime, kMarsMovieScale, kMaze104RobotLoopingEvent);
+}
+
+void Mars::launchMaze133Robot() {
+ startExtraLongSequence(kMarsMaze133SouthApproach, kMarsMaze133SouthDeath, kExtraCompletedFlag, kFilterAllInput);
+ scheduleEvent(kMaze133RobotLoopingTime, kMarsMovieScale, kMaze133RobotLoopingEvent);
+}
+
+void Mars::launchMaze136Robot() {
+ startExtraLongSequence(kMarsMaze136NorthApproach, kMarsMaze136NorthDeath, kExtraCompletedFlag, kFilterAllInput);
+ scheduleEvent(kMaze136RobotLoopingTime, kMarsMovieScale, kMaze136RobotLoopingEvent);
+}
+
+void Mars::launchMaze184Robot() {
+ startExtraLongSequence(kMarsMaze184WestLoop, kMarsMaze184WestDeath, kExtraCompletedFlag, kFilterAllInput);
+ scheduleEvent(kMaze184RobotLoopingTime, kMarsMovieScale, kMaze184RobotLoopingEvent);
+}
+
+void Mars::timerExpired(const uint32 eventType) {
+ switch (eventType) {
+ case kMaze007RobotLoopingEvent:
+ case kMaze015RobotLoopingEvent:
+ case kMaze101RobotLoopingEvent:
+ case kMaze104RobotLoopingEvent:
+ case kMaze133RobotLoopingEvent:
+ case kMaze136RobotLoopingEvent:
+ case kMaze184RobotLoopingEvent:
+ _interruptionFilter = kFilterNoInput;
+ break;
+ }
+}
+
+void Mars::arriveAt(const RoomID room, const DirectionConstant direction) {
+ switch (MakeRoomView(room, direction)) {
+ case MakeRoomView(kMars18, kNorth):
+ if (GameState.getMarsPodAtUpperPlatform())
+ setCurrentAlternate(kAltMarsPodAtMars34);
+ break;
+ case MakeRoomView(kMars27, kEast):
+ case MakeRoomView(kMars29, kEast):
+ if (GameState.isTakenItemID(kMarsCard))
+ setCurrentAlternate(kAltMarsTookCard);
+ else
+ setCurrentAlternate(kAltMarsNormal);
+ break;
+ case MakeRoomView(kMars35, kEast):
+ case MakeRoomView(kMars35, kWest):
+ if (GameState.getMarsAirlockOpen())
+ setCurrentAlternate(kAltMars35AirlockWest);
+ else
+ setCurrentAlternate(kAltMars35AirlockEast);
+ break;
+ case MakeRoomView(kMars60, kEast):
+ case MakeRoomView(kMars60, kWest):
+ if (GameState.getMarsAirlockOpen())
+ setCurrentAlternate(kAltMars60AirlockEast);
+ else
+ setCurrentAlternate(kAltMars60AirlockWest);
+ break;
+ case MakeRoomView(kMars45, kNorth):
+ case MakeRoomView(kMars45, kSouth):
+ case MakeRoomView(kMars45, kEast):
+ case MakeRoomView(kMars45, kWest):
+ GameState.setMarsPodAtUpperPlatform(false);
+ setCurrentAlternate(kAltMarsPodAtMars45);
+ break;
+ case MakeRoomView(kMars46, kNorth):
+ case MakeRoomView(kMars46, kSouth):
+ case MakeRoomView(kMars46, kEast):
+ case MakeRoomView(kMars46, kWest):
+ case MakeRoomView(kMars47, kNorth):
+ case MakeRoomView(kMars47, kSouth):
+ case MakeRoomView(kMars47, kEast):
+ case MakeRoomView(kMars47, kWest):
+ if (GameState.getMarsPodAtUpperPlatform())
+ setCurrentAlternate(kAltMarsNormal);
+ else
+ setCurrentAlternate(kAltMarsPodAtMars45);
+ break;
+ case MakeRoomView(kMars48, kNorth):
+ case MakeRoomView(kMars48, kSouth):
+ case MakeRoomView(kMars48, kEast):
+ case MakeRoomView(kMars48, kWest):
+ case MakeRoomView(kMars49, kNorth):
+ case MakeRoomView(kMars49, kEast):
+ case MakeRoomView(kMars49, kWest):
+ if (GameState.isTakenItemID(kAirMask))
+ setCurrentAlternate(kAltMarsTookMask);
+ else
+ setCurrentAlternate(kAltMarsNormal);
+ break;
+ case MakeRoomView(kMars49, kSouth):
+ if (GameState.getMarsMaskOnFiller())
+ setCurrentAlternate(kAltMarsMaskOnFiller);
+ else if (GameState.isTakenItemID(kAirMask))
+ setCurrentAlternate(kAltMarsTookMask);
+ else
+ setCurrentAlternate(kAltMarsNormal);
+ break;
+ }
+
+ Neighborhood::arriveAt(room, direction);
+ checkAirlockDoors();
+ setUpReactorEnergyDrain();
+
+ switch (MakeRoomView(room, direction)) {
+ case MakeRoomView(kMars0A, kNorth):
+ if (!GameState.getMarsSeenTimeStream())
+ startExtraLongSequence(kMarsArrivalFromTSA, kMars0AWatchShuttleDepart, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case MakeRoomView(kMars07, kSouth):
+ case MakeRoomView(kMars13, kNorth):
+ if (!GameState.getMarsHeardCheckInMessage()) {
+ playSpotSoundSync(kMarsCheckInRequiredIn, kMarsCheckInRequiredOut);
+ GameState.setMarsHeardCheckInMessage(true);
+ }
+ break;
+ case MakeRoomView(kMars44, kWest):
+ if (GameState.getMarsReadyForShuttleTransport())
+ startUpFromFinishedSpaceChase();
+ else if (GameState.getMarsFinishedCanyonChase())
+ startUpFromSpaceChase();
+ else
+ _neighborhoodNotification.setNotificationFlags(kTimeForCanyonChaseFlag, kTimeForCanyonChaseFlag);
+ break;
+ case MakeRoomView(kMars10, kNorth):
+ if (!GameState.getMarsRobotThrownPlayer())
+ startExtraSequence(kRobotThrowsPlayer, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case MakeRoomView(kMars11, kSouth):
+ case MakeRoomView(kMars12, kSouth):
+ setCurrentActivation(kActivationReadyForKiosk);
+ break;
+ case MakeRoomView(kMars15, kWest):
+ if (GameState.getMarsThreadedMaze() && !GameState.getMarsSecurityDown()) {
+ playSpotSoundSync(kMarsShuttle2DepartedIn, kMarsShuttle2DepartedOut);
+ restoreStriding(kMars17, kWest, kAltMarsNormal);
+ GameState.setMarsSecurityDown(true);
+ }
+ break;
+ case MakeRoomView(kMars17, kNorth):
+ case MakeRoomView(kMars17, kSouth):
+ case MakeRoomView(kMars17, kEast):
+ case MakeRoomView(kMars17, kWest):
+ if (GameState.getMarsThreadedMaze() && !GameState.getMarsSecurityDown())
+ forceStridingStop(kMars17, kWest, kAltMarsNormal);
+
+ if (GameState.getMarsThreadedMaze() && !GameState.getMarsSawRobotLeave()) {
+ startExtraSequence(kRobotOnWayToShuttle, kExtraCompletedFlag, kFilterNoInput);
+ restoreStriding(kMars19, kWest, kAltMarsNormal);
+ GameState.setMarsSawRobotLeave(true);
+ }
+ break;
+ case MakeRoomView(kMars19, kNorth):
+ case MakeRoomView(kMars19, kSouth):
+ case MakeRoomView(kMars19, kWest):
+ if (GameState.getMarsThreadedMaze() && !GameState.getMarsSawRobotLeave())
+ forceStridingStop(kMars19, kWest, kAltMarsNormal);
+
+ if (GameState.getMarsThreadedMaze() && !GameState.getMarsSecurityDown())
+ forceStridingStop(kMars17, kWest, kAltMarsNormal);
+ break;
+ case MakeRoomView(kMars19, kEast):
+ if (GameState.getMarsThreadedMaze() && !GameState.getMarsSawRobotLeave())
+ forceStridingStop(kMars19, kWest, kAltMarsNormal);
+
+ if (GameState.getMarsThreadedMaze() && !GameState.getMarsSecurityDown())
+ forceStridingStop(kMars17, kWest, kAltMarsNormal);
+ break;
+ case MakeRoomView(kMars32, kNorth):
+ if (!GameState.getMarsPodAtUpperPlatform()) {
+ playSpotSoundSync(kMarsPodArrivedUpperPlatformIn, kMarsPodArrivedUpperPlatformOut);
+ GameState.setMarsPodAtUpperPlatform(true);
+ }
+ break;
+ case MakeRoomView(kMars33North, kNorth):
+ setCurrentActivation(kActivationTunnelMapReady);
+ // Fall through...
+ case MakeRoomView(kMars33, kSouth):
+ case MakeRoomView(kMars33, kEast):
+ case MakeRoomView(kMars33, kWest):
+ case MakeRoomView(kMars32, kSouth):
+ case MakeRoomView(kMars32, kEast):
+ case MakeRoomView(kMars32, kWest):
+ if (!GameState.getMarsPodAtUpperPlatform())
+ GameState.setMarsPodAtUpperPlatform(true);
+ break;
+ case MakeRoomView(kMars34, kNorth):
+ startExtraSequence(kMars34NorthPodGreeting, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case MakeRoomView(kMars34, kSouth):
+ case MakeRoomView(kMars45, kNorth):
+ setCurrentActivation(kActivateMarsPodClosed);
+ break;
+ case MakeRoomView(kMars35, kWest):
+ if (GameState.getMarsThreadedMaze() && !GameState.getMarsSecurityDown())
+ forceStridingStop(kMars19, kWest, kAltMarsNormal);
+ // Fall through...
+ case MakeRoomView(kMars60, kEast):
+ if (!GameState.getMarsAirlockOpen())
+ setCurrentActivation(kActivateReadyToPressurizeAirlock);
+ break;
+ case MakeRoomView(kMars35, kEast):
+ case MakeRoomView(kMars60, kWest):
+ if (GameState.getMarsAirlockOpen())
+ setCurrentActivation(kActivateReadyToPressurizeAirlock);
+ break;
+ case MakeRoomView(kMars39, kWest):
+ if (GameState.getLastRoom() == kMarsMaze200)
+ GameState.setMarsPodAtUpperPlatform(false);
+ break;
+ case MakeRoomView(kMars45, kSouth):
+ // Set up maze doors here.
+ // Doing it here makes sure that it will be the same if the player comes
+ // back out of the maze and goes back in, but will vary if
+ // the player comes back down to the maze a second time.
+ GameState.setMarsMazeDoorPair1(_vm->getRandomBit());
+ GameState.setMarsMazeDoorPair2(_vm->getRandomBit());
+ GameState.setMarsMazeDoorPair3(_vm->getRandomBit());
+ GameState.setMarsArrivedBelow(true);
+ break;
+ case MakeRoomView(kMars48, kEast):
+ if (!GameState.getMarsSeenRobotAtReactor()) {
+ // Preload the looping sound...
+ loadLoopSound2("Sounds/Mars/Robot Loop.aiff", 0, 0, 0);
+ startExtraSequence(kMars48RobotApproaches, kExtraCompletedFlag, kFilterNoInput);
+ } else if (!GameState.getMarsAvoidedReactorRobot()) {
+ loadLoopSound2("Sounds/Mars/Robot Loop.aiff", 0x100, 0, 0);
+ loopExtraSequence(kMars48RobotLoops);
+ _utilityFuse.primeFuse(kMarsRobotPatienceLimit);
+ _utilityFuse.setFunctor(new Common::Functor0Mem<void, Mars>(this, &Mars::robotTiredOfWaiting));
+ _utilityFuse.lightFuse();
+ }
+ break;
+ case MakeRoomView(kMars48, kSouth):
+ if (GameState.getMarsSeenRobotAtReactor() && !GameState.getMarsAvoidedReactorRobot()) {
+ loadLoopSound2("Sounds/Mars/Robot Loop.aiff", 0x100, 0, 0);
+ _utilityFuse.primeFuse(kMarsRobotPatienceLimit);
+ _utilityFuse.setFunctor(new Common::Functor0Mem<void, Mars>(this, &Mars::robotTiredOfWaiting));
+ _utilityFuse.lightFuse();
+ }
+ break;
+ case MakeRoomView(kMars49, kSouth):
+ if (GameState.getMarsSeenRobotAtReactor() && !GameState.getMarsAvoidedReactorRobot()) {
+ playSpotSoundSync(kMarsRobotTakesTransportIn, kMarsRobotTakesTransportOut);
+ playSpotSoundSync(kMarsPodDepartedLowerPlatformIn, kMarsPodDepartedLowerPlatformOut);
+ GameState.setMarsAvoidedReactorRobot(true);
+ GameState.setMarsPodAtUpperPlatform(true);
+ GameState.setScoringAvoidedRobot();
+ }
+
+ if (GameState.isTakenItemID(kAirMask))
+ setCurrentActivation(kActivateHotSpotAlways);
+ else if (GameState.getMarsMaskOnFiller())
+ setCurrentActivation(kActivateMaskOnFiller);
+ else
+ setCurrentActivation(kActivateMaskOnHolder);
+ break;
+ case MakeRoomView(kMars51, kWest):
+ case MakeRoomView(kMars50, kWest):
+ case MakeRoomView(kMars48, kWest):
+ if (GameState.getShieldOn())
+ g_shield->setItemState(kShieldNormal);
+ g_energyMonitor->setEnergyDrainRate(kEnergyDrainNormal);
+ _vm->resetEnergyDeathReason();
+ break;
+ case MakeRoomView(kMars52, kNorth):
+ case MakeRoomView(kMars52, kSouth):
+ case MakeRoomView(kMars52, kEast):
+ case MakeRoomView(kMars52, kWest):
+ case MakeRoomView(kMars54, kNorth):
+ case MakeRoomView(kMars54, kSouth):
+ case MakeRoomView(kMars54, kEast):
+ case MakeRoomView(kMars54, kWest):
+ case MakeRoomView(kMars56, kNorth):
+ case MakeRoomView(kMars56, kSouth):
+ case MakeRoomView(kMars56, kWest):
+ case MakeRoomView(kMars58, kNorth):
+ case MakeRoomView(kMars58, kSouth):
+ case MakeRoomView(kMars58, kEast):
+ case MakeRoomView(kMars58, kWest):
+ setCurrentActivation(kActivateReactorPlatformOut);
+ break;
+ case MakeRoomView(kMars56, kEast):
+ if (GameState.getMarsLockBroken()) {
+ setCurrentActivation(kActivateReactorAskOperation);
+ _privateFlags.setFlag(kMarsPrivatePlatformZoomedInFlag, true);
+ } else if (GameState.getMarsLockFrozen()) {
+ setCurrentActivation(kActivateReactorReadyForCrowBar);
+ _privateFlags.setFlag(kMarsPrivatePlatformZoomedInFlag, true);
+ _utilityFuse.primeFuse(kLockFreezeTimeLmit);
+ _utilityFuse.setFunctor(new Common::Functor0Mem<void, Mars>(this, &Mars::lockThawed));
+ _utilityFuse.lightFuse();
+ } else {
+ setCurrentActivation(kActivateReactorPlatformOut);
+ }
+ break;
+ case MakeRoomView(kMarsRobotShuttle, kEast):
+ setCurrentActivation(kActivationRobotHeadClosed);
+ break;
+ case MakeRoomView(kMarsMaze007, kNorth):
+ launchMaze007Robot();
+ break;
+ case MakeRoomView(kMarsMaze015, kSouth):
+ launchMaze015Robot();
+ break;
+ case MakeRoomView(kMarsMaze101, kEast):
+ launchMaze101Robot();
+ break;
+ case MakeRoomView(kMarsMaze104, kWest):
+ launchMaze104Robot();
+ break;
+ case MakeRoomView(kMarsMaze133, kSouth):
+ launchMaze133Robot();
+ break;
+ case MakeRoomView(kMarsMaze136, kNorth):
+ launchMaze136Robot();
+ break;
+ case MakeRoomView(kMarsMaze184, kWest):
+ launchMaze184Robot();
+ break;
+ case MakeRoomView(kMarsMaze199, kSouth):
+ GameState.setScoringThreadedMaze();
+ GameState.setMarsThreadedMaze(true);
+ break;
+ case MakeRoomView(kMarsDeathRoom, kNorth):
+ case MakeRoomView(kMarsDeathRoom, kSouth):
+ case MakeRoomView(kMarsDeathRoom, kEast):
+ case MakeRoomView(kMarsDeathRoom, kWest):
+ switch (GameState.getLastRoom()) {
+ case kMars39:
+ die(kDeathDidntLeaveBucket);
+ break;
+ case kMars46:
+ die(kDeathRunOverByPod);
+ break;
+ }
+ break;
+ }
+
+ checkAirMask();
+}
+
+void Mars::shieldOn() {
+ setUpReactorEnergyDrain();
+}
+
+void Mars::shieldOff() {
+ setUpReactorEnergyDrain();
+}
+
+void Mars::turnTo(const DirectionConstant direction) {
+ switch (MakeRoomView(GameState.getCurrentRoom(), direction)) {
+ case MakeRoomView(kMars27, kNorth):
+ case MakeRoomView(kMars27, kSouth):
+ case MakeRoomView(kMars27, kEast):
+ case MakeRoomView(kMars29, kNorth):
+ case MakeRoomView(kMars29, kSouth):
+ case MakeRoomView(kMars29, kEast):
+ if (GameState.isTakenItemID(kMarsCard))
+ setCurrentAlternate(kAltMarsTookCard);
+ break;
+ case MakeRoomView(kMars35, kNorth):
+ case MakeRoomView(kMars35, kSouth):
+ case MakeRoomView(kMars60, kNorth):
+ case MakeRoomView(kMars60, kSouth):
+ if (getCurrentActivation() == kActivateAirlockPressurized)
+ playSpotSoundSync(kMarsAirlockPressurizeIn, kMarsAirlockPressurizeOut);
+ break;
+ }
+
+ Neighborhood::turnTo(direction);
+
+ switch (MakeRoomView(GameState.getCurrentRoom(), direction)) {
+ case MakeRoomView(kMars11, kSouth):
+ case MakeRoomView(kMars12, kSouth):
+ setCurrentActivation(kActivationReadyForKiosk);
+ break;
+ case MakeRoomView(kMars18, kNorth):
+ if (GameState.getMarsPodAtUpperPlatform())
+ setCurrentAlternate(kAltMarsPodAtMars34);
+ break;
+ case MakeRoomView(kMars22, kSouth):
+ if (!GameState.getMarsHeardCheckInMessage()) {
+ playSpotSoundSync(kMarsCheckInRequiredIn, kMarsCheckInRequiredOut);
+ GameState.setMarsHeardCheckInMessage(true);
+ }
+ break;
+ case MakeRoomView(kMars34, kSouth):
+ case MakeRoomView(kMars45, kNorth):
+ setCurrentActivation(kActivateMarsPodClosed);
+ break;
+ case MakeRoomView(kMars34, kNorth):
+ startExtraSequence(kMars34NorthPodGreeting, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case MakeRoomView(kMars35, kEast):
+ case MakeRoomView(kMars60, kWest):
+ if (GameState.getMarsAirlockOpen())
+ setCurrentActivation(kActivateReadyToPressurizeAirlock);
+ break;
+ case MakeRoomView(kMars60, kEast):
+ if (!GameState.getMarsAirlockOpen())
+ setCurrentActivation(kActivateReadyToPressurizeAirlock);
+ break;
+ case MakeRoomView(kMars35, kWest):
+ if (!GameState.getMarsAirlockOpen())
+ setCurrentActivation(kActivateReadyToPressurizeAirlock);
+
+ // Do this here because this will be called after spinning the airlock after
+ // going through the gear room.
+ if (GameState.getMarsThreadedMaze())
+ GameState.setScoringThreadedGearRoom();
+ break;
+ case MakeRoomView(kMars48, kNorth):
+ if (GameState.getMarsSeenRobotAtReactor() && !GameState.getMarsAvoidedReactorRobot())
+ die(kDeathDidntGetOutOfWay);
+ break;
+ case MakeRoomView(kMars48, kEast):
+ if (!GameState.getMarsSeenRobotAtReactor()) {
+ // Preload the looping sound...
+ loadLoopSound2("Sounds/Mars/Robot Loop.aiff", 0, 0, 0);
+ startExtraSequence(kMars48RobotApproaches, kExtraCompletedFlag, kFilterNoInput);
+ } else if (!GameState.getMarsAvoidedReactorRobot()) {
+ loopExtraSequence(kMars48RobotLoops);
+ } else if (GameState.isTakenItemID(kAirMask)) {
+ setCurrentAlternate(kAltMarsTookMask);
+ } else {
+ setCurrentAlternate(kAltMarsNormal);
+ }
+ break;
+ case MakeRoomView(kMars48, kWest):
+ if (GameState.getMarsSeenRobotAtReactor() && !GameState.getMarsAvoidedReactorRobot())
+ die(kDeathDidntGetOutOfWay);
+ else if (GameState.isTakenItemID(kAirMask))
+ setCurrentAlternate(kAltMarsTookMask);
+ else
+ setCurrentAlternate(kAltMarsNormal);
+ break;
+ case MakeRoomView(kMars49, kSouth):
+ if (GameState.isTakenItemID(kAirMask))
+ setCurrentActivation(kActivateHotSpotAlways);
+ else
+ setCurrentActivation(kActivateMaskOnHolder);
+ break;
+ case MakeRoomView(kMars52, kNorth):
+ case MakeRoomView(kMars52, kSouth):
+ case MakeRoomView(kMars52, kEast):
+ case MakeRoomView(kMars52, kWest):
+ case MakeRoomView(kMars54, kNorth):
+ case MakeRoomView(kMars54, kSouth):
+ case MakeRoomView(kMars54, kEast):
+ case MakeRoomView(kMars54, kWest):
+ case MakeRoomView(kMars56, kNorth):
+ case MakeRoomView(kMars56, kSouth):
+ case MakeRoomView(kMars56, kEast):
+ case MakeRoomView(kMars56, kWest):
+ case MakeRoomView(kMars58, kNorth):
+ case MakeRoomView(kMars58, kSouth):
+ case MakeRoomView(kMars58, kEast):
+ case MakeRoomView(kMars58, kWest):
+ setCurrentActivation(kActivateReactorPlatformOut);
+ break;
+ case MakeRoomView(kMarsMaze007, kNorth):
+ launchMaze007Robot();
+ break;
+ case MakeRoomView(kMarsMaze015, kSouth):
+ launchMaze015Robot();
+ break;
+ case MakeRoomView(kMarsMaze101, kEast):
+ launchMaze101Robot();
+ break;
+ case MakeRoomView(kMarsMaze104, kWest):
+ launchMaze104Robot();
+ break;
+ case MakeRoomView(kMarsMaze133, kSouth):
+ launchMaze133Robot();
+ break;
+ case MakeRoomView(kMarsMaze136, kNorth):
+ launchMaze136Robot();
+ break;
+ case MakeRoomView(kMarsMaze184, kWest):
+ launchMaze184Robot();
+ break;
+ }
+}
+
+void Mars::activateOneHotspot(HotspotInfoTable::Entry &entry, Hotspot *hotspot) {
+ switch (hotspot->getObjectID()) {
+ case kMars57RedMoveSpotID:
+ case kMars57YellowMoveSpotID:
+ case kMars57GreenMoveSpotID:
+ if (!_choiceHighlight.choiceHighlighted(hotspot->getObjectID() - kMars57RedMoveSpotID))
+ hotspot->setActive();
+ break;
+ case kMars57BlueMoveSpotID:
+ if (_reactorStage >= 2 && !_choiceHighlight.choiceHighlighted(3))
+ hotspot->setActive();
+ break;
+ case kMars57PurpleMoveSpotID:
+ if (_reactorStage == 3 && !_choiceHighlight.choiceHighlighted(4))
+ hotspot->setActive();
+ break;
+ default:
+ Neighborhood::activateOneHotspot(entry, hotspot);
+ break;
+ }
+}
+
+void Mars::activateHotspots() {
+ InventoryItem *item;
+
+ Neighborhood::activateHotspots();
+
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kMars48, kEast):
+ if ((_navMovie.getFlags() & kLoopTimeBase) != 0 && _vm->getDragType() == kDragInventoryUse)
+ _vm->getAllHotspots().activateOneHotspot(kAttackRobotHotSpotID);
+ break;
+ case MakeRoomView(kMars56, kEast):
+ switch (getCurrentActivation()) {
+ case kActivateReactorReadyForNitrogen:
+ item = (InventoryItem *)_vm->getAllItems().findItemByID(kNitrogenCanister);
+ if (item->getItemState() != kNitrogenFull)
+ _vm->getAllHotspots().deactivateOneHotspot(kMars57DropNitrogenSpotID);
+ // Fall through...
+ case kActivateReactorReadyForCrowBar:
+ _vm->getAllHotspots().activateOneHotspot(kMars57CantOpenPanelSpotID);
+ break;
+ }
+ break;
+ case MakeRoomView(kMarsRobotShuttle, kEast):
+ if (_privateFlags.getFlag(kMarsPrivateGotMapChipFlag))
+ _vm->getAllHotspots().deactivateOneHotspot(kRobotShuttleMapChipSpotID);
+ else
+ _vm->getAllHotspots().activateOneHotspot(kRobotShuttleMapChipSpotID);
+
+ if (_privateFlags.getFlag(kMarsPrivateGotOpticalChipFlag))
+ _vm->getAllHotspots().deactivateOneHotspot(kRobotShuttleOpticalChipSpotID);
+ else
+ _vm->getAllHotspots().activateOneHotspot(kRobotShuttleOpticalChipSpotID);
+
+ if (_privateFlags.getFlag(kMarsPrivateGotShieldChipFlag))
+ _vm->getAllHotspots().deactivateOneHotspot(kRobotShuttleShieldChipSpotID);
+ else
+ _vm->getAllHotspots().activateOneHotspot(kRobotShuttleShieldChipSpotID);
+ break;
+ default:
+ if (_privateFlags.getFlag(kMarsPrivateInSpaceChaseFlag)) {
+ if (GameState.getMarsReadyForShuttleTransport()) {
+ _shuttleTransportSpot.setActive();
+ } else {
+ _energyChoiceSpot.setActive();
+ _gravitonChoiceSpot.setActive();
+ _tractorChoiceSpot.setActive();
+ if (_weaponSelection != kNoWeapon)
+ _shuttleViewSpot.setActive();
+ }
+ }
+ break;
+ }
+}
+
+void Mars::clickInHotspot(const Input &input, const Hotspot *clickedSpot) {
+ switch (clickedSpot->getObjectID()) {
+ case kMars11NorthKioskSpotID:
+ case kMars12NorthKioskSpotID:
+ playSpotSoundSync(kMarsKioskBeepIn, kMarsKioskBeepOut);
+ Neighborhood::clickInHotspot(input, clickedSpot);
+ break;
+ case kMars11NorthKioskSightsSpotID:
+ case kMars12NorthKioskSightsSpotID:
+ playSpotSoundSync(kMarsKioskBeepIn, kMarsKioskBeepOut);
+ if (!startExtraSequenceSync(kMarsSightsInfo, kFilterAllInput))
+ showExtraView(kMarsInfoKioskIntro);
+ break;
+ case kMars11NorthKioskColonySpotID:
+ case kMars12NorthKioskColonySpotID:
+ playSpotSoundSync(kMarsKioskBeepIn, kMarsKioskBeepOut);
+ if (!startExtraSequenceSync(kMarsColonyInfo, kFilterAllInput))
+ showExtraView(kMarsInfoKioskIntro);
+ break;
+ case kMars33NorthMonitorSpotID:
+ switch (_lastExtra) {
+ case kMars33SlideShow1:
+ startExtraSequence(kMars33SlideShow2, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kMars33SlideShow2:
+ startExtraSequence(kMars33SlideShow3, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kMars33SlideShow3:
+ startExtraSequence(kMars33SlideShow4, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kMars33SlideShow4:
+ // Should never happen...
+ default:
+ startExtraSequence(kMars33SlideShow1, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ }
+ break;
+ case kMars34SouthOpenStorageSpotID:
+ if (GameState.isTakenItemID(kCrowbar))
+ startExtraSequence(kMars34SpotOpenNoBar, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kMars34SpotOpenWithBar, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kMars34SouthCloseStorageSpotID:
+ if (GameState.isTakenItemID(kCrowbar))
+ startExtraSequence(kMars34SpotCloseNoBar, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kMars34SpotCloseWithBar, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kMars35WestPressurizeSpotID:
+ case kMars35EastPressurizeSpotID:
+ case kMars60WestPressurizeSpotID:
+ case kMars60EastPressurizeSpotID:
+ playSpotSoundSync(kMarsAirlockButtonBeepIn, kMarsAirlockButtonBeepOut);
+ playSpotSoundSync(kMarsAirlockPressurizeIn, kMarsAirlockPressurizeOut);
+ setCurrentActivation(kActivateAirlockPressurized);
+ break;
+ case kMars45NorthOpenStorageSpotID:
+ if (GameState.isTakenItemID(kCrowbar))
+ startExtraSequence(kMars45SpotOpenNoBar, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kMars45SpotOpenWithBar, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kMars45NorthCloseStorageSpotID:
+ if (GameState.isTakenItemID(kCrowbar))
+ startExtraSequence(kMars45SpotCloseNoBar, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kMars45SpotCloseWithBar, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kMars56ExtractSpotID:
+ if (GameState.isTakenItemID(kCardBomb)) {
+ startExtraSequence(kMars56ExtendNoBomb, kExtraCompletedFlag, kFilterNoInput);
+ setCurrentActivation(kActivateReactorPlatformIn);
+ } else {
+ startExtraSequence(kMars56ExtendWithBomb, kExtraCompletedFlag, kFilterNoInput);
+ setCurrentActivation(kActivateReactorAskLowerScreen);
+ }
+ break;
+ case kMars57UndoMoveSpotID:
+ playSpotSoundSync(kMarsColorMatchingButtonBeepIn, kMarsColorMatchingButtonBeepOut);
+ doUndoOneGuess();
+ break;
+ case kMars57RedMoveSpotID:
+ playSpotSoundSync(kMarsColorMatchingButtonBeepIn, kMarsColorMatchingButtonBeepOut);
+ doReactorGuess(0);
+ break;
+ case kMars57YellowMoveSpotID:
+ playSpotSoundSync(kMarsColorMatchingButtonBeepIn, kMarsColorMatchingButtonBeepOut);
+ doReactorGuess(1);
+ break;
+ case kMars57GreenMoveSpotID:
+ playSpotSoundSync(kMarsColorMatchingButtonBeepIn, kMarsColorMatchingButtonBeepOut);
+ doReactorGuess(2);
+ break;
+ case kMars57BlueMoveSpotID:
+ playSpotSoundSync(kMarsColorMatchingButtonBeepIn, kMarsColorMatchingButtonBeepOut);
+ doReactorGuess(3);
+ break;
+ case kMars57PurpleMoveSpotID:
+ playSpotSoundSync(kMarsColorMatchingButtonBeepIn, kMarsColorMatchingButtonBeepOut);
+ doReactorGuess(4);
+ break;
+ case kShuttleEnergySpotID:
+ case kShuttleGravitonSpotID:
+ case kShuttleTractorSpotID:
+ case kShuttleViewSpotID:
+ case kShuttleTransportSpotID:
+ spaceChaseClick(input, clickedSpot->getObjectID());
+ break;
+ default:
+ Neighborhood::clickInHotspot(input, clickedSpot);
+ break;
+ }
+}
+
+InputBits Mars::getInputFilter() {
+ InputBits result = Neighborhood::getInputFilter();
+
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kMars49, kSouth):
+ if (GameState.getMarsMaskOnFiller())
+ // Can't move when mask is on filler.
+ result &= ~kFilterAllDirections;
+ break;
+ case MakeRoomView(kMars52, kNorth):
+ case MakeRoomView(kMars52, kSouth):
+ case MakeRoomView(kMars52, kEast):
+ case MakeRoomView(kMars52, kWest):
+ case MakeRoomView(kMars54, kNorth):
+ case MakeRoomView(kMars54, kSouth):
+ case MakeRoomView(kMars54, kEast):
+ case MakeRoomView(kMars54, kWest):
+ case MakeRoomView(kMars56, kNorth):
+ case MakeRoomView(kMars56, kSouth):
+ case MakeRoomView(kMars56, kEast):
+ case MakeRoomView(kMars56, kWest):
+ case MakeRoomView(kMars58, kNorth):
+ case MakeRoomView(kMars58, kSouth):
+ case MakeRoomView(kMars58, kEast):
+ case MakeRoomView(kMars58, kWest):
+ if (_privateFlags.getFlag(kMarsPrivatePlatformZoomedInFlag))
+ // Can't move when platform is extended.
+ result &= ~kFilterAllDirections;
+ break;
+ case MakeRoomView(kMars44, kWest):
+ if (_canyonChaseMovie.isMovieValid() && _canyonChaseMovie.isRunning())
+ result &= ~kFilterAllDirections;
+ break;
+ }
+
+ return result;
+}
+
+// Only called when trying to pick up an item and the player can't (because
+// the inventory is too full or because the player lets go of the item before
+// dropping it into the inventory).
+Hotspot *Mars::getItemScreenSpot(Item *item, DisplayElement *element) {
+ HotSpotID destSpotID;
+
+ switch (item->getObjectID()) {
+ case kCardBomb:
+ destSpotID = kMars57GrabBombSpotID;
+ break;
+ case kMarsCard:
+ destSpotID = kMars31SouthCardSpotID;
+ break;
+ case kAirMask:
+ if (GameState.getMarsMaskOnFiller())
+ destSpotID = kMars49AirFillingDropSpotID;
+ else
+ destSpotID = kMars49AirMaskSpotID;
+ break;
+ case kCrowbar:
+ if (GameState.getCurrentRoom() == kMars34)
+ destSpotID = kMars34SouthCrowbarSpotID;
+ else
+ destSpotID = kMars45NorthCrowbarSpotID;
+ break;
+ case kMapBiochip:
+ destSpotID = kRobotShuttleMapChipSpotID;
+ break;
+ case kOpticalBiochip:
+ destSpotID = kRobotShuttleOpticalChipSpotID;
+ break;
+ case kShieldBiochip:
+ destSpotID = kRobotShuttleShieldChipSpotID;
+ break;
+ default:
+ destSpotID = kNoHotSpotID;
+ break;
+ }
+
+ if (destSpotID == kNoHotSpotID)
+ return Neighborhood::getItemScreenSpot(item, element);
+
+ return _vm->getAllHotspots().findHotspotByID(destSpotID);
+}
+
+void Mars::takeItemFromRoom(Item *item) {
+ switch (item->getObjectID()) {
+ case kAirMask:
+ setCurrentAlternate(kAltMarsTookMask);
+ break;
+ case kCardBomb:
+ _privateFlags.setFlag(kMarsPrivateDraggingBombFlag, true);
+ break;
+ case kMapBiochip:
+ _privateFlags.setFlag(kMarsPrivateGotMapChipFlag, true);
+ break;
+ case kShieldBiochip:
+ _privateFlags.setFlag(kMarsPrivateGotShieldChipFlag, true);
+ break;
+ case kOpticalBiochip:
+ _privateFlags.setFlag(kMarsPrivateGotOpticalChipFlag, true);
+ break;
+ }
+
+ Neighborhood::takeItemFromRoom(item);
+}
+
+void Mars::pickedUpItem(Item *item) {
+ switch (item->getObjectID()) {
+ case kAirMask:
+ setCurrentActivation(kActivateHotSpotAlways);
+ if (!GameState.getScoringGotOxygenMask()) {
+ g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Mars/XM48SB", false, kWarningInterruption);
+ GameState.setScoringGotOxygenMask();
+ }
+ break;
+ case kCrowbar:
+ GameState.setScoringGotCrowBar();
+ g_AIArea->checkMiddleArea();
+ break;
+ case kMarsCard:
+ GameState.setScoringGotMarsCard();
+ g_AIArea->checkMiddleArea();
+ break;
+ case kCardBomb:
+ GameState.setScoringGotCardBomb();
+ if (GameState.getMarsLockBroken()) {
+ startExtraSequence(kMars57BackToNormal, kExtraCompletedFlag, kFilterNoInput);
+ GameState.setMarsLockBroken(false);
+ }
+
+ _privateFlags.setFlag(kMarsPrivateDraggingBombFlag, false);
+ break;
+ case kMapBiochip:
+ if (_privateFlags.getFlag(kMarsPrivateGotMapChipFlag) &&
+ _privateFlags.getFlag(kMarsPrivateGotShieldChipFlag) &&
+ _privateFlags.getFlag(kMarsPrivateGotOpticalChipFlag)) {
+ GameState.setMarsFinished(true);
+ GameState.setScoringMarsGandhi();
+ startExtraSequence(kMarsRobotHeadClose, kExtraCompletedFlag, kFilterNoInput);
+ }
+ break;
+ case kShieldBiochip:
+ if (_privateFlags.getFlag(kMarsPrivateGotMapChipFlag) &&
+ _privateFlags.getFlag(kMarsPrivateGotShieldChipFlag) &&
+ _privateFlags.getFlag(kMarsPrivateGotOpticalChipFlag)) {
+ GameState.setMarsFinished(true);
+ GameState.setScoringMarsGandhi();
+ startExtraSequence(kMarsRobotHeadClose, kExtraCompletedFlag, kFilterNoInput);
+ }
+ break;
+ case kOpticalBiochip:
+ g_opticalChip->addAries();
+ GameState.setScoringGotMarsOpMemChip();
+
+ if (_privateFlags.getFlag(kMarsPrivateGotMapChipFlag) &&
+ _privateFlags.getFlag(kMarsPrivateGotShieldChipFlag) &&
+ _privateFlags.getFlag(kMarsPrivateGotOpticalChipFlag)) {
+ GameState.setMarsFinished(true);
+ GameState.setScoringMarsGandhi();
+ startExtraSequence(kMarsRobotHeadClose, kExtraCompletedFlag, kFilterNoInput);
+ }
+ break;
+ }
+}
+
+void Mars::dropItemIntoRoom(Item *item, Hotspot *dropSpot) {
+ if (dropSpot->getObjectID() == kAttackRobotHotSpotID) {
+ _attackingItem = (InventoryItem *)item;
+ startExtraSequence(kMars48RobotDefends, kExtraCompletedFlag, kFilterNoInput);
+ loadLoopSound2("");
+ } else {
+ switch (item->getObjectID()) {
+ case kMarsCard:
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ if (dropSpot && dropSpot->getObjectID() == kMars34NorthCardDropSpotID)
+ startExtraSequence(kMarsTurnOnPod, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kNitrogenCanister:
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ if (dropSpot && dropSpot->getObjectID() == kMars57DropNitrogenSpotID)
+ startExtraSequence(kMars57FreezeLock, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kCrowbar:
+ _utilityFuse.stopFuse();
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ if (dropSpot && dropSpot->getObjectID() == kMars57DropCrowBarSpotID)
+ startExtraSequence(kMars57BreakLock, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kAirMask:
+ if (dropSpot) {
+ if (dropSpot->getObjectID() == kMars49AirFillingDropSpotID) {
+ if (!GameState.getMarsMaskOnFiller()) {
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ startExtraSequence(kMars49SouthViewMaskFilling, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ setCurrentActivation(kActivateMaskOnFiller);
+ setCurrentAlternate(kAltMarsMaskOnFiller);
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ }
+ } else if (dropSpot->getObjectID() == kMars49AirMaskSpotID) {
+ setCurrentAlternate(kAltMarsNormal);
+ setCurrentActivation(kActivateMaskOnHolder);
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ }
+ }
+ break;
+ case kCardBomb:
+ _privateFlags.setFlag(kMarsPrivateDraggingBombFlag, false);
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ break;
+ case kMapBiochip:
+ _privateFlags.setFlag(kMarsPrivateGotMapChipFlag, false);
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ break;
+ case kShieldBiochip:
+ _privateFlags.setFlag(kMarsPrivateGotShieldChipFlag, false);
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ break;
+ case kOpticalBiochip:
+ _privateFlags.setFlag(kMarsPrivateGotOpticalChipFlag, false);
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ break;
+ default:
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ break;
+ }
+ }
+}
+
+void Mars::robotTiredOfWaiting() {
+ if (GameState.getCurrentRoomAndView() == MakeRoomView(kMars48, kEast)) {
+ if (_attackingItem) {
+ startExtraSequence(kMars48RobotKillsPlayer, kExtraCompletedFlag, kFilterNoInput);
+ loadLoopSound2("");
+ } else {
+ _privateFlags.setFlag(kMarsPrivateRobotTiredOfWaitingFlag, true);
+ }
+ } else {
+ die(kDeathDidntGetOutOfWay);
+ }
+}
+
+void Mars::turnLeft() {
+ if (isEventTimerRunning())
+ cancelEvent();
+
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kMars34, kSouth):
+ if (_privateFlags.getFlag(kMarsPrivatePodStorageOpenFlag)) {
+ _privateFlags.setFlag(kMarsPrivatePodTurnLeftFlag, true);
+ if (GameState.isTakenItemID(kCrowbar))
+ startExtraSequence(kMars34SpotCloseNoBar, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kMars34SpotCloseWithBar, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ Neighborhood::turnLeft();
+ }
+ break;
+ case MakeRoomView(kMars45, kNorth):
+ if (_privateFlags.getFlag(kMarsPrivatePodStorageOpenFlag)) {
+ _privateFlags.setFlag(kMarsPrivatePodTurnLeftFlag, true);
+ if (GameState.isTakenItemID(kCrowbar))
+ startExtraSequence(kMars45SpotCloseNoBar, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kMars45SpotCloseWithBar, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ Neighborhood::turnLeft();
+ }
+ break;
+ default:
+ Neighborhood::turnLeft();
+ break;
+ }
+}
+
+void Mars::turnRight() {
+ if (isEventTimerRunning())
+ cancelEvent();
+
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kMars34, kSouth):
+ if (_privateFlags.getFlag(kMarsPrivatePodStorageOpenFlag)) {
+ _privateFlags.setFlag(kMarsPrivatePodTurnRightFlag, true);
+ if (GameState.isTakenItemID(kCrowbar))
+ startExtraSequence(kMars34SpotCloseNoBar, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kMars34SpotCloseWithBar, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ Neighborhood::turnRight();
+ }
+ break;
+ case MakeRoomView(kMars45, kNorth):
+ if (_privateFlags.getFlag(kMarsPrivatePodStorageOpenFlag)) {
+ _privateFlags.setFlag(kMarsPrivatePodTurnRightFlag, true);
+ if (GameState.isTakenItemID(kCrowbar))
+ startExtraSequence(kMars45SpotCloseNoBar, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kMars45SpotCloseWithBar, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ Neighborhood::turnRight();
+ }
+ break;
+ default:
+ Neighborhood::turnRight();
+ break;
+ }
+}
+
+void Mars::receiveNotification(Notification *notification, const NotificationFlags flag) {
+ InventoryItem *item;
+
+ Neighborhood::receiveNotification(notification, flag);
+
+ if ((flag & kExtraCompletedFlag) != 0) {
+ _interruptionFilter = kFilterAllInput;
+
+ switch (_lastExtra) {
+ case kMarsArrivalFromTSA:
+ GameState.setMarsSeenTimeStream(true);
+ loadAmbientLoops();
+ playSpotSoundSync(kMarsShuttle1DepartedIn, kMarsShuttle1DepartedOut);
+ makeContinuePoint();
+ break;
+ case kRobotThrowsPlayer:
+ GameState.setMarsRobotThrownPlayer(true);
+ GameState.setScoringThrownByRobot();
+ restoreStriding(kMars08, kNorth, kAltMarsNormal);
+ arriveAt(kMars08, kNorth);
+ if (!GameState.getMarsHeardUpperPodMessage()) {
+ playSpotSoundSync(kMarsPodDepartedUpperPlatformIn,
+ kMarsPodDepartedUpperPlatformOut);
+ GameState.setMarsHeardUpperPodMessage(true);
+ }
+ break;
+ case kMarsInfoKioskIntro:
+ GameState.setScoringSawMarsKiosk();
+ setCurrentActivation(kActivationKioskChoice);
+ break;
+ case kMars33SlideShow4:
+ GameState.setScoringSawTransportMap();
+ setCurrentActivation(kActivateHotSpotAlways);
+ break;
+ case kMars34SpotOpenNoBar:
+ case kMars34SpotOpenWithBar:
+ case kMars45SpotOpenNoBar:
+ case kMars45SpotOpenWithBar:
+ _privateFlags.setFlag(kMarsPrivatePodStorageOpenFlag, true);
+ setCurrentActivation(kActivateMarsPodOpen);
+ break;
+ case kMars34SpotCloseNoBar:
+ case kMars34SpotCloseWithBar:
+ case kMars45SpotCloseNoBar:
+ case kMars45SpotCloseWithBar:
+ _privateFlags.setFlag(kMarsPrivatePodStorageOpenFlag, false);
+ setCurrentActivation(kActivateMarsPodClosed);
+ if (_privateFlags.getFlag(kMarsPrivatePodTurnLeftFlag)) {
+ _privateFlags.setFlag(kMarsPrivatePodTurnLeftFlag, false);
+ turnLeft();
+ } else if (_privateFlags.getFlag(kMarsPrivatePodTurnRightFlag)) {
+ _privateFlags.setFlag(kMarsPrivatePodTurnRightFlag, false);
+ turnRight();
+ }
+ break;
+ case kMarsTurnOnPod:
+ item = (InventoryItem *)_vm->getAllItems().findItemByID(kMarsCard);
+ _vm->addItemToInventory(item);
+ GameState.setScoringTurnedOnTransport();
+ loadLoopSound1("");
+ loadLoopSound2("");
+ startExtraSequence(kMarsTakePodToMars45, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kMarsTakePodToMars45:
+ arriveAt(kMars45, kSouth);
+ break;
+ case kMars35WestSpinAirlockToEast:
+ GameState.setMarsAirlockOpen(false);
+ setCurrentAlternate(kAltMars35AirlockEast);
+ turnTo(kWest);
+ setCurrentActivation(kActivateReadyToPressurizeAirlock);
+ g_airMask->airQualityChanged();
+ checkAirMask();
+ loadAmbientLoops();
+ break;
+ case kMars35EastSpinAirlockToWest:
+ GameState.setMarsAirlockOpen(true);
+ setCurrentAlternate(kAltMars35AirlockWest);
+ turnTo(kEast);
+ setCurrentActivation(kActivateReadyToPressurizeAirlock);
+ g_airMask->airQualityChanged();
+ checkAirMask();
+ loadAmbientLoops();
+ break;
+ case kMars48RobotApproaches:
+ loadLoopSound2("Sounds/Mars/Robot Loop.aiff", 0x100, 0, 0);
+ GameState.setMarsSeenRobotAtReactor(true);
+ loopExtraSequence(kMars48RobotLoops);
+ _utilityFuse.primeFuse(kMarsRobotPatienceLimit);
+ _utilityFuse.setFunctor(new Common::Functor0Mem<void, Mars>(this, &Mars::robotTiredOfWaiting));
+ _utilityFuse.lightFuse();
+ break;
+ case kMars48RobotDefends:
+ _vm->addItemToInventory(_attackingItem);
+ _attackingItem = 0;
+ if (_privateFlags.getFlag(kMarsPrivateRobotTiredOfWaitingFlag)) {
+ startExtraSequence(kMars48RobotKillsPlayer, kExtraCompletedFlag, kFilterNoInput);
+ loadLoopSound2("", 0x100, 0, 0);
+ } else {
+ loadLoopSound2("Sounds/Mars/Robot Loop.aiff", 0x100, 0, 0);
+ loopExtraSequence(kMars48RobotLoops, kExtraCompletedFlag);
+ }
+ break;
+ case kMars48RobotKillsPlayer:
+ loadLoopSound2("");
+ die(kDeathDidntGetOutOfWay);
+ break;
+ case kMars49SouthViewMaskFilling:
+ setCurrentActivation(kActivateMaskOnFiller);
+ setCurrentAlternate(kAltMarsMaskOnFiller);
+ GameState.setMarsMaskOnFiller(true);
+ break;
+ case kMars58SpinLeft:
+ case kMars54SpinRight:
+ GameState.setScoringActivatedPlatform();
+ arriveAt(kMars52, kEast);
+ break;
+ case kMars52SpinLeft:
+ case kMars56SpinRight:
+ GameState.setScoringActivatedPlatform();
+ arriveAt(kMars54, kEast);
+ break;
+ case kMars54SpinLeft:
+ case kMars58SpinRight:
+ GameState.setScoringActivatedPlatform();
+ arriveAt(kMars56, kEast);
+ break;
+ case kMars56SpinLeft:
+ case kMars52SpinRight:
+ GameState.setScoringActivatedPlatform();
+ arriveAt(kMars58, kEast);
+ break;
+ case kMars52Extend:
+ case kMars54Extend:
+ case kMars56ExtendNoBomb:
+ case kMars58Extend:
+ GameState.setScoringActivatedPlatform();
+ setCurrentActivation(kActivateReactorPlatformIn);
+ _privateFlags.setFlag(kMarsPrivatePlatformZoomedInFlag, true);
+ break;
+ case kMars53Retract:
+ case kMars55Retract:
+ case kMars57RetractWithBomb:
+ case kMars57RetractNoBomb:
+ case kMars59Retract:
+ GameState.setScoringActivatedPlatform();
+ setCurrentActivation(kActivateReactorPlatformOut);
+ _privateFlags.setFlag(kMarsPrivatePlatformZoomedInFlag, false);
+ break;
+ case kMars56ExtendWithBomb:
+ playSpotSoundSync(kMustBeUnlockedIn, kMustBeUnlockedOut);
+ GameState.setScoringActivatedPlatform();
+ _privateFlags.setFlag(kMarsPrivatePlatformZoomedInFlag, true);
+ break;
+ case kMars57CantOpenPanel:
+ GameState.setScoringActivatedPlatform();
+ setCurrentActivation(kActivateReactorAskLowerScreen);
+ break;
+ case kMars57LowerScreenClosed:
+ case kMars57ThawLock:
+ setCurrentActivation(kActivateReactorReadyForNitrogen);
+ GameState.setMarsLockFrozen(false);
+ break;
+ case kMars57FreezeLock:
+ item = (InventoryItem *)_vm->getAllItems().findItemByID(kNitrogenCanister);
+ item->setItemState(kNitrogenEmpty);
+ _vm->addItemToInventory(item);
+ setCurrentActivation(kActivateReactorReadyForCrowBar);
+ GameState.setScoringUsedLiquidNitrogen();
+ GameState.setMarsLockFrozen(true);
+ showExtraView(kMars57LockFrozenView);
+ _utilityFuse.primeFuse(kLockFreezeTimeLmit);
+ _utilityFuse.setFunctor(new Common::Functor0Mem<void, Mars>(this, &Mars::lockThawed));
+ _utilityFuse.lightFuse();
+ break;
+ case kMars57BreakLock:
+ item = (InventoryItem *)_vm->getAllItems().findItemByID(kCrowbar);
+ _vm->addItemToInventory(item);
+ GameState.setScoringUsedCrowBar();
+ GameState.setMarsLockBroken(true);
+ GameState.setMarsLockFrozen(false);
+ startExtraLongSequence(kMars57OpenPanel, kMars57OpenPanelChoices, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kMars57OpenPanel:
+ case kMars57OpenPanelChoices:
+ setCurrentActivation(kActivateReactorAskOperation);
+ break;
+ case kMars57ShieldEvaluation:
+ case kMars57MeasureOutput:
+ setCurrentActivation(kActivateReactorRanEvaluation);
+ loopExtraSequence(kMars57ShieldOkayLoop);
+ break;
+ case kMars57RunDiagnostics:
+ setCurrentActivation(kActivateReactorRanDiagnostics);
+ GameState.setScoringFoundCardBomb();
+ break;
+ case kMars57BombExplodes:
+ case kMars57BombExplodesInGame:
+ die(kDeathDidntDisarmMarsBomb);
+ break;
+ case kMars57BombAnalysis:
+ setCurrentActivation(kActivateReactorAnalyzed);
+ break;
+ case kMars57DontLink:
+ startExtraSequence(kMars57OpenPanelChoices, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kMars57CircuitLink:
+ setCurrentActivation(kActivateReactorInstructions);
+ break;
+ case kMars57GameLevel1:
+ setUpReactorLevel1();
+ break;
+ case kMars57GameLevel2:
+ case kMars57GameLevel3:
+ setUpNextReactorLevel();
+ break;
+ case kMars57GameSolved:
+ setCurrentActivation(kActivateReactorBombSafe);
+ break;
+ case kMars57ExposeBomb:
+ setCurrentActivation(kActivateReactorBombExposed);
+ _privateFlags.setFlag(kMarsPrivateBombExposedFlag, true);
+ break;
+ case kMars57BackToNormal:
+ setCurrentActivation(kActivateReactorPlatformIn);
+ _privateFlags.setFlag(kMarsPrivateBombExposedFlag, false);
+ g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Mars/XM51SW", false, kWarningInterruption);
+ break;
+ case kMars60WestSpinAirlockToEast:
+ GameState.setMarsAirlockOpen(true);
+ setCurrentAlternate(kAltMars60AirlockEast);
+ turnTo(kWest);
+ setCurrentActivation(kActivateReadyToPressurizeAirlock);
+ g_airMask->airQualityChanged();
+ checkAirMask();
+ loadAmbientLoops();
+ break;
+ case kMars60EastSpinAirlockToWest:
+ GameState.setMarsAirlockOpen(false);
+ setCurrentAlternate(kAltMars60AirlockWest);
+ turnTo(kEast);
+ setCurrentActivation(kActivateReadyToPressurizeAirlock);
+ g_airMask->airQualityChanged();
+ checkAirMask();
+ loadAmbientLoops();
+ break;
+ case kMarsRobotHeadOpen:
+ setCurrentActivation(kActivationRobotHeadOpen);
+ break;
+ case kMarsRobotHeadClose:
+ recallToTSASuccess();
+ break;
+ case kMarsMaze007RobotApproach:
+ case kMarsMaze015SouthRobotApproach:
+ case kMarsMaze101EastRobotApproach:
+ case kMarsMaze104WestLoop:
+ case kMarsMaze133SouthApproach:
+ case kMarsMaze136NorthApproach:
+ case kMarsMaze184WestLoop:
+ die(kDeathGroundByMazebot);
+ break;
+ }
+ } else if ((flag & kTimeForCanyonChaseFlag) != 0) {
+ doCanyonChase();
+ } else if ((flag & kExplosionFinishedFlag) != 0) {
+ _explosions.stop();
+ _explosions.hide();
+ if (g_robotShip->isDead()) {
+ GameState.setMarsFinished(true);
+ _centerShuttleMovie.hide();
+ _upperRightShuttleMovie.show();
+ _upperRightShuttleMovie.setTime(kShuttleUpperRightTargetDestroyedTime);
+ _upperRightShuttleMovie.redrawMovieWorld();
+ _rightDamageShuttleMovie.hide();
+ playMovieSegment(&_rightShuttleMovie, kShuttleRightDestroyedStart, kShuttleRightDestroyedStop);
+ playSpotSoundSync(kShuttleDestroyedIn, kShuttleDestroyedOut);
+ throwAwayMarsShuttle();
+ reinstateMonocleInterface();
+ recallToTSASuccess();
+ }
+ } else if ((flag & kTimeToTransportFlag) != 0) {
+ transportToRobotShip();
+ }
+
+ if (g_AIArea)
+ g_AIArea->checkMiddleArea();
+}
+
+void Mars::spotCompleted() {
+ Neighborhood::spotCompleted();
+
+ if (GameState.getCurrentRoom() == kMarsRobotShuttle)
+ g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Mars/XN59WD", false, kWarningInterruption);
+}
+
+void Mars::doCanyonChase() {
+ GameState.setScoringEnteredShuttle();
+ setNextHandler(_vm);
+ throwAwayInterface();
+
+ _vm->_cursor->hide();
+
+ // Open the spot sounds movie again...
+ _spotSounds.initFromQuickTime(getSoundSpotsName());
+ _spotSounds.setVolume(_vm->getSoundFXLevel());
+
+ Video::VideoDecoder *video = new Video::QuickTimeDecoder();
+ 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();
+
+ if (frame)
+ _vm->drawScaledFrame(frame, 0, 0);
+ }
+
+ Common::Event event;
+ while (g_system->getEventManager()->pollEvent(event))
+ ;
+
+ g_system->delayMillis(10);
+ }
+
+ delete video;
+
+ if (_vm->shouldQuit())
+ return;
+
+ initOnePicture(&_shuttleInterface1, "Images/Mars/MCmain1.pict", kShuttleBackgroundOrder, kShuttle1Left,
+ kShuttle1Top, true);
+ initOnePicture(&_shuttleInterface2, "Images/Mars/MCmain2.pict", kShuttleBackgroundOrder, kShuttle2Left,
+ kShuttle2Top, true);
+ initOnePicture(&_shuttleInterface3, "Images/Mars/MCmain3.pict", kShuttleBackgroundOrder, kShuttle3Left,
+ kShuttle3Top, true);
+ initOnePicture(&_shuttleInterface4, "Images/Mars/MCmain4.pict", kShuttleBackgroundOrder, kShuttle4Left,
+ kShuttle4Top, true);
+
+ initOneMovie(&_canyonChaseMovie, "Images/Mars/Canyon.movie",
+ kShuttleMonitorOrder, kShuttleWindowLeft, kShuttleWindowTop, true);
+ _canyonChaseMovie.setVolume(_vm->getSoundFXLevel());
+
+ loadLoopSound1("Sounds/Mars/Inside Cockpit.22K.8.AIFF");
+
+ // Swing shuttle around...
+ playMovieSegment(&_canyonChaseMovie, kShuttleSwingStart, kShuttleSwingStop);
+
+ initOneMovie(&_leftShuttleMovie, "Images/Mars/Left Shuttle.movie",
+ kShuttleMonitorOrder, kShuttleLeftLeft, kShuttleLeftTop, false);
+
+ initOneMovie(&_rightShuttleMovie, "Images/Mars/Right Shuttle.movie",
+ kShuttleMonitorOrder, kShuttleRightLeft, kShuttleRightTop, false);
+
+ initOneMovie(&_lowerLeftShuttleMovie, "Images/Mars/Lower Left Shuttle.movie", kShuttleMonitorOrder,
+ kShuttleLowerLeftLeft, kShuttleLowerLeftTop, false);
+
+ initOneMovie(&_lowerRightShuttleMovie, "Images/Mars/Lower Right Shuttle.movie", kShuttleMonitorOrder,
+ kShuttleLowerRightLeft, kShuttleLowerRightTop, false);
+
+ initOneMovie(&_centerShuttleMovie, "Images/Mars/Center Shuttle.movie",
+ kShuttleMonitorOrder, kShuttleCenterLeft, kShuttleCenterTop, false);
+
+ initOneMovie(&_upperLeftShuttleMovie, "Images/Mars/Upper Left Shuttle.movie", kShuttleMonitorOrder,
+ kShuttleUpperLeftLeft, kShuttleUpperLeftTop, false);
+
+ initOneMovie(&_upperRightShuttleMovie, "Images/Mars/Upper Right Shuttle.movie", kShuttleMonitorOrder,
+ kShuttleUpperRightLeft, kShuttleUpperRightTop, false);
+
+ initOneMovie(&_leftDamageShuttleMovie, "Images/Mars/Left Damage Shuttle.movie",
+ kShuttleStatusOrder, kShuttleLeftEnergyLeft, kShuttleLeftEnergyTop, false);
+
+ initOneMovie(&_rightDamageShuttleMovie, "Images/Mars/Right Damage Shuttle.movie",
+ kShuttleStatusOrder, kShuttleRightEnergyLeft, kShuttleRightEnergyTop, false);
+
+ _centerShuttleMovie.show();
+ _centerShuttleMovie.setTime(kShuttleCenterBoardingTime);
+ playSpotSoundSync(kShuttleCockpitIn, kShuttleCockpitOut);
+
+ _centerShuttleMovie.setTime(kShuttleCenterCheckTime);
+ playSpotSoundSync(kShuttleOnboardIn, kShuttleOnboardOut);
+
+ _shuttleEnergyMeter.initShuttleEnergyMeter();
+ _shuttleEnergyMeter.powerUpMeter();
+ while (_shuttleEnergyMeter.isFading()) {
+ _vm->checkCallBacks();
+ _vm->refreshDisplay();
+ g_system->updateScreen();
+ }
+
+ _leftShuttleMovie.show();
+ playMovieSegment(&_leftShuttleMovie, kShuttleLeftIntroStart, kShuttleLeftIntroStop);
+
+ _leftShuttleMovie.setTime(kShuttleLeftNormalTime);
+ _leftShuttleMovie.redrawMovieWorld();
+
+ _leftDamageShuttleMovie.show();
+ playMovieSegment(&_leftDamageShuttleMovie);
+
+ // Take it down a tick initially. This sets the time to the time of the last tick,
+ // so that subsequence drops will drop it down a tick.
+ _leftDamageShuttleMovie.setTime(_leftDamageShuttleMovie.getTime() - 40);
+ _leftDamageShuttleMovie.redrawMovieWorld();
+
+ _lowerRightShuttleMovie.show();
+ _lowerRightShuttleMovie.setTime(kShuttleLowerRightOffTime);
+ _lowerRightShuttleMovie.redrawMovieWorld();
+ _centerShuttleMovie.setTime(kShuttleCenterNavCompTime);
+ _centerShuttleMovie.redrawMovieWorld();
+ playSpotSoundSync(kShuttleNavigationIn, kShuttleNavigationOut);
+
+ _centerShuttleMovie.setTime(kShuttleCenterCommTime);
+ _centerShuttleMovie.redrawMovieWorld();
+ playSpotSoundSync(kShuttleCommunicationIn, kShuttleCommunicationOut);
+
+ _centerShuttleMovie.setTime(kShuttleCenterAllSystemsTime);
+ _centerShuttleMovie.redrawMovieWorld();
+ playSpotSoundSync(kShuttleAllSystemsIn, kShuttleAllSystemsOut);
+
+ _centerShuttleMovie.setTime(kShuttleCenterSecureLooseTime);
+ _centerShuttleMovie.redrawMovieWorld();
+ playSpotSoundSync(kShuttleSecureLooseIn, kShuttleSecureLooseOut);
+
+ _centerShuttleMovie.setTime(kShuttleCenterAutoTestTime);
+ _centerShuttleMovie.redrawMovieWorld();
+ playSpotSoundSync(kShuttleAutoTestingIn, kShuttleAutoTestingOut);
+
+ _leftShuttleMovie.setTime(kShuttleLeftAutoTestTime);
+ _leftShuttleMovie.redrawMovieWorld();
+ playSpotSoundSync(kMarsThrusterAutoTestIn, kMarsThrusterAutoTestOut);
+ _leftShuttleMovie.setTime(kShuttleLeftNormalTime);
+ _leftShuttleMovie.redrawMovieWorld();
+
+ _centerShuttleMovie.setTime(kShuttleCenterLaunchTime);
+ _centerShuttleMovie.redrawMovieWorld();
+ playSpotSoundSync(kShuttlePrepareForDropIn, kShuttlePrepareForDropOut);
+
+ playSpotSoundSync(kShuttleAllClearIn, kShuttleAllClearOut);
+
+ _centerShuttleMovie.setTime(kShuttleCenterEnterTubeTime);
+ _centerShuttleMovie.redrawMovieWorld();
+
+ _lowerLeftShuttleMovie.show();
+ _lowerLeftShuttleMovie.setTime(kShuttleLowerLeftCollisionTime);
+
+ loadLoopSound1("");
+
+ _canyonChaseMovie.setSegment(kCanyonChaseStart, kCanyonChaseStop);
+ _canyonChaseMovie.start();
+
+ startMarsTimer(kLaunchTubeReachedTime, kMovieTicksPerSecond, kMarsLaunchTubeReached);
+}
+
+void Mars::startUpFromFinishedSpaceChase() {
+ setNextHandler(_vm);
+ throwAwayInterface();
+
+ initOnePicture(&_shuttleInterface1, "Images/Mars/MCmain1.pict", kShuttleBackgroundOrder, kShuttle1Left,
+ kShuttle1Top, true);
+ initOnePicture(&_shuttleInterface2, "Images/Mars/MCmain2.pict", kShuttleBackgroundOrder, kShuttle2Left,
+ kShuttle2Top, true);
+ initOnePicture(&_shuttleInterface3, "Images/Mars/MCmain3.pict", kShuttleBackgroundOrder, kShuttle3Left,
+ kShuttle3Top, true);
+ initOnePicture(&_shuttleInterface4, "Images/Mars/MCmain4.pict", kShuttleBackgroundOrder, kShuttle4Left,
+ kShuttle4Top, true);
+
+ initOneMovie(&_leftShuttleMovie, "Images/Mars/Left Shuttle.movie",
+ kShuttleMonitorOrder, kShuttleLeftLeft, kShuttleLeftTop, false);
+
+ initOneMovie(&_rightShuttleMovie, "Images/Mars/Right Shuttle.movie",
+ kShuttleMonitorOrder, kShuttleRightLeft, kShuttleRightTop, false);
+
+ initOneMovie(&_lowerLeftShuttleMovie, "Images/Mars/Lower Left Shuttle.movie", kShuttleMonitorOrder,
+ kShuttleLowerLeftLeft, kShuttleLowerLeftTop, false);
+
+ initOneMovie(&_lowerRightShuttleMovie, "Images/Mars/Lower Right Shuttle.movie", kShuttleMonitorOrder,
+ kShuttleLowerRightLeft, kShuttleLowerRightTop, false);
+
+ initOneMovie(&_centerShuttleMovie, "Images/Mars/Center Shuttle.movie",
+ kShuttleMonitorOrder, kShuttleCenterLeft, kShuttleCenterTop, false);
+
+ initOneMovie(&_upperLeftShuttleMovie, "Images/Mars/Upper Left Shuttle.movie", kShuttleMonitorOrder,
+ kShuttleUpperLeftLeft, kShuttleUpperLeftTop, false);
+
+ initOneMovie(&_upperRightShuttleMovie, "Images/Mars/Upper Right Shuttle.movie", kShuttleMonitorOrder,
+ kShuttleUpperRightLeft, kShuttleUpperRightTop, false);
+
+ initOneMovie(&_leftDamageShuttleMovie, "Images/Mars/Left Damage Shuttle.movie",
+ kShuttleStatusOrder, kShuttleLeftEnergyLeft, kShuttleLeftEnergyTop, false);
+
+ initOneMovie(&_rightDamageShuttleMovie, "Images/Mars/Right Damage Shuttle.movie",
+ kShuttleStatusOrder, kShuttleRightEnergyLeft, kShuttleRightEnergyTop, false);
+
+ _centerShuttleMovie.show();
+
+ _shuttleEnergyMeter.initShuttleEnergyMeter();
+ _shuttleEnergyMeter.setEnergyValue(kFullShuttleEnergy);
+
+ _leftShuttleMovie.show();
+ _leftShuttleMovie.setTime(kShuttleLeftNormalTime);
+ _leftShuttleMovie.redrawMovieWorld();
+
+ _leftDamageShuttleMovie.show();
+ _leftDamageShuttleMovie.setTime(_leftDamageShuttleMovie.getDuration() - 40);
+ _leftDamageShuttleMovie.redrawMovieWorld();
+
+ _lowerRightShuttleMovie.show();
+
+ _lowerLeftShuttleMovie.show();
+
+ loadLoopSound1("Sounds/Mars/Space Ambient.22K.8.AIFF");
+
+ initOneMovie(&_junk, "Images/Mars/Junk.movie", kShuttleJunkOrder, kShuttleJunkLeft,
+ kShuttleJunkTop, false);
+
+ initOneMovie(&_explosions, "Images/Mars/Explosions.movie", kShuttleWeaponFrontOrder, 0, 0, false);
+ _explosionCallBack.initCallBack(&_explosions, kCallBackAtExtremes);
+
+ _energyBeam.initShuttleWeapon();
+ _gravitonCannon.initShuttleWeapon();
+
+ _upperLeftShuttleMovie.show();
+ _upperLeftShuttleMovie.setTime(kShuttleUpperLeftDimTime);
+ _upperLeftShuttleMovie.redrawMovieWorld();
+
+ _rightShuttleMovie.show();
+ _rightShuttleMovie.setTime(kShuttleRightIntroStop - 1);
+ _rightShuttleMovie.redrawMovieWorld();
+
+ _rightDamageShuttleMovie.show();
+ _rightDamageShuttleMovie.setTime(40);
+ _rightDamageShuttleMovie.redrawMovieWorld();
+
+ _lowerLeftShuttleMovie.setTime(kShuttleLowerLeftAutopilotTime);
+ _lowerLeftShuttleMovie.redrawMovieWorld();
+
+ _shuttleTransportSpot.setArea(kShuttleTransportBounds);
+ _shuttleTransportSpot.setHotspotFlags(kNeighborhoodSpotFlag | kClickSpotFlag);
+ _vm->getAllHotspots().push_back(&_shuttleTransportSpot);
+
+ _privateFlags.setFlag(kMarsPrivateInSpaceChaseFlag, true);
+
+ _upperRightShuttleMovie.show();
+ _upperRightShuttleMovie.setTime(kShuttleUpperRightOverloadTime);
+ _upperRightShuttleMovie.redrawMovieWorld();
+
+ _centerShuttleMovie.setTime(kShuttleCenterSafeTime);
+ _centerShuttleMovie.redrawMovieWorld();
+
+ _lowerRightShuttleMovie.setTime(kShuttleLowerRightTransportTime);
+ _lowerRightShuttleMovie.redrawMovieWorld();
+
+ initOneMovie(&_canyonChaseMovie, "Images/Mars/M98EAS.movie", kShuttleTractorBeamMovieOrder,
+ kShuttleWindowLeft, kShuttleWindowTop, true);
+ _canyonChaseMovie.setTime(_canyonChaseMovie.getDuration());
+ _canyonChaseMovie.redrawMovieWorld();
+}
+
+void Mars::startUpFromSpaceChase() {
+ setNextHandler(_vm);
+ throwAwayInterface();
+
+ // Open the spot sounds movie again...
+ _spotSounds.initFromQuickTime(getSoundSpotsName());
+ _spotSounds.setVolume(_vm->getSoundFXLevel());;
+
+ initOnePicture(&_shuttleInterface1, "Images/Mars/MCmain1.pict", kShuttleBackgroundOrder, kShuttle1Left,
+ kShuttle1Top, true);
+ initOnePicture(&_shuttleInterface2, "Images/Mars/MCmain2.pict", kShuttleBackgroundOrder, kShuttle2Left,
+ kShuttle2Top, true);
+ initOnePicture(&_shuttleInterface3, "Images/Mars/MCmain3.pict", kShuttleBackgroundOrder, kShuttle3Left,
+ kShuttle3Top, true);
+ initOnePicture(&_shuttleInterface4, "Images/Mars/MCmain4.pict", kShuttleBackgroundOrder, kShuttle4Left,
+ kShuttle4Top, true);
+
+ initOneMovie(&_leftShuttleMovie, "Images/Mars/Left Shuttle.movie",
+ kShuttleMonitorOrder, kShuttleLeftLeft, kShuttleLeftTop, false);
+
+ initOneMovie(&_rightShuttleMovie, "Images/Mars/Right Shuttle.movie",
+ kShuttleMonitorOrder, kShuttleRightLeft, kShuttleRightTop, false);
+
+ initOneMovie(&_lowerLeftShuttleMovie, "Images/Mars/Lower Left Shuttle.movie", kShuttleMonitorOrder,
+ kShuttleLowerLeftLeft, kShuttleLowerLeftTop, false);
+
+ initOneMovie(&_lowerRightShuttleMovie, "Images/Mars/Lower Right Shuttle.movie", kShuttleMonitorOrder,
+ kShuttleLowerRightLeft, kShuttleLowerRightTop, false);
+
+ initOneMovie(&_centerShuttleMovie, "Images/Mars/Center Shuttle.movie",
+ kShuttleMonitorOrder, kShuttleCenterLeft, kShuttleCenterTop, false);
+
+ initOneMovie(&_upperLeftShuttleMovie, "Images/Mars/Upper Left Shuttle.movie", kShuttleMonitorOrder,
+ kShuttleUpperLeftLeft, kShuttleUpperLeftTop, false);
+
+ initOneMovie(&_upperRightShuttleMovie, "Images/Mars/Upper Right Shuttle.movie", kShuttleMonitorOrder,
+ kShuttleUpperRightLeft, kShuttleUpperRightTop, false);
+
+ initOneMovie(&_leftDamageShuttleMovie, "Images/Mars/Left Damage Shuttle.movie",
+ kShuttleStatusOrder, kShuttleLeftEnergyLeft, kShuttleLeftEnergyTop, false);
+
+ initOneMovie(&_rightDamageShuttleMovie, "Images/Mars/Right Damage Shuttle.movie",
+ kShuttleStatusOrder, kShuttleRightEnergyLeft, kShuttleRightEnergyTop, false);
+
+ _centerShuttleMovie.show();
+
+ _shuttleEnergyMeter.initShuttleEnergyMeter();
+ _shuttleEnergyMeter.setEnergyValue(kFullShuttleEnergy);
+
+ _leftShuttleMovie.show();
+ _leftShuttleMovie.setTime(kShuttleLeftNormalTime);
+ _leftShuttleMovie.redrawMovieWorld();
+
+ _leftDamageShuttleMovie.show();
+ _leftDamageShuttleMovie.setTime(_leftDamageShuttleMovie.getDuration() - 40);
+ _leftDamageShuttleMovie.redrawMovieWorld();
+
+ _lowerRightShuttleMovie.show();
+
+ _lowerLeftShuttleMovie.show();
+
+ loadLoopSound1("Sounds/Mars/Space Ambient.22K.8.AIFF");
+
+ initOneMovie(&_planetMovie, "Images/Mars/Planet.movie", kShuttlePlanetOrder,
+ kPlanetStartLeft, kPlanetStartTop, true);
+ _planetMovie.setFlags(kLoopTimeBase);
+
+ initOneMovie(&_junk, "Images/Mars/Junk.movie", kShuttleJunkOrder, kShuttleJunkLeft,
+ kShuttleJunkTop, false);
+
+ initOneMovie(&_explosions, "Images/Mars/Explosions.movie", kShuttleWeaponFrontOrder, 0, 0, false);
+ _explosionCallBack.initCallBack(&_explosions, kCallBackAtExtremes);
+
+ _energyBeam.initShuttleWeapon();
+ _gravitonCannon.initShuttleWeapon();
+
+ _upperLeftShuttleMovie.show();
+
+ _robotShip.initRobotShip();
+
+ _planetMovie.start();
+ _planetMover.startMoving(&_planetMovie);
+
+ _upperLeftShuttleMovie.setTime(kShuttleUpperLeftDimTime);
+ _upperLeftShuttleMovie.redrawMovieWorld();
+
+ _centerShuttleMovie.setTime(kShuttleCenterTargetSightedTime);
+ _centerShuttleMovie.redrawMovieWorld();
+
+ _lowerRightShuttleMovie.setTime(kShuttleLowerRightTrackingTime);
+ _lowerRightShuttleMovie.redrawMovieWorld();
+
+ _rightShuttleMovie.show();
+ _rightShuttleMovie.setTime(kShuttleRightIntroStop - 1);
+ _rightShuttleMovie.redrawMovieWorld();
+
+ _rightDamageShuttleMovie.show();
+ _rightDamageShuttleMovie.setTime(_rightDamageShuttleMovie.getDuration() - 40);
+ _rightDamageShuttleMovie.redrawMovieWorld();
+
+ _lowerLeftShuttleMovie.setTime(kShuttleLowerLeftAutopilotTime);
+ _lowerLeftShuttleMovie.redrawMovieWorld();
+
+ _robotShip.startMoving();
+
+ _shuttleHUD.initShuttleHUD();
+
+ _tractorBeam.startDisplaying();
+
+ _energyChoiceSpot.setArea(kShuttleEnergyBeamBounds);
+ _energyChoiceSpot.setHotspotFlags(kNeighborhoodSpotFlag | kClickSpotFlag);
+ _vm->getAllHotspots().push_back(&_energyChoiceSpot);
+ _gravitonChoiceSpot.setArea(kShuttleGravitonBounds);
+ _gravitonChoiceSpot.setHotspotFlags(kNeighborhoodSpotFlag | kClickSpotFlag);
+ _vm->getAllHotspots().push_back(&_gravitonChoiceSpot);
+ _tractorChoiceSpot.setArea(kShuttleTractorBounds);
+ _tractorChoiceSpot.setHotspotFlags(kNeighborhoodSpotFlag | kClickSpotFlag);
+ _vm->getAllHotspots().push_back(&_tractorChoiceSpot);
+ _shuttleViewSpot.setArea(kShuttleWindowLeft, kShuttleWindowTop,
+ kShuttleWindowLeft + kShuttleWindowWidth, kShuttleWindowTop + kShuttleWindowHeight);
+ _shuttleViewSpot.setHotspotFlags(kNeighborhoodSpotFlag | kClickSpotFlag);
+ _vm->getAllHotspots().push_back(&_shuttleViewSpot);
+ _shuttleTransportSpot.setArea(kShuttleTransportBounds);
+ _shuttleTransportSpot.setHotspotFlags(kNeighborhoodSpotFlag | kClickSpotFlag);
+ _vm->getAllHotspots().push_back(&_shuttleTransportSpot);
+
+ _privateFlags.setFlag(kMarsPrivateInSpaceChaseFlag, true);
+
+ startMarsTimer(kSpaceChaseTimeLimit, kOneTickPerSecond, kMarsSpaceChaseFinished);
+}
+
+void Mars::setSoundFXLevel(const uint16 level) {
+ Neighborhood::setSoundFXLevel(level);
+
+ if (_canyonChaseMovie.isMovieValid())
+ _canyonChaseMovie.setVolume(level);
+
+ if (_explosions.isMovieValid())
+ _explosions.setVolume(level);
+}
+
+void Mars::startMarsTimer(TimeValue time, TimeScale scale, MarsTimerCode code) {
+ _utilityFuse.primeFuse(time, scale);
+ _marsEvent.mars = this;
+ _marsEvent.event = code;
+ _utilityFuse.setFunctor(new Common::Functor0Mem<void, MarsTimerEvent>(&_marsEvent, &MarsTimerEvent::fire));
+ _utilityFuse.lightFuse();
+}
+
+void Mars::marsTimerExpired(MarsTimerEvent &event) {
+ Common::Rect r;
+ uint16 x, y;
+
+ switch (event.event) {
+ case kMarsLaunchTubeReached:
+ _lowerLeftShuttleMovie.setTime(kShuttleLowerLeftTubeTime);
+ _lowerLeftShuttleMovie.redrawMovieWorld();
+ startMarsTimer(kCanyonChaseFinishedTime, kMovieTicksPerSecond, kMarsCanyonChaseFinished);
+ break;
+ case kMarsCanyonChaseFinished:
+ GameState.setScoringEnteredLaunchTube();
+
+ while (_canyonChaseMovie.isRunning()) {
+ _vm->checkCallBacks();
+ _vm->refreshDisplay();
+ _vm->_system->delayMillis(10);
+ }
+
+ _canyonChaseMovie.stop();
+ _canyonChaseMovie.stopDisplaying();
+ _canyonChaseMovie.releaseMovie();
+
+ _vm->_gfx->enableErase();
+
+ loadLoopSound1("Sounds/Mars/Space Ambient.22K.8.AIFF");
+
+ playSpotSoundSync(kShuttleConfiguringIn, kShuttleConfiguringOut);
+ playSpotSoundSync(kShuttleGeneratingIn, kShuttleGeneratingOut);
+ playSpotSoundSync(kShuttleBreakawayIn, kShuttleBreakawayOut);
+ playSpotSoundSync(kMarsAtmosphericBreakawayIn, kMarsAtmosphericBreakawayOut);
+
+ initOneMovie(&_planetMovie, "Images/Mars/Planet.movie", kShuttlePlanetOrder, kPlanetStartLeft, kPlanetStartTop, true);
+ _planetMovie.setFlags(kLoopTimeBase);
+
+ initOneMovie(&_junk, "Images/Mars/Junk.movie", kShuttleJunkOrder, kShuttleJunkLeft, kShuttleJunkTop, false);
+
+ initOneMovie(&_explosions, "Images/Mars/Explosions.movie", kShuttleWeaponFrontOrder, 0, 0, false);
+ _explosionCallBack.initCallBack(&_explosions, kCallBackAtExtremes);
+
+ _energyBeam.initShuttleWeapon();
+ _gravitonCannon.initShuttleWeapon();
+
+ _centerShuttleMovie.setTime(kShuttleCenterWeaponsTime);
+ _centerShuttleMovie.redrawMovieWorld();
+
+ _upperLeftShuttleMovie.show();
+ _upperLeftShuttleMovie.setTime(kShuttleUpperLeftDampingTime);
+ _upperLeftShuttleMovie.redrawMovieWorld();
+
+ _robotShip.initRobotShip();
+
+ _planetMovie.start();
+ _planetMover.startMoving(&_planetMovie);
+
+ playSpotSoundSync(kShuttleDamperDescIn, kShuttleDamperDescOut);
+ _upperLeftShuttleMovie.setTime(kShuttleUpperLeftGravitonTime);
+ _upperLeftShuttleMovie.redrawMovieWorld();
+
+ playSpotSoundSync(kShuttleGravitonDescIn, kShuttleGravitonDescOut);
+ _upperLeftShuttleMovie.setTime(kShuttleUpperLeftTractorTime);
+ _upperLeftShuttleMovie.redrawMovieWorld();
+
+ playSpotSoundSync(kShuttleTractorDescIn, kShuttleTractorDescOut);
+ _upperLeftShuttleMovie.setTime(kShuttleUpperLeftDimTime);
+ _upperLeftShuttleMovie.redrawMovieWorld();
+
+ _centerShuttleMovie.setTime(kShuttleCenterTargetSightedTime);
+ _centerShuttleMovie.redrawMovieWorld();
+ playSpotSoundSync(kShuttleTargetSightedIn, kShuttleTargetSightedOut);
+
+ _lowerRightShuttleMovie.setTime(kShuttleLowerRightTrackingTime);
+ _lowerRightShuttleMovie.redrawMovieWorld();
+ _rightShuttleMovie.show();
+ playMovieSegment(&_rightShuttleMovie, kShuttleRightIntroStart, kShuttleRightIntroStop);
+
+ _rightDamageShuttleMovie.show();
+ playMovieSegment(&_rightDamageShuttleMovie);
+
+ // Take it down a tick initially. This sets the time to the time of the last tick,
+ // so that subsequence drops will drop it down a tick.
+ _rightDamageShuttleMovie.setTime(_rightDamageShuttleMovie.getTime() - 40);
+ _rightDamageShuttleMovie.redrawMovieWorld();
+
+ _lowerLeftShuttleMovie.setTime(kShuttleLowerLeftAutopilotTime);
+ _lowerLeftShuttleMovie.redrawMovieWorld();
+ playSpotSoundSync(kShuttleAutopilotEngagedIn, kShuttleAutopilotEngagedOut);
+
+ _robotShip.startMoving();
+
+ _shuttleHUD.initShuttleHUD();
+
+ _tractorBeam.startDisplaying();
+
+ _energyChoiceSpot.setArea(kShuttleEnergyBeamBounds);
+ _energyChoiceSpot.setHotspotFlags(kNeighborhoodSpotFlag | kClickSpotFlag);
+ _vm->getAllHotspots().push_back(&_energyChoiceSpot);
+ _gravitonChoiceSpot.setArea(kShuttleGravitonBounds);
+ _gravitonChoiceSpot.setHotspotFlags(kNeighborhoodSpotFlag | kClickSpotFlag);
+ _vm->getAllHotspots().push_back(&_gravitonChoiceSpot);
+ _tractorChoiceSpot.setArea(kShuttleTractorBounds);
+ _tractorChoiceSpot.setHotspotFlags(kNeighborhoodSpotFlag | kClickSpotFlag);
+ _vm->getAllHotspots().push_back(&_tractorChoiceSpot);
+ _shuttleViewSpot.setArea(kShuttleWindowLeft, kShuttleWindowTop,
+ kShuttleWindowLeft + kShuttleWindowWidth, kShuttleWindowTop + kShuttleWindowHeight);
+ _shuttleViewSpot.setHotspotFlags(kNeighborhoodSpotFlag | kClickSpotFlag);
+ _vm->getAllHotspots().push_back(&_shuttleViewSpot);
+ _shuttleTransportSpot.setArea(kShuttleTransportBounds);
+ _shuttleTransportSpot.setHotspotFlags(kNeighborhoodSpotFlag | kClickSpotFlag);
+ _vm->getAllHotspots().push_back(&_shuttleTransportSpot);
+
+ _privateFlags.setFlag(kMarsPrivateInSpaceChaseFlag, true);
+
+ playSpotSoundSync(kMarsCockpitChatterIn, kMarsCockpitChatterOut);
+
+ GameState.setMarsFinishedCanyonChase(true);
+
+ startMarsTimer(kSpaceChaseTimeLimit, kOneTickPerSecond, kMarsSpaceChaseFinished);
+
+ _vm->_cursor->hideUntilMoved();
+ break;
+ case kMarsSpaceChaseFinished:
+ // Player failed to stop the robot in time...
+ _interruptionFilter = kFilterNoInput;
+
+ _rightShuttleMovie.setTime(kShuttleRightTargetLockTime);
+ _rightShuttleMovie.redrawMovieWorld();
+
+ _upperRightShuttleMovie.show();
+ _upperRightShuttleMovie.setTime(kShuttleUpperRightLockedTime);
+ _upperRightShuttleMovie.redrawMovieWorld();
+
+ _rightShuttleMovie.setTime(kShuttleRightGravitonTime);
+ _rightShuttleMovie.redrawMovieWorld();
+ _upperRightShuttleMovie.setTime(kShuttleUpperRightArmedTime);
+ _upperRightShuttleMovie.redrawMovieWorld();
+
+ _vm->delayShell(3, 1);
+
+ x = _vm->getRandomNumber(19);
+ y = _vm->getRandomNumber(19);
+
+ r = Common::Rect(kShuttleWindowMidH - x, kShuttleWindowMidV - y,
+ kShuttleWindowMidH - x + 20, kShuttleWindowMidV - y + 20);
+ showBigExplosion(r, kShuttleAlienShipOrder);
+
+ while (_explosions.isRunning()) {
+ _vm->checkCallBacks();
+ _vm->refreshDisplay();
+ g_system->delayMillis(10);
+ }
+
+ throwAwayMarsShuttle();
+ reinstateMonocleInterface();
+ recallToTSAFailure();
+ break;
+ default:
+ break;
+ }
+
+ _interruptionFilter = kFilterAllInput;
+}
+
+void Mars::throwAwayMarsShuttle() {
+ _shuttleInterface1.deallocateSurface();
+ _shuttleInterface1.stopDisplaying();
+ _shuttleInterface2.deallocateSurface();
+ _shuttleInterface2.stopDisplaying();
+ _shuttleInterface3.deallocateSurface();
+ _shuttleInterface3.stopDisplaying();
+ _shuttleInterface4.deallocateSurface();
+ _shuttleInterface4.stopDisplaying();
+
+ _spotSounds.disposeSound();
+
+ _canyonChaseMovie.releaseMovie();
+ _canyonChaseMovie.stopDisplaying();
+ _leftShuttleMovie.releaseMovie();
+ _leftShuttleMovie.stopDisplaying();
+ _rightShuttleMovie.releaseMovie();
+ _rightShuttleMovie.stopDisplaying();
+ _lowerLeftShuttleMovie.releaseMovie();
+ _lowerLeftShuttleMovie.stopDisplaying();
+ _lowerRightShuttleMovie.releaseMovie();
+ _lowerRightShuttleMovie.stopDisplaying();
+ _centerShuttleMovie.releaseMovie();
+ _centerShuttleMovie.stopDisplaying();
+ _upperLeftShuttleMovie.releaseMovie();
+ _upperLeftShuttleMovie.stopDisplaying();
+ _upperRightShuttleMovie.releaseMovie();
+ _upperRightShuttleMovie.stopDisplaying();
+ _leftDamageShuttleMovie.releaseMovie();
+ _leftDamageShuttleMovie.stopDisplaying();
+ _rightDamageShuttleMovie.releaseMovie();
+ _rightDamageShuttleMovie.stopDisplaying();
+
+ _shuttleEnergyMeter.disposeShuttleEnergyMeter();
+ _robotShip.cleanUpRobotShip();
+ _shuttleHUD.cleanUpShuttleHUD();
+ _tractorBeam.stopDisplaying();
+ _junk.releaseMovie();
+ _junk.stopDisplaying();
+ _energyBeam.cleanUpShuttleWeapon();
+ _gravitonCannon.cleanUpShuttleWeapon();
+ _vm->getAllHotspots().remove(&_energyChoiceSpot);
+ _vm->getAllHotspots().remove(&_gravitonChoiceSpot);
+ _vm->getAllHotspots().remove(&_tractorChoiceSpot);
+ _vm->getAllHotspots().remove(&_shuttleViewSpot);
+ _vm->getAllHotspots().remove(&_shuttleTransportSpot);
+ _explosions.releaseMovie();
+ _explosions.stopDisplaying();
+
+ loadLoopSound1("");
+}
+
+void Mars::transportToRobotShip() {
+ throwAwayMarsShuttle();
+
+ Video::VideoDecoder *video = new Video::QuickTimeDecoder();
+ 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();
+
+ if (frame)
+ _vm->drawScaledFrame(frame, 0, 0);
+ }
+
+ Common::Event event;
+ while (g_system->getEventManager()->pollEvent(event))
+ ;
+
+ g_system->delayMillis(10);
+ }
+
+ delete video;
+
+ if (_vm->shouldQuit())
+ return;
+
+ reinstateMonocleInterface();
+
+ g_energyMonitor->stopEnergyDraining();
+ g_energyMonitor->restoreLastEnergyValue();
+ _vm->resetEnergyDeathReason();
+ g_energyMonitor->startEnergyDraining();
+
+ arriveAt(kMarsRobotShuttle, kEast);
+
+ _navMovie.stop();
+ _navMovie.setTime(_navMovie.getStart());
+ _navMovie.start();
+}
+
+const int kRobotTooStrong = 1;
+const int kTractorTooWeak = 2;
+const int kCapturedRobotShip = 3;
+
+void Mars::spaceChaseClick(const Input &input, const HotSpotID id) {
+ Common::Point pt;
+
+ switch (id) {
+ case kShuttleEnergySpotID:
+ _upperLeftShuttleMovie.setTime(kShuttleUpperLeftDampingTime);
+ _upperLeftShuttleMovie.redrawMovieWorld();
+ _leftShuttleMovie.setTime(kShuttleLeftDampingTime);
+ _leftShuttleMovie.redrawMovieWorld();
+ _shuttleHUD.hide();
+ _weaponSelection = kEnergyBeam;
+ playSpotSoundSync(kShuttleDampingBeamIn, kShuttleDampingBeamOut);
+ break;
+ case kShuttleGravitonSpotID:
+ _upperLeftShuttleMovie.setTime(kShuttleUpperLeftGravitonTime);
+ _upperLeftShuttleMovie.redrawMovieWorld();
+ _leftShuttleMovie.setTime(kShuttleLeftGravitonTime);
+ _leftShuttleMovie.redrawMovieWorld();
+ _shuttleHUD.hide();
+ _weaponSelection = kGravitonCannon;
+ playSpotSoundSync(kShuttleGravitonIn, kShuttleGravitonOut);
+ break;
+ case kShuttleTractorSpotID:
+ _upperLeftShuttleMovie.setTime(kShuttleUpperLeftTractorTime);
+ _upperLeftShuttleMovie.redrawMovieWorld();
+ _leftShuttleMovie.setTime(kShuttleLeftTractorTime);
+ _leftShuttleMovie.redrawMovieWorld();
+ _shuttleHUD.show();
+ _weaponSelection = kTractorBeam;
+ playSpotSoundSync(kShuttleTractorBeamIn, kShuttleTractorBeamOut);
+ break;
+ case kShuttleViewSpotID:
+ switch (_weaponSelection) {
+ case kEnergyBeam:
+ if (_shuttleEnergyMeter.getEnergyValue() < kMinDampingEnergy) {
+ playSpotSoundSync(kShuttleEnergyTooLowIn, kShuttleEnergyTooLowOut);
+ } else {
+ if (_energyBeam.canFireWeapon()) {
+ _shuttleEnergyMeter.dropEnergyValue(kMinDampingEnergy);
+ input.getInputLocation(pt);
+ _energyBeam.fireWeapon(pt.x, pt.y);
+ playSpotSoundSync(kMarsEDBBlastIn, kMarsEDBBlastOut);
+ }
+ }
+ break;
+ case kGravitonCannon:
+ if (_shuttleEnergyMeter.getEnergyValue() < kMinGravitonEnergy) {
+ playSpotSoundSync(kShuttleEnergyTooLowIn, kShuttleEnergyTooLowOut);
+ } else {
+ if (_gravitonCannon.canFireWeapon()) {
+ _shuttleEnergyMeter.dropEnergyValue(kMinGravitonEnergy);
+ input.getInputLocation(pt);
+ _gravitonCannon.fireWeapon(pt.x, pt.y);
+ playSpotSoundSync(kMarsGravitonBlastIn, kMarsGravitonBlastOut);
+ }
+ }
+ break;
+ case kTractorBeam:
+ if (_shuttleHUD.isTargetLocked()) {
+ // play tractor beam sound?
+ _utilityFuse.stopFuse();
+
+ _tractorBeam.show();
+
+ int capture;
+ if (_rightDamageShuttleMovie.getTime() > 40) {
+ capture = kRobotTooStrong;
+ } else if (!_shuttleEnergyMeter.enoughEnergyForTractorBeam()) {
+ capture = kTractorTooWeak;
+ } else {
+ _robotShip.snareByTractorBeam();
+ capture = kCapturedRobotShip;
+ _planetMover.dropPlanetOutOfSight();
+ }
+
+ _shuttleEnergyMeter.drainForTractorBeam();
+
+ while (_shuttleEnergyMeter.isFading()) {
+ _vm->checkCallBacks();
+ _vm->refreshDisplay();
+ _vm->_system->delayMillis(10);
+ }
+
+ _shuttleEnergyMeter.setEnergyValue(_shuttleEnergyMeter.getEnergyValue());
+
+ switch (capture) {
+ case kRobotTooStrong:
+ _tractorBeam.hide();
+ playSpotSoundSync(kShuttleBrokeFreeIn, kShuttleBrokeFreeOut);
+ _utilityFuse.lightFuse();
+ break;
+ case kTractorTooWeak:
+ playSpotSoundSync(kShuttleCantHoldIn, kShuttleCantHoldOut);
+ _tractorBeam.hide();
+ _utilityFuse.lightFuse();
+ break;
+ case kCapturedRobotShip:
+ _tractorBeam.hide();
+ _shuttleHUD.hide();
+ _robotShip.cleanUpRobotShip();
+ _planetMovie.stop();
+ _planetMovie.stopDisplaying();
+ _planetMovie.releaseMovie();
+
+ // Shameless reuse of a variable :P
+ initOneMovie(&_canyonChaseMovie, "Images/Mars/M98EAS.movie", kShuttleTractorBeamMovieOrder,
+ kShuttleWindowLeft, kShuttleWindowTop, true);
+ _canyonChaseMovie.redrawMovieWorld();
+ playMovieSegment(&_canyonChaseMovie, 0, _canyonChaseMovie.getDuration());
+
+ // wait here until any junk clears...
+ while (_junk.junkFlying()) {
+ _vm->checkCallBacks();
+ _vm->refreshDisplay();
+ _vm->_system->delayMillis(10);
+ }
+
+ _upperRightShuttleMovie.show();
+ _upperRightShuttleMovie.setTime(kShuttleUpperRightOverloadTime);
+ _upperRightShuttleMovie.redrawMovieWorld();
+
+ playSpotSoundSync(kShuttleOverloadedIn, kShuttleOverloadedOut);
+ _centerShuttleMovie.setTime(kShuttleCenterVerifyingTime);
+ _centerShuttleMovie.redrawMovieWorld();
+
+ playSpotSoundSync(kShuttleCoordinatesIn, kShuttleCoordinatesOut);
+ _centerShuttleMovie.setTime(kShuttleCenterScanningTime);
+ _centerShuttleMovie.redrawMovieWorld();
+
+ playSpotSoundSync(kShuttleScanningIn, kShuttleScanningOut);
+ _centerShuttleMovie.setTime(kShuttleCenterSafeTime);
+ _centerShuttleMovie.redrawMovieWorld();
+
+ playSpotSoundSync(kShuttleSafeIn, kShuttleSafeOut);
+ _lowerRightShuttleMovie.setTime(kShuttleLowerRightTransportTime);
+ _lowerRightShuttleMovie.redrawMovieWorld();
+ GameState.setMarsReadyForShuttleTransport(true);
+ break;
+ }
+ } else {
+ playSpotSoundSync(kShuttleTractorLimitedIn, kShuttleTractorLimitedOut);
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case kShuttleTransportSpotID:
+ _lowerRightShuttleMovie.setTime(kShuttleLowerRightTransportHiliteTime);
+ _lowerRightShuttleMovie.redrawMovieWorld();
+ _neighborhoodNotification.setNotificationFlags(kTimeToTransportFlag, kTimeToTransportFlag);
+ break;
+ }
+}
+
+void Mars::showBigExplosion(const Common::Rect &r, const DisplayOrder order) {
+ if (_explosions.isMovieValid()) {
+ _explosions.setDisplayOrder(order);
+
+ Common::Rect r2 = r;
+ int dx = r.width() / 2;
+ int dy = r.height() / 2;
+ r2.left -= dx;
+ r2.right += dx;
+ r2.top -= dy;
+ r2.bottom += dy;
+
+ _explosions.setBounds(r2);
+ _explosions.show();
+ _explosions.stop();
+ _explosions.setSegment(kBigExplosionStart, kBigExplosionStop);
+ _explosions.setTime(kBigExplosionStart);
+ _explosionCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ _explosions.start();
+ }
+}
+
+void Mars::showLittleExplosion(const Common::Rect &r, const DisplayOrder order) {
+ if (_explosions.isMovieValid()) {
+ _explosions.setDisplayOrder(order);
+
+ Common::Rect r2 = r;
+ int dx = r.width() / 2;
+ int dy = r.height() / 2;
+ r2.left -= dx;
+ r2.right += dx;
+ r2.top -= dy;
+ r2.bottom += dy;
+ _explosions.setBounds(r2);
+
+ _explosions.show();
+ _explosions.stop();
+ _explosions.setSegment(kLittleExplosionStart, kLittleExplosionStop);
+ _explosions.setTime(kLittleExplosionStart);
+ _explosionCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ _explosions.start();
+ }
+}
+
+void Mars::hitByJunk() {
+ _leftDamageShuttleMovie.setTime(_leftDamageShuttleMovie.getTime() - 40);
+ _leftDamageShuttleMovie.redrawMovieWorld();
+
+ playSpotSoundSync(kMarsJunkCollisionIn, kMarsJunkCollisionOut);
+
+ if (_leftDamageShuttleMovie.getTime() == 0) {
+ die(kDeathRanIntoSpaceJunk);
+ } else {
+ TimeValue t = _leftDamageShuttleMovie.getTime() / 40;
+
+ if (t == 1)
+ playSpotSoundSync(kShuttleHullBreachIn, kShuttleHullBreachOut);
+
+ t = _leftShuttleMovie.getTime();
+ _leftShuttleMovie.setTime(kShuttleLeftDamagedTime);
+ _leftShuttleMovie.redrawMovieWorld();
+ _vm->delayShell(1, 3);
+ _leftShuttleMovie.setTime(t);
+ _leftShuttleMovie.redrawMovieWorld();
+ }
+}
+
+void Mars::setUpNextDropTime() {
+ _robotShip.setUpNextDropTime();
+}
+
+void Mars::decreaseRobotShuttleEnergy(const int delta, Common::Point impactPoint) {
+ _rightDamageShuttleMovie.setTime(_rightDamageShuttleMovie.getTime() - 40 * delta);
+ _rightDamageShuttleMovie.redrawMovieWorld();
+
+ if (_rightDamageShuttleMovie.getTime() == 0) {
+ Common::Rect r;
+ _robotShip.getShuttleBounds(r);
+ int size = MAX(r.width(), r.height());
+ r = Common::Rect::center(impactPoint.x, impactPoint.y, size, size);
+ _robotShip.killRobotShip();
+ showBigExplosion(r, kShuttleRobotShipOrder);
+ } else if (delta > 1) {
+ Common::Rect r;
+ _robotShip.getShuttleBounds(r);
+ int size = MIN(r.width(), r.height());
+ r = Common::Rect::center(impactPoint.x, impactPoint.y, size, size);
+ showLittleExplosion(r, kShuttleWeaponBackOrder);
+ TimeValue t = _rightShuttleMovie.getTime();
+ _rightShuttleMovie.setTime(kShuttleRightDamagedTime);
+ _rightShuttleMovie.redrawMovieWorld();
+ _vm->delayShell(1, 3);
+ _rightShuttleMovie.setTime(t);
+ _rightShuttleMovie.redrawMovieWorld();
+ }
+
+ if (_rightDamageShuttleMovie.getTime() <= 40) {
+ GameState.setScoringStoppedRobotsShuttle();
+ if (!GameState.getMarsHitRobotWithCannon())
+ GameState.setScoringMarsGandhi();
+ }
+}
+
+void Mars::updateCursor(const Common::Point cursorLocation, const Hotspot *cursorSpot) {
+ if (cursorSpot && cursorSpot->getObjectID() == kShuttleViewSpotID) {
+ if (_weaponSelection != kNoWeapon)
+ _vm->_cursor->setCurrentFrameIndex(6);
+ else
+ _vm->_cursor->setCurrentFrameIndex(0);
+ } else {
+ Neighborhood::updateCursor(cursorLocation, cursorSpot);
+ }
+}
+
+AirQuality Mars::getAirQuality(const RoomID room) {
+ if ((room >= kMars36 && room <= kMars39) || (room >= kMarsMaze004 && room <= kMarsMaze200))
+ return kAirQualityVacuum;
+ if (room == kMars35 && !GameState.getMarsAirlockOpen())
+ return kAirQualityVacuum;
+ if (room == kMars60 && !GameState.getMarsAirlockOpen())
+ return kAirQualityVacuum;
+
+ return Neighborhood::getAirQuality(room);
+}
+
+// Start up panting sound if necessary.
+
+void Mars::checkAirMask() {
+ Neighborhood::checkAirMask();
+
+ if (getAirQuality(GameState.getCurrentRoom()) == kAirQualityVacuum) {
+ if (g_airMask->isAirMaskOn()) {
+ if (_noAirFuse.isFuseLit()) {
+ _noAirFuse.stopFuse();
+ loadLoopSound2("");
+ loadAmbientLoops();
+ playSpotSoundSync(kMarsOxyMaskOnIn, kMarsOxyMaskOnOut);
+ }
+ } else {
+ if (!_noAirFuse.isFuseLit()) {
+ loadLoopSound2("Sounds/Mars/SukWind1.22K.AIFF");
+ _noAirFuse.primeFuse(kVacuumSurvivalTimeLimit);
+ _noAirFuse.lightFuse();
+ }
+ }
+ } else {
+ if (_noAirFuse.isFuseLit()) {
+ _noAirFuse.stopFuse();
+ loadLoopSound2("");
+ loadAmbientLoops();
+ }
+ }
+}
+
+void Mars::airStageExpired() {
+ if (((PegasusEngine *)g_engine)->playerHasItemID(kAirMask))
+ die(kDeathNoAirInMaze);
+ else
+ die(kDeathNoMaskInMaze);
+}
+
+void Mars::lockThawed() {
+ startExtraSequence(kMars57ThawLock, kExtraCompletedFlag, kFilterNoInput);
+}
+
+void Mars::setUpReactorLevel1() {
+ _reactorStage = 1;
+ makeColorSequence();
+ _guessObject.initReactorGuess();
+ _undoPict.initFromPICTResource(_vm->_resFork, kReactorUndoHilitePICTID);
+ _undoPict.setDisplayOrder(kMonitorLayer);
+ _undoPict.moveElementTo(kUndoHiliteLeft, kUndoHiliteTop);
+ _undoPict.startDisplaying();
+ _guessHistory.initReactorHistory();
+ _choiceHighlight.initReactorChoiceHighlight();
+ setCurrentActivation(kActivateReactorInGame);
+ _bombFuse.primeFuse(kColorMatchingTimeLimit);
+ _bombFuse.setFunctor(new Common::Functor0Mem<void, Mars>(this, &Mars::bombExplodesInGame));
+ _bombFuse.lightFuse();
+}
+
+void Mars::setUpNextReactorLevel() {
+ _guessObject.show();
+ _guessHistory.show();
+ _guessHistory.clearHistory();
+ _choiceHighlight.show();
+ _reactorStage++;
+ makeColorSequence();
+}
+
+void Mars::makeColorSequence() {
+ int32 code[5];
+ int32 highest = _reactorStage + 2;
+
+ for (int32 i = 0; i < highest; i++)
+ code[i] = i;
+
+ _vm->shuffleArray(code, highest);
+ _currentGuess[0] = -1;
+ _currentGuess[1] = -1;
+ _currentGuess[2] = -1;
+ _nextGuess = 0;
+ _guessObject.setGuess(-1, -1, -1);
+ _guessHistory.setAnswer(code[0], code[1], code[2]);
+}
+
+void Mars::doUndoOneGuess() {
+ if (_nextGuess > 0) {
+ _undoPict.show();
+ _vm->delayShell(1, 2);
+ _undoPict.hide();
+ _nextGuess--;
+ _currentGuess[_nextGuess] = -1;
+ _guessObject.setGuess(_currentGuess[0], _currentGuess[1], _currentGuess[2]);
+ _choiceHighlight.resetHighlight();
+
+ if (_currentGuess[0] != -1) {
+ _choiceHighlight.highlightChoice(_currentGuess[0]);
+
+ if (_currentGuess[1] != -1) {
+ _choiceHighlight.highlightChoice(_currentGuess[1]);
+
+ if (_currentGuess[2] != -1)
+ _choiceHighlight.highlightChoice(_currentGuess[2]);
+ }
+ }
+ }
+}
+
+void Mars::doReactorGuess(int32 guess) {
+ _choiceHighlight.highlightChoice(guess);
+ _currentGuess[_nextGuess] = guess;
+ _guessObject.setGuess(_currentGuess[0], _currentGuess[1], _currentGuess[2]);
+
+ switch (guess) {
+ case 0:
+ playSpotSoundSync(kColorMatchRedIn, kColorMatchRedOut);
+ break;
+ case 1:
+ playSpotSoundSync(kColorMatchYellowIn, kColorMatchYellowOut);
+ break;
+ case 2:
+ playSpotSoundSync(kColorMatchGreenIn, kColorMatchGreenOut);
+ break;
+ case 3:
+ playSpotSoundSync(kColorMatchBlueIn, kColorMatchBlueOut);
+ break;
+ case 4:
+ playSpotSoundSync(kColorMatchPurpleIn, kColorMatchPurpleOut);
+ break;
+ }
+
+ _nextGuess++;
+
+ if (_nextGuess == 3) {
+ _vm->delayShell(1, 2);
+ _nextGuess = 0;
+ _guessHistory.addGuess(_currentGuess[0], _currentGuess[1], _currentGuess[2]);
+
+ switch (_guessHistory.getCurrentNumCorrect()) {
+ case 0:
+ playSpotSoundSync(kColorMatchZeroNodesIn, kColorMatchZeroNodesOut);
+ break;
+ case 1:
+ playSpotSoundSync(kColorMatchOneNodeIn, kColorMatchOneNodeOut);
+ break;
+ case 2:
+ playSpotSoundSync(kColorMatchTwoNodesIn, kColorMatchTwoNodesOut);
+ break;
+ case 3:
+ playSpotSoundSync(kColorMatchThreeNodesIn, kColorMatchThreeNodesOut);
+ break;
+ }
+
+ _currentGuess[0] = -1;
+ _currentGuess[1] = -1;
+ _currentGuess[2] = -1;
+ _guessObject.setGuess(-1, -1, -1);
+ _choiceHighlight.resetHighlight();
+
+ if (_guessHistory.isSolved()) {
+ _guessHistory.showAnswer();
+ _vm->delayShell(1, 2);
+ _guessObject.hide();
+ _guessHistory.hide();
+ _choiceHighlight.hide();
+
+ switch (_reactorStage) {
+ case 1:
+ startExtraSequence(kMars57GameLevel2, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case 2:
+ startExtraSequence(kMars57GameLevel3, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case 3:
+ _bombFuse.stopFuse();
+ _guessObject.disposeReactorGuess();
+ _undoPict.deallocateSurface();
+ _guessHistory.disposeReactorHistory();
+ _choiceHighlight.disposeReactorChoiceHighlight();
+ GameState.setScoringDisarmedCardBomb();
+ startExtraSequence(kMars57GameSolved, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ }
+ } else if (_guessHistory.getNumGuesses() >= 5) {
+ _vm->delayShell(2, 1);
+ bombExplodesInGame();
+ }
+ }
+}
+
+void Mars::bombExplodesInGame() {
+ _guessObject.disposeReactorGuess();
+ _undoPict.deallocateSurface();
+ _guessHistory.disposeReactorHistory();
+ _choiceHighlight.disposeReactorChoiceHighlight();
+ startExtraSequence(kMars57BombExplodesInGame, kExtraCompletedFlag, kFilterNoInput);
+}
+
+void Mars::didntFindBomb() {
+ die(kDeathDidntFindMarsBomb);
+}
+
+Common::String Mars::getBriefingMovie() {
+ Common::String movieName = Neighborhood::getBriefingMovie();
+
+ if (!movieName.empty())
+ return movieName;
+
+ return "Images/AI/Mars/XM01";
+}
+
+Common::String Mars::getEnvScanMovie() {
+ Common::String movieName = Neighborhood::getEnvScanMovie();
+
+ if (movieName.empty()) {
+ RoomID room = GameState.getCurrentRoom();
+
+ if (room >= kMars0A && room <= kMars21)
+ return "Images/AI/Mars/XME1";
+ else if (room >= kMars22 && room <= kMars31South)
+ return "Images/AI/Mars/XME2";
+ else if (room >= kMars52 && room <= kMars58)
+ return "Images/AI/Mars/XMREACE";
+
+ return "Images/AI/Mars/XME3";
+ }
+
+ return movieName;
+}
+
+uint Mars::getNumHints() {
+ uint numHints = Neighborhood::getNumHints();
+
+ if (numHints == 0) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kMars27, kNorth):
+ case MakeRoomView(kMars28, kNorth):
+ case MakeRoomView(kMars49, kSouth):
+ numHints = 1;
+ break;
+ case MakeRoomView(kMars31, kSouth):
+ case MakeRoomView(kMars31South, kSouth):
+ if (!GameState.isTakenItemID(kMarsCard))
+ numHints = 1;
+ break;
+ case MakeRoomView(kMars34, kNorth):
+ if (!GameState.isTakenItemID(kMarsCard))
+ numHints = 2;
+ break;
+ case MakeRoomView(kMars34, kSouth):
+ case MakeRoomView(kMars45, kNorth):
+ if (!GameState.isTakenItemID(kCrowbar))
+ numHints = 1;
+ break;
+ case MakeRoomView(kMars51, kEast):
+ if (GameState.isCurrentDoorOpen() && !GameState.getShieldOn()) {
+ if (GameState.isTakenItemID(kShieldBiochip))
+ numHints = 1;
+ else
+ numHints = 2;
+ }
+ break;
+ case MakeRoomView(kMars52, kNorth):
+ case MakeRoomView(kMars52, kSouth):
+ case MakeRoomView(kMars52, kEast):
+ case MakeRoomView(kMars52, kWest):
+ case MakeRoomView(kMars54, kNorth):
+ case MakeRoomView(kMars54, kSouth):
+ case MakeRoomView(kMars54, kEast):
+ case MakeRoomView(kMars54, kWest):
+ case MakeRoomView(kMars56, kNorth):
+ case MakeRoomView(kMars56, kSouth):
+ case MakeRoomView(kMars56, kWest):
+ case MakeRoomView(kMars58, kNorth):
+ case MakeRoomView(kMars58, kSouth):
+ case MakeRoomView(kMars58, kEast):
+ case MakeRoomView(kMars58, kWest):
+ if (!GameState.getShieldOn()) {
+ if (GameState.isTakenItemID(kShieldBiochip))
+ numHints = 1;
+ else
+ numHints = 2;
+ }
+ break;
+ case MakeRoomView(kMars56, kEast):
+ if (getCurrentActivation() == kActivateReactorReadyForNitrogen) {
+ if ((ExtraID)_lastExtra == kMars57LowerScreenClosed)
+ numHints = 3;
+ } else if (getCurrentActivation() == kActivateReactorPlatformOut) {
+ if (!GameState.getShieldOn()) {
+ if (GameState.isTakenItemID(kShieldBiochip))
+ numHints = 1;
+ else
+ numHints = 2;
+ }
+ }
+ break;
+ }
+ }
+
+ return numHints;
+}
+
+Common::String Mars::getHintMovie(uint hintNum) {
+ Common::String movieName = Neighborhood::getHintMovie(hintNum);
+
+ if (movieName.empty()) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kMars27, kNorth):
+ case MakeRoomView(kMars28, kNorth):
+ return "Images/AI/Globals/XGLOB5C";
+ case MakeRoomView(kMars31, kSouth):
+ case MakeRoomView(kMars31South, kSouth):
+ case MakeRoomView(kMars34, kSouth):
+ case MakeRoomView(kMars45, kNorth):
+ return "Images/AI/Globals/XGLOB1C";
+ case MakeRoomView(kMars34, kNorth):
+ if (hintNum == 1)
+ return "Images/AI/Globals/XGLOB2C";
+
+ return "Images/AI/Globals/XGLOB3G";
+ case MakeRoomView(kMars49, kSouth):
+ if (GameState.isTakenItemID(kAirMask))
+ return "Images/AI/Globals/XGLOB3E";
+
+ return "Images/AI/Globals/XGLOB1C";
+ case MakeRoomView(kMars51, kEast):
+ if (GameState.isTakenItemID(kShieldBiochip))
+ return "Images/AI/Mars/XM52NW";
+
+ if (hintNum == 1)
+ return "Images/AI/Globals/XGLOB2D";
+
+ return "Images/AI/Globals/XGLOB3F";
+ case MakeRoomView(kMars52, kNorth):
+ case MakeRoomView(kMars52, kSouth):
+ case MakeRoomView(kMars52, kEast):
+ case MakeRoomView(kMars52, kWest):
+ case MakeRoomView(kMars54, kNorth):
+ case MakeRoomView(kMars54, kSouth):
+ case MakeRoomView(kMars54, kEast):
+ case MakeRoomView(kMars54, kWest):
+ case MakeRoomView(kMars56, kNorth):
+ case MakeRoomView(kMars56, kSouth):
+ case MakeRoomView(kMars56, kWest):
+ case MakeRoomView(kMars58, kNorth):
+ case MakeRoomView(kMars58, kSouth):
+ case MakeRoomView(kMars58, kEast):
+ case MakeRoomView(kMars58, kWest):
+ if (hintNum == 1) {
+ if (GameState.isTakenItemID(kShieldBiochip))
+ return "Images/AI/Mars/XM52NW";
+
+ return "Images/AI/Globals/XGLOB2D";
+ }
+
+ return "Images/AI/Globals/XGLOB3F";
+ case MakeRoomView(kMars56, kEast):
+ if (getCurrentActivation() == kActivateReactorReadyForNitrogen)
+ return Common::String::format("Images/AI/Mars/XM57SD%d", hintNum);
+
+ if (hintNum == 1) {
+ if (GameState.isTakenItemID(kShieldBiochip))
+ return "Images/AI/Mars/XM52NW";
+
+ return "Images/AI/Globals/XGLOB2D";
+ }
+
+ return "Images/AI/Globals/XGLOB3F";
+ }
+ }
+
+ return movieName;
+}
+
+bool Mars::inColorMatchingGame() {
+ return _guessObject.isDisplaying();
+}
+
+bool Mars::canSolve() {
+ return GameState.getCurrentRoomAndView() == MakeRoomView(kMars56, kEast) && (getCurrentActivation() == kActivateReactorReadyForNitrogen ||
+ getCurrentActivation() == kActivateReactorReadyForCrowBar || inColorMatchingGame());
+}
+
+void Mars::doSolve() {
+ if (getCurrentActivation() == kActivateReactorReadyForNitrogen || getCurrentActivation() == kActivateReactorReadyForCrowBar) {
+ _utilityFuse.stopFuse();
+ GameState.setMarsLockBroken(true);
+ GameState.setMarsLockFrozen(false);
+ startExtraLongSequence(kMars57OpenPanel, kMars57OpenPanelChoices, kExtraCompletedFlag, kFilterNoInput);
+ } else if (inColorMatchingGame()) {
+ _bombFuse.stopFuse();
+ _guessObject.disposeReactorGuess();
+ _undoPict.deallocateSurface();
+ _guessHistory.disposeReactorHistory();
+ _choiceHighlight.disposeReactorChoiceHighlight();
+ startExtraSequence(kMars57GameSolved, kExtraCompletedFlag, kFilterNoInput);
+ }
+}
+
+Common::String Mars::getSoundSpotsName() {
+ return "Sounds/Mars/Mars Spots";
+}
+
+Common::String Mars::getNavMovieName() {
+ return "Images/Mars/Mars.movie";
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/mars/mars.h b/engines/pegasus/neighborhood/mars/mars.h
new file mode 100644
index 0000000000..0859522890
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/mars.h
@@ -0,0 +1,238 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_MARS_MARS_H
+#define PEGASUS_NEIGHBORHOOD_MARS_MARS_H
+
+#include "pegasus/neighborhood/neighborhood.h"
+#include "pegasus/neighborhood/mars/constants.h"
+#include "pegasus/neighborhood/mars/energybeam.h"
+#include "pegasus/neighborhood/mars/gravitoncannon.h"
+#include "pegasus/neighborhood/mars/planetmover.h"
+#include "pegasus/neighborhood/mars/reactor.h"
+#include "pegasus/neighborhood/mars/robotship.h"
+#include "pegasus/neighborhood/mars/shuttleenergymeter.h"
+#include "pegasus/neighborhood/mars/shuttlehud.h"
+#include "pegasus/neighborhood/mars/spacejunk.h"
+#include "pegasus/neighborhood/mars/tractorbeam.h"
+
+namespace Pegasus {
+
+class InventoryItem;
+class Mars;
+
+enum MarsTimerCode {
+ kMarsLaunchTubeReached,
+ kMarsCanyonChaseFinished,
+ kMarsSpaceChaseFinished // Player ran out of time...
+};
+
+struct MarsTimerEvent {
+ Mars *mars;
+ MarsTimerCode event;
+
+ void fire();
+};
+
+enum ShuttleWeaponSelection {
+ kNoWeapon,
+ kEnergyBeam,
+ kGravitonCannon,
+ kTractorBeam
+};
+
+class Mars : public Neighborhood {
+friend struct MarsTimerEvent;
+public:
+ Mars(InputHandler *, PegasusEngine *);
+ virtual ~Mars();
+
+ void flushGameState();
+
+ virtual uint16 getDateResID() const;
+
+ virtual AirQuality getAirQuality(const RoomID);
+
+ void checkAirMask();
+
+ void showBigExplosion(const Common::Rect &, const DisplayOrder);
+ void showLittleExplosion(const Common::Rect &, const DisplayOrder);
+ void hitByJunk();
+ void decreaseRobotShuttleEnergy(const int, Common::Point impactPoint);
+ void setUpNextDropTime();
+
+ Common::String getBriefingMovie();
+ Common::String getEnvScanMovie();
+ uint getNumHints();
+ Common::String getHintMovie(uint);
+
+ virtual void shieldOn();
+ virtual void shieldOff();
+
+ void checkContinuePoint(const RoomID, const DirectionConstant);
+
+ void setSoundFXLevel(const uint16);
+
+ bool canSolve();
+ void doSolve();
+
+ bool inColorMatchingGame();
+
+protected:
+ enum {
+ kMarsPrivatePodStorageOpenFlag,
+ kMarsPrivatePodTurnLeftFlag,
+ kMarsPrivatePodTurnRightFlag,
+ kMarsPrivateRobotTiredOfWaitingFlag,
+ kMarsPrivatePlatformZoomedInFlag,
+ kMarsPrivateBombExposedFlag,
+ kMarsPrivateDraggingBombFlag,
+ kMarsPrivateInSpaceChaseFlag,
+ kMarsPrivateGotMapChipFlag,
+ kMarsPrivateGotOpticalChipFlag,
+ kMarsPrivateGotShieldChipFlag,
+ kNumMarsPrivateFlags
+ };
+
+ void init();
+ void start();
+ void setUpAIRules();
+ void arriveAt(const RoomID, const DirectionConstant);
+ void takeItemFromRoom(Item *);
+ void dropItemIntoRoom(Item *, Hotspot *);
+ void activateHotspots();
+ void activateOneHotspot(HotspotInfoTable::Entry &, Hotspot *);
+ void clickInHotspot(const Input &, const Hotspot *);
+ InputBits getInputFilter();
+
+ TimeValue getViewTime(const RoomID, const DirectionConstant);
+ void getZoomEntry(const HotSpotID, ZoomTable::Entry &);
+ void findSpotEntry(const RoomID, const DirectionConstant, SpotFlags, SpotTable::Entry &);
+ CanOpenDoorReason canOpenDoor(DoorTable::Entry &);
+ void openDoor();
+ void closeDoorOffScreen(const RoomID, const DirectionConstant);
+ int16 getStaticCompassAngle(const RoomID, const DirectionConstant);
+ void getExitCompassMove(const ExitTable::Entry &, FaderMoveSpec &);
+ void getExtraCompassMove(const ExtraTable::Entry &, FaderMoveSpec &);
+ void turnTo(const DirectionConstant);
+ void receiveNotification(Notification *, const NotificationFlags);
+ void doorOpened();
+ void setUpReactorEnergyDrain();
+ Hotspot *getItemScreenSpot(Item *, DisplayElement *);
+ void lockThawed();
+ void robotTiredOfWaiting();
+
+ void setUpReactorLevel1();
+ void setUpNextReactorLevel();
+ void makeColorSequence();
+ void doUndoOneGuess();
+ void doReactorGuess(int32 guess);
+ void bombExplodesInGame();
+ void didntFindBomb();
+ CanMoveForwardReason canMoveForward(ExitTable::Entry &);
+ void cantMoveThatWay(CanMoveForwardReason);
+ void moveForward();
+ void bumpIntoWall();
+ void turnLeft();
+ void turnRight();
+ void airStageExpired();
+ void loadAmbientLoops();
+ void checkAirlockDoors();
+ void pickedUpItem(Item *item);
+ void cantOpenDoor(CanOpenDoorReason);
+ void launchMaze007Robot();
+ void launchMaze015Robot();
+ void launchMaze101Robot();
+ void launchMaze104Robot();
+ void launchMaze133Robot();
+ void launchMaze136Robot();
+ void launchMaze184Robot();
+ void timerExpired(const uint32);
+ void spotCompleted();
+
+ void doCanyonChase(void);
+ void startMarsTimer(TimeValue, TimeScale, MarsTimerCode);
+ void marsTimerExpired(MarsTimerEvent &);
+ void throwAwayMarsShuttle();
+ void startUpFromFinishedSpaceChase();
+ void startUpFromSpaceChase();
+ void transportToRobotShip();
+ void spaceChaseClick(const Input &, const HotSpotID);
+ void updateCursor(const Common::Point, const Hotspot *);
+
+ Common::String getSoundSpotsName();
+ Common::String getNavMovieName();
+
+ InventoryItem *_attackingItem;
+ FuseFunction _bombFuse;
+ FuseFunction _noAirFuse;
+ FuseFunction _utilityFuse;
+ FlagsArray<byte, kNumMarsPrivateFlags> _privateFlags;
+ uint _reactorStage, _nextGuess;
+ int32 _currentGuess[3];
+ ReactorGuess _guessObject;
+ Picture _undoPict;
+ ReactorHistory _guessHistory;
+ ReactorChoiceHighlight _choiceHighlight;
+
+ Picture _shuttleInterface1;
+ Picture _shuttleInterface2;
+ Picture _shuttleInterface3;
+ Picture _shuttleInterface4;
+ Movie _canyonChaseMovie;
+
+ MarsTimerEvent _marsEvent;
+
+ Movie _leftShuttleMovie;
+ Movie _rightShuttleMovie;
+ Movie _lowerLeftShuttleMovie;
+ Movie _lowerRightShuttleMovie;
+ Movie _centerShuttleMovie;
+ Movie _upperLeftShuttleMovie;
+ Movie _upperRightShuttleMovie;
+ Movie _leftDamageShuttleMovie;
+ Movie _rightDamageShuttleMovie;
+ ShuttleEnergyMeter _shuttleEnergyMeter;
+ Movie _planetMovie;
+ PlanetMover _planetMover;
+ RobotShip _robotShip;
+ ShuttleHUD _shuttleHUD;
+ TractorBeam _tractorBeam;
+ SpaceJunk _junk;
+ EnergyBeam _energyBeam;
+ GravitonCannon _gravitonCannon;
+ Hotspot _energyChoiceSpot;
+ Hotspot _gravitonChoiceSpot;
+ Hotspot _tractorChoiceSpot;
+ Hotspot _shuttleViewSpot;
+ Hotspot _shuttleTransportSpot;
+ ShuttleWeaponSelection _weaponSelection;
+ ScalingMovie _explosions;
+ NotificationCallBack _explosionCallBack;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/mars/planetmover.cpp b/engines/pegasus/neighborhood/mars/planetmover.cpp
new file mode 100644
index 0000000000..a340120c12
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/planetmover.cpp
@@ -0,0 +1,104 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/movie.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/neighborhood/mars/constants.h"
+#include "pegasus/neighborhood/mars/hermite.h"
+#include "pegasus/neighborhood/mars/planetmover.h"
+#include "pegasus/neighborhood/mars/shuttleenergymeter.h"
+
+namespace Pegasus {
+
+static const TimeScale kRovingScale = kTractorBeamScale;
+static const TimeValue kRovingTime = kTenSeconds * kRovingScale;
+static const TimeValue kRovingSlop = kTwoSeconds * kRovingScale;
+
+static const CoordType kMaxVelocity = 20;
+
+PlanetMover::PlanetMover() {
+ setScale(kRovingScale);
+ _dropping = false;
+ _planetMovie = 0;
+}
+
+void PlanetMover::startMoving(Movie *planetMovie) {
+ _planetMovie = planetMovie;
+ _p4 = kPlanetStartTop;
+ _r4 = ((PegasusEngine *)g_engine)->getRandomNumber(kMaxVelocity - 1);
+ if (_r4 + _p4 < kPlanetStopTop)
+ _r4 = kPlanetStopTop - _p4;
+ newDestination();
+}
+
+void PlanetMover::stopMoving() {
+ stop();
+}
+
+void PlanetMover::dropPlanetOutOfSight() {
+ stop();
+ CoordType currentLoc = hermite(_p1, _p4, _r1, _r4, _lastTime, _duration);
+ CoordType currentV = dHermite(_p1, _p4, _r1, _r4, _lastTime, _duration);
+ _p1 = currentLoc;
+ _r1 = currentV;
+ _p4 = kPlanetStartTop;
+ _r4 = 0;
+ _duration = kTractorBeamTime - kTractorBeamScale;
+ _dropping = true;
+ setSegment(0, _duration);
+ setTime(0);
+ start();
+}
+
+void PlanetMover::newDestination() {
+ _p1 = _p4;
+ _r1 = _r4;
+
+ _p4 = kPlanetStopTop + ((PegasusEngine *)g_engine)->getRandomNumber(kPlanetStartTop - kPlanetStopTop - 1);
+ _r4 = ((PegasusEngine *)g_engine)->getRandomNumber(kMaxVelocity - 1);
+
+ if (_r4 + _p4 < kPlanetStopTop)
+ _r4 = kPlanetStopTop - _p4;
+
+ stop();
+ _duration = kRovingTime + ((PegasusEngine *)g_engine)->getRandomNumber(kRovingSlop - 1);
+ setSegment(0, _duration);
+ setTime(0);
+ start();
+}
+
+void PlanetMover::timeChanged(const TimeValue) {
+ if (_planetMovie) {
+ _planetMovie->moveElementTo(kPlanetStartLeft, hermite(_p1, _p4, _r1, _r4, _lastTime, _duration));
+ if (_lastTime == _duration) {
+ if (_dropping)
+ stop();
+ else
+ newDestination();
+ }
+ }
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/mars/planetmover.h b/engines/pegasus/neighborhood/mars/planetmover.h
new file mode 100644
index 0000000000..2c195387e8
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/planetmover.h
@@ -0,0 +1,57 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_MARS_PLANETMOVER_H
+#define PEGASUS_NEIGHBORHOOD_MARS_PLANETMOVER_H
+
+#include "pegasus/timers.h"
+
+namespace Pegasus {
+
+class Movie;
+
+class PlanetMover : IdlerTimeBase {
+public:
+ PlanetMover();
+ virtual ~PlanetMover() {}
+
+ void startMoving(Movie *);
+ void stopMoving();
+
+ void dropPlanetOutOfSight();
+
+protected:
+ void newDestination();
+ virtual void timeChanged(const TimeValue);
+
+ Movie *_planetMovie;
+ CoordType _p1, _p4, _r1, _r4;
+ TimeValue _duration;
+ bool _dropping;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/mars/reactor.cpp b/engines/pegasus/neighborhood/mars/reactor.cpp
new file mode 100644
index 0000000000..334fb98879
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/reactor.cpp
@@ -0,0 +1,297 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * aint32 with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/pegasus.h"
+#include "pegasus/neighborhood/mars/reactor.h"
+
+namespace Pegasus {
+
+static const CoordType kCurrentGuessWidth = 121;
+static const CoordType kCurrentGuessHeight = 23;
+
+static const CoordType kOneGuessWidth = 25;
+static const CoordType kOneGuessHeight = 23;
+
+static const ResIDType kReactorChoicesPICTID = 905;
+
+static const CoordType kCurrentGuessLeft = kNavAreaLeft + 146;
+static const CoordType kCurrentGuessTop = kNavAreaTop + 90;
+
+ReactorGuess::ReactorGuess(const DisplayElementID id) : DisplayElement(id) {
+ setBounds(kCurrentGuessLeft, kCurrentGuessTop, kCurrentGuessLeft + kCurrentGuessWidth,
+ kCurrentGuessTop + kCurrentGuessHeight);
+ setDisplayOrder(kMonitorLayer);
+ _currentGuess[0] = -1;
+ _currentGuess[1] = -1;
+ _currentGuess[2] = -1;
+}
+
+void ReactorGuess::initReactorGuess() {
+ _colors.getImageFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kReactorChoicesPICTID);
+ startDisplaying();
+ show();
+}
+
+void ReactorGuess::disposeReactorGuess() {
+ stopDisplaying();
+ _colors.deallocateSurface();
+}
+
+void ReactorGuess::setGuess(int32 a, int32 b, int32 c) {
+ _currentGuess[0] = a;
+ _currentGuess[1] = b;
+ _currentGuess[2] = c;
+ triggerRedraw();
+}
+
+void ReactorGuess::draw(const Common::Rect &) {
+ if (_colors.isSurfaceValid()) {
+ Common::Rect r1(0, 0, kOneGuessWidth, kOneGuessHeight);
+ Common::Rect r2 = r1;
+
+ for (int i = 0; i < 3; i++) {
+ if (_currentGuess[i] >= 0) {
+ r1.moveTo(kOneGuessWidth * _currentGuess[i], 0);
+ r2.moveTo(kCurrentGuessLeft + 48 * i, kCurrentGuessTop);
+ _colors.copyToCurrentPortTransparent(r1, r2);
+ }
+ }
+ }
+}
+
+static const CoordType kReactorChoiceHiliteWidth = 166;
+static const CoordType kReactorChoiceHiliteHeight = 26;
+
+static const CoordType kChoiceHiliteLefts[6] = {
+ 0,
+ 34,
+ 34 + 34,
+ 34 + 34 + 32,
+ 34 + 34 + 32 + 34,
+ 34 + 34 + 32 + 34 + 32
+};
+
+static const ResIDType kReactorChoiceHilitePICTID = 901;
+
+static const CoordType kReactorChoiceHiliteLeft = kNavAreaLeft + 116;
+static const CoordType kReactorChoiceHiliteTop = kNavAreaTop + 158;
+
+ReactorChoiceHighlight::ReactorChoiceHighlight(const DisplayElementID id) : DisplayElement(id) {
+ setBounds(kReactorChoiceHiliteLeft, kReactorChoiceHiliteTop, kReactorChoiceHiliteLeft + kReactorChoiceHiliteWidth,
+ kReactorChoiceHiliteTop + kReactorChoiceHiliteHeight);
+ setDisplayOrder(kMonitorLayer);
+}
+
+void ReactorChoiceHighlight::initReactorChoiceHighlight() {
+ _colors.getImageFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kReactorChoiceHilitePICTID);
+ startDisplaying();
+ show();
+}
+
+void ReactorChoiceHighlight::disposeReactorChoiceHighlight() {
+ stopDisplaying();
+ _colors.deallocateSurface();
+}
+
+void ReactorChoiceHighlight::draw(const Common::Rect &) {
+ if (_colors.isSurfaceValid()) {
+ for (int i = 0; i < 5; ++i) {
+ if (_choices.getFlag(i)) {
+ Common::Rect r1(0, 0, kChoiceHiliteLefts[i + 1] - kChoiceHiliteLefts[i], kReactorChoiceHiliteHeight);
+ Common::Rect r2 = r1;
+ r1.moveTo(kChoiceHiliteLefts[i], 0);
+ r2.moveTo(kReactorChoiceHiliteLeft + kChoiceHiliteLefts[i], kReactorChoiceHiliteTop);
+ _colors.copyToCurrentPort(r1, r2);
+ }
+ }
+ }
+}
+
+static const CoordType kReactorHistoryWidth = 128;
+static const CoordType kReactorHistoryHeight = 168;
+
+static const CoordType kColorWidths[5] = { 24, 25, 25, 26, 27 };
+static const CoordType kColorHeights[5] = { 14, 15, 17, 17, 19};
+
+static const CoordType kHistoryLefts[5][3] = {
+ { 302 + kNavAreaLeft, 329 + kNavAreaLeft, 357 + kNavAreaLeft },
+ { 302 + kNavAreaLeft, 331 + kNavAreaLeft, 360 + kNavAreaLeft },
+ { 303 + kNavAreaLeft, 333 + kNavAreaLeft, 363 + kNavAreaLeft },
+ { 304 + kNavAreaLeft, 335 + kNavAreaLeft, 366 + kNavAreaLeft },
+ { 305 + kNavAreaLeft, 337 + kNavAreaLeft, 369 + kNavAreaLeft }
+};
+
+static const CoordType kHistoryTops[5] = {
+ 39 + kNavAreaTop,
+ 61 + kNavAreaTop,
+ 84 + kNavAreaTop,
+ 110 + kNavAreaTop,
+ 137 + kNavAreaTop
+};
+
+static const CoordType kOneAnswerWidth = 35;
+static const CoordType kOneAnswerHeight = 27;
+
+static const CoordType kDigitWidth = 16;
+static const CoordType kDigitHeight = 12;
+
+static const CoordType kCorrectCountLefts[5] = {
+ 388 + kNavAreaLeft,
+ 392 + kNavAreaLeft,
+ 398 + kNavAreaLeft,
+ 402 + kNavAreaLeft,
+ 406 + kNavAreaLeft
+};
+
+static const CoordType kCorrectCountTops[5] = {
+ 40 + kNavAreaTop,
+ 62 + kNavAreaTop,
+ 86 + kNavAreaTop,
+ 112 + kNavAreaTop,
+ 140 + kNavAreaTop
+};
+
+static const ResIDType kReactorDigitsPICTID = 902;
+static const ResIDType kReactorHistoryPICTID = 903;
+static const ResIDType kReactorAnswerPICTID = 904;
+
+static const CoordType kReactorHistoryLeft = kNavAreaLeft + 302;
+static const CoordType kReactorHistoryTop = kNavAreaTop + 39;
+
+static const CoordType kAnswerLeft = kNavAreaLeft + 304;
+static const CoordType kAnswerTop = kNavAreaTop + 180;
+
+ReactorHistory::ReactorHistory(const DisplayElementID id) : DisplayElement(id) {
+ setBounds(kReactorHistoryLeft, kReactorHistoryTop, kReactorHistoryLeft + kReactorHistoryWidth,
+ kReactorHistoryTop + kReactorHistoryHeight);
+ setDisplayOrder(kMonitorLayer);
+ _numGuesses = 0;
+ _answer[0] = -1;
+ _answer[1] = -1;
+ _answer[2] = -1;
+ _showAnswer = false;
+}
+
+void ReactorHistory::initReactorHistory() {
+ _colors.getImageFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kReactorHistoryPICTID);
+ _digits.getImageFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kReactorDigitsPICTID);
+ _answerColors.getImageFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kReactorAnswerPICTID);
+ startDisplaying();
+ show();
+}
+
+void ReactorHistory::disposeReactorHistory() {
+ stopDisplaying();
+ _colors.deallocateSurface();
+}
+
+void ReactorHistory::addGuess(int32 a, int32 b, int32 c) {
+ _history[_numGuesses][0] = a;
+ _history[_numGuesses][1] = b;
+ _history[_numGuesses][2] = c;
+ _numGuesses++;
+ triggerRedraw();
+}
+
+void ReactorHistory::clearHistory() {
+ _numGuesses = 0;
+ _showAnswer = false;
+ triggerRedraw();
+}
+
+void ReactorHistory::setAnswer(int32 a, int32 b, int32 c) {
+ _answer[0] = a;
+ _answer[1] = b;
+ _answer[2] = c;
+}
+
+void ReactorHistory::showAnswer() {
+ _showAnswer = true;
+ triggerRedraw();
+}
+
+bool ReactorHistory::isSolved() {
+ for (int i = 0; i < _numGuesses; i++)
+ if (_history[i][0] == _answer[0] && _history[i][1] == _answer[1] && _history[i][2] == _answer[2])
+ return true;
+
+ return false;
+}
+
+void ReactorHistory::draw(const Common::Rect &) {
+ static const CoordType kColorTops[5] = {
+ 0,
+ kColorHeights[0],
+ kColorHeights[0] + kColorHeights[1],
+ kColorHeights[0] + kColorHeights[1] + kColorHeights[2],
+ kColorHeights[0] + kColorHeights[1] + kColorHeights[2] + kColorHeights[3],
+ };
+
+ if (_colors.isSurfaceValid() && _digits.isSurfaceValid()) {
+ for (int i = 0; i < _numGuesses; ++i) {
+ Common::Rect r1(0, 0, kColorWidths[i], kColorHeights[i]);
+ Common::Rect r2 = r1;
+ Common::Rect r3(0, 0, kDigitWidth, kDigitHeight);
+ Common::Rect r4 = r3;
+ int correct = 0;
+
+ for (int j = 0; j < 3; ++j) {
+ r1.moveTo(kColorWidths[i] * _history[i][j], kColorTops[i]);
+ r2.moveTo(kHistoryLefts[i][j], kHistoryTops[i]);
+ _colors.copyToCurrentPortTransparent(r1, r2);
+
+ if (_history[i][j] == _answer[j])
+ correct++;
+ }
+
+ r3.moveTo(kDigitWidth * correct, 0);
+ r4.moveTo(kCorrectCountLefts[i], kCorrectCountTops[i]);
+ _digits.copyToCurrentPort(r3, r4);
+ }
+
+ if (_showAnswer && _answerColors.isSurfaceValid()) {
+ Common::Rect r1(0, 0, kOneAnswerWidth, kOneAnswerHeight);
+ Common::Rect r2 = r1;
+
+ for (int i = 0; i < 3; i++) {
+ r1.moveTo(kOneAnswerWidth * _answer[i], 0);
+ r2.moveTo(kAnswerLeft + 34 * i, kAnswerTop);
+ _answerColors.copyToCurrentPortTransparent(r1, r2);
+ }
+ }
+ }
+}
+
+int32 ReactorHistory::getCurrentNumCorrect() {
+ int correct = 0;
+
+ for (int i = 0; i < 3; i++)
+ if (_history[_numGuesses - 1][i] == _answer[i])
+ correct++;
+
+ return correct;
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/mars/reactor.h b/engines/pegasus/neighborhood/mars/reactor.h
new file mode 100644
index 0000000000..86338f8266
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/reactor.h
@@ -0,0 +1,108 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_MARS_REACTOR_H
+#define PEGASUS_NEIGHBORHOOD_MARS_REACTOR_H
+
+#include "pegasus/elements.h"
+#include "pegasus/surface.h"
+#include "pegasus/util.h"
+
+namespace Pegasus {
+
+class ReactorGuess : public DisplayElement {
+public:
+ ReactorGuess(const DisplayElementID);
+ virtual ~ReactorGuess() {}
+
+ void initReactorGuess();
+ void disposeReactorGuess();
+
+ void setGuess(int32, int32, int32);
+
+ void draw(const Common::Rect &);
+
+protected:
+ int32 _currentGuess[3];
+
+ Surface _colors;
+};
+
+class ReactorChoiceHighlight : public DisplayElement {
+public:
+ ReactorChoiceHighlight(const DisplayElementID);
+ virtual ~ReactorChoiceHighlight() {}
+
+ void initReactorChoiceHighlight();
+ void disposeReactorChoiceHighlight();
+
+ void resetHighlight() {
+ _choices.clearAllFlags();
+ triggerRedraw();
+ }
+
+ bool choiceHighlighted(uint32 whichChoice) { return _choices.getFlag(whichChoice); }
+
+ void draw(const Common::Rect &);
+
+ void highlightChoice(uint32 whichChoice) {
+ _choices.setFlag(whichChoice);
+ triggerRedraw();
+ }
+
+protected:
+ Surface _colors;
+ FlagsArray<byte, 5> _choices;
+};
+
+class ReactorHistory : public DisplayElement {
+public:
+ ReactorHistory(const DisplayElementID);
+ virtual ~ReactorHistory() {}
+
+ void initReactorHistory();
+ void disposeReactorHistory();
+
+ void draw(const Common::Rect &);
+
+ void addGuess(int32, int32, int32);
+ int32 getNumGuesses() { return _numGuesses; }
+ void clearHistory();
+ void setAnswer(int32, int32, int32);
+ void showAnswer();
+ bool isSolved();
+ int32 getCurrentNumCorrect();
+
+protected:
+ Surface _colors, _digits, _answerColors;
+ int32 _answer[3];
+ int32 _history[5][3];
+ int32 _numGuesses;
+ bool _showAnswer;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/mars/robotship.cpp b/engines/pegasus/neighborhood/mars/robotship.cpp
new file mode 100644
index 0000000000..1f4bbc1779
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/robotship.cpp
@@ -0,0 +1,267 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/gamestate.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/neighborhood/mars/hermite.h"
+#include "pegasus/neighborhood/mars/mars.h"
+#include "pegasus/neighborhood/mars/robotship.h"
+#include "pegasus/neighborhood/mars/spacechase3d.h"
+#include "pegasus/neighborhood/mars/spacejunk.h"
+
+namespace Pegasus {
+
+static const TimeScale kRovingScale = kTractorBeamScale;
+static const TimeValue kRovingTime = kSixSeconds * kRovingScale;
+static const TimeValue kRovingSlop = kThreeSeconds * kRovingScale;
+
+static const int kNumSpriteColumns = 15;
+static const int kNumSpriteRows = 16;
+
+static const CoordType kInitialLocationLeft = kShuttleWindowLeft - 50;
+static const CoordType kInitialLocationTop = kShuttleWindowTop - 50;
+static const CoordType kInitialLocationWidth = kShuttleWindowWidth + 100;
+static const CoordType kInitialLocationHeight = kShuttleWindowHeight + 100;
+
+static const CoordType kVelocityVectorLength = 100;
+static const CoordType kVelocityVectorSlop = 50;
+
+static const CoordType kRovingLeft = kShuttleWindowLeft + 20;
+static const CoordType kRovingTop = kShuttleWindowTop + 20;
+static const CoordType kRovingWidth = kShuttleWindowMidH - kRovingLeft;
+static const CoordType kRovingHeight = kShuttleWindowMidV - kRovingTop;
+
+RobotShip *g_robotShip = 0;
+
+RobotShip::RobotShip() : _spritesMovie(kNoDisplayElement) {
+ g_robotShip = this;
+ _shipRange = Common::Rect(kShuttleWindowLeft, kShuttleWindowTop, kShuttleWindowLeft + kShuttleWindowWidth,
+ kShuttleWindowTop + kShuttleWindowHeight);
+ setScale(kRovingScale);
+ _currentLocation.x = 0;
+ _currentLocation.y = 0;
+ _snaring = false;
+ _dropJunkFuse.setFunctor(new Common::Functor0Mem<void, RobotShip>(this, &RobotShip::timeToDropJunk));
+ _duration = 0xFFFFFFFF;
+}
+
+RobotShip::~RobotShip() {
+ g_robotShip = 0;
+}
+
+void RobotShip::initRobotShip() {
+ _spritesMovie.initFromMovieFile("Images/Mars/Ship.movie", true);
+ _spritesMovie.setDisplayOrder(kShuttleRobotShipOrder);
+ _spritesMovie.moveElementTo(kPlanetStartLeft, kPlanetStartTop);
+ _spritesMovie.startDisplaying();
+ _spritesMovie.show();
+
+ Common::Rect r;
+ _spritesMovie.getBounds(r);
+ _shipWidth = r.width();
+ _shipHeight = r.height();
+ _dead = false;
+}
+
+void RobotShip::cleanUpRobotShip() {
+ _dropJunkFuse.stopFuse();
+ _spritesMovie.stopDisplaying();
+ _spritesMovie.releaseMovie();
+}
+
+void RobotShip::startMoving() {
+ if (((PegasusEngine *)g_engine)->getRandomBit()) {
+ _p4.x = kInitialLocationLeft + ((PegasusEngine *)g_engine)->getRandomNumber(kInitialLocationWidth - 1);
+ if (((PegasusEngine *)g_engine)->getRandomBit())
+ _p4.y = kInitialLocationTop;
+ else
+ _p4.y = kInitialLocationTop + kInitialLocationHeight;
+ } else {
+ _p4.y = kInitialLocationTop + ((PegasusEngine *)g_engine)->getRandomNumber(kInitialLocationHeight - 1);
+ if (((PegasusEngine *)g_engine)->getRandomBit())
+ _p4.x = kInitialLocationLeft;
+ else
+ _p4.x = kInitialLocationLeft + kInitialLocationWidth;
+ }
+
+ makeVelocityVector(_p4.x, _p4.y, kShuttleWindowLeft + kShuttleWindowWidth / 2,
+ kShuttleWindowTop + kShuttleWindowHeight / 2, _r4);
+ newDestination();
+ setUpNextDropTime();
+}
+
+void RobotShip::killRobotShip() {
+ cleanUpRobotShip();
+ _dead = true;
+}
+
+void RobotShip::setUpNextDropTime() {
+ if (!isSnared()) {
+ _dropJunkFuse.primeFuse(kJunkDropBaseTime + ((PegasusEngine *)g_engine)->getRandomNumber(kJunkDropSlopTime));
+ _dropJunkFuse.lightFuse();
+ }
+}
+
+void RobotShip::timeToDropJunk() {
+ if (g_spaceJunk) {
+ CoordType x, y;
+ _spritesMovie.getCenter(x, y);
+ g_spaceJunk->launchJunk(((PegasusEngine *)g_engine)->getRandomNumber(24), x, y);
+ }
+}
+
+void RobotShip::newDestination() {
+ _p1 = _p4;
+ _r1 = _r4;
+
+ _p4.x = kRovingLeft + ((PegasusEngine *)g_engine)->getRandomNumber(kRovingWidth - 1);
+ _p4.y = kRovingTop + ((PegasusEngine *)g_engine)->getRandomNumber(kRovingHeight - 1);
+
+ if (((PegasusEngine *)g_engine)->getRandomNumber(7) < 6) {
+ if (!sameSign(_p4.x - kShuttleWindowMidH, kShuttleWindowMidH - _p1.x)) {
+ if (sign(_p4.x - kShuttleWindowMidH) > 0)
+ _p4.x -= kRovingWidth;
+ else
+ _p4.x += kRovingWidth;
+ }
+ }
+
+ if (((PegasusEngine *)g_engine)->getRandomNumber(7) < 6) {
+ if (!sameSign(_p4.y - kShuttleWindowMidV, kShuttleWindowMidV - _p1.y)) {
+ if (sign(_p4.y - kShuttleWindowMidV) > 0)
+ _p4.y -= kRovingHeight;
+ else
+ _p4.y += kRovingHeight;
+ }
+ }
+
+ makeVelocityVector(_p4.x, _p4.y, kShuttleWindowLeft + kShuttleWindowWidth / 2,
+ kShuttleWindowTop + kShuttleWindowHeight / 2, _r4);
+ stop();
+ _duration = kRovingTime + ((PegasusEngine *)g_engine)->getRandomNumber(kRovingSlop - 1);
+ setSegment(0, _duration);
+ setTime(0);
+ start();
+}
+
+void RobotShip::moveRobotTo(CoordType x, CoordType y) {
+ _currentLocation.x = x;
+ _currentLocation.y = y;
+
+ if (_spritesMovie.isMovieValid()) {
+ _spritesMovie.moveElementTo(x - (_shipWidth >> 1), y - (_shipHeight >> 1));
+
+ if (x < _shipRange.left)
+ x = 0;
+ else if (x > _shipRange.right - 1)
+ x = _shipRange.width() - 1;
+ else
+ x -= _shipRange.left;
+
+ if (y < _shipRange.top)
+ y = 0;
+ else if (y > _shipRange.bottom - 1)
+ y = _shipRange.height() - 1;
+ else
+ y -= _shipRange.top;
+
+ x = kNumSpriteColumns * x / _shipRange.width();
+ y = kNumSpriteRows * y / _shipRange.height();
+
+ _spritesMovie.setTime(40 * (x + y * kNumSpriteColumns));
+ _spritesMovie.redrawMovieWorld();
+ }
+}
+
+bool RobotShip::pointInShuttle(Common::Point &pt) {
+ Common::Rect r;
+ _spritesMovie.getBounds(r);
+
+ int dx = r.width() / 4;
+ int dy = r.height() / 6;
+
+ r.left += dx;
+ r.right -= dx;
+ r.top += dy;
+ r.bottom -= dy;
+
+ return r.contains(pt);
+}
+
+void RobotShip::hitByEnergyBeam(Common::Point impactPoint) {
+ ((Mars *)g_neighborhood)->decreaseRobotShuttleEnergy(1, impactPoint);
+ setGlowing(true);
+ ((PegasusEngine *)g_engine)->delayShell(1, 3);
+ setGlowing(false);
+}
+
+void RobotShip::hitByGravitonCannon(Common::Point impactPoint) {
+ GameState.setMarsHitRobotWithCannon(true);
+ ((Mars *)g_neighborhood)->decreaseRobotShuttleEnergy(6, impactPoint);
+}
+
+void RobotShip::snareByTractorBeam() {
+ _dropJunkFuse.stopFuse();
+ stop();
+
+ Common::Point currentV;
+ dHermite(_p1, _p4, _r1, _r4, _lastTime, _duration, currentV);
+
+ _p1 = _currentLocation;
+ _r1 = currentV;
+ _p4.x = kShuttleWindowMidH;
+ _p4.y = kShuttleWindowMidV;
+ _r4.x = 0;
+ _r4.y = 0;
+ _duration = kTractorBeamTime;
+ _snaring = true;
+ setSegment(0, _duration);
+ setTime(0);
+ start();
+}
+
+void RobotShip::timeChanged(const TimeValue) {
+ Common::Point newLocation;
+ hermite(_p1, _p4, _r1, _r4, _lastTime, _duration, newLocation);
+ moveRobotTo(newLocation.x, newLocation.y);
+
+ if (_lastTime == _duration) {
+ if (_snaring)
+ stop();
+ else
+ newDestination();
+ }
+}
+
+void RobotShip::makeVelocityVector(CoordType x1, CoordType y1, CoordType x2, CoordType y2, Common::Point &vector) {
+ CoordType length = ((PegasusEngine *)g_engine)->getRandomNumber(kVelocityVectorSlop - 1) + kVelocityVectorLength;
+ vector.x = x2 - x1;
+ vector.y = y2 - y1;
+ float oldLength = sqrt((float)(vector.x * vector.x + vector.y * vector.y));
+ vector.x = (int)(vector.x * length / oldLength);
+ vector.y = (int)(vector.y * length / oldLength);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/mars/robotship.h b/engines/pegasus/neighborhood/mars/robotship.h
new file mode 100644
index 0000000000..04be3ea56e
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/robotship.h
@@ -0,0 +1,84 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_MARS_ROBOTSHIP_H
+#define PEGASUS_NEIGHBORHOOD_MARS_ROBOTSHIP_H
+
+#include "pegasus/movie.h"
+
+namespace Pegasus {
+
+static const CoordType kShuttleMovieWidth = 114;
+static const CoordType kShuttleMovieHeight = 42;
+
+class RobotShip : IdlerTimeBase {
+public:
+ RobotShip();
+ virtual ~RobotShip();
+
+ void initRobotShip();
+ void cleanUpRobotShip();
+
+ void startMoving();
+
+ void killRobotShip();
+
+ bool pointInShuttle(Common::Point&);
+
+ void hitByEnergyBeam(Common::Point impactPoint);
+ void hitByGravitonCannon(Common::Point impactPoint);
+
+ void getShuttleBounds(Common::Rect &r) { _spritesMovie.getBounds(r); }
+
+ void setGlowing(const bool glowing) { _spritesMovie.setGlowing(glowing); }
+
+ void snareByTractorBeam();
+ bool isSnared() { return _snaring && getTime() == _duration; }
+
+ bool isDead() { return _dead; }
+
+ void setUpNextDropTime();
+
+protected:
+ void newDestination();
+ void moveRobotTo(CoordType, CoordType);
+ void timeToDropJunk();
+ virtual void timeChanged(const TimeValue);
+ void makeVelocityVector(CoordType, CoordType, CoordType, CoordType, Common::Point &);
+
+ GlowingMovie _spritesMovie;
+ Common::Rect _shipRange;
+ int _shipWidth, _shipHeight;
+ Common::Point _p1, _p4, _r1, _r4, _currentLocation;
+ FuseFunction _dropJunkFuse;
+ TimeValue _duration;
+ bool _snaring, _dead;
+};
+
+extern RobotShip *g_robotShip;
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/mars/shuttleenergymeter.cpp b/engines/pegasus/neighborhood/mars/shuttleenergymeter.cpp
new file mode 100644
index 0000000000..cd08dbae6a
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/shuttleenergymeter.cpp
@@ -0,0 +1,116 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/neighborhood/mars/constants.h"
+#include "pegasus/neighborhood/mars/shuttleenergymeter.h"
+
+namespace Pegasus {
+
+ShuttleEnergyMeter::ShuttleEnergyMeter() : FaderAnimation(kNoDisplayElement) {
+ setBounds(kShuttleEnergyLeft, kShuttleEnergyTop, kShuttleEnergyLeft + kShuttleEnergyWidth,
+ kShuttleEnergyTop + kShuttleEnergyHeight);
+ setDisplayOrder(kShuttleStatusOrder);
+ setFaderValue(0);
+}
+
+void ShuttleEnergyMeter::initShuttleEnergyMeter() {
+ _meterImage.getImageFromPICTFile("Images/Mars/Shuttle Energy.pict");
+ _lowWarning.getImageFromPICTFile("Images/Mars/Shuttle Low Energy.pict");
+ startDisplaying();
+ show();
+}
+
+void ShuttleEnergyMeter::disposeShuttleEnergyMeter() {
+ stopFader();
+ hide();
+ stopDisplaying();
+ _meterImage.deallocateSurface();
+ _lowWarning.deallocateSurface();
+}
+
+void ShuttleEnergyMeter::draw(const Common::Rect &) {
+ int32 currentValue = getFaderValue();
+
+ Common::Rect r1, r2, bounds;
+ getBounds(bounds);
+
+ if (currentValue < kLowShuttleEnergy) {
+ _lowWarning.getSurfaceBounds(r1);
+ r2 = r1;
+ r2.moveTo(bounds.left, bounds.top);
+ _lowWarning.copyToCurrentPort(r1, r2);
+ }
+
+ _meterImage.getSurfaceBounds(r1);
+ r1.right = r1.left + r1.width() * currentValue / kFullShuttleEnergy;
+ r2 = r1;
+ r2.moveTo(bounds.left + 102, bounds.top + 6);
+ _meterImage.copyToCurrentPort(r1, r2);
+}
+
+void ShuttleEnergyMeter::powerUpMeter() {
+ FaderMoveSpec moveSpec;
+ moveSpec.makeTwoKnotFaderSpec(kThirtyTicksPerSecond, 0, 0, 45, kFullShuttleEnergy);
+ startFader(moveSpec);
+}
+
+void ShuttleEnergyMeter::setEnergyValue(const int32 value) {
+ stopFader();
+ FaderMoveSpec moveSpec;
+ moveSpec.makeTwoKnotFaderSpec(kFifteenTicksPerSecond, value * 3, value, kFullShuttleEnergy * 3, kFullShuttleEnergy);
+ startFader(moveSpec);
+}
+
+void ShuttleEnergyMeter::drainForTractorBeam() {
+ stopFader();
+ TimeValue startTime = 0, stopTime;
+ int32 startValue = getFaderValue(), stopValue;
+
+ if (startValue < kTractorBeamEnergy) {
+ stopTime = startValue * kTractorBeamTime / kTractorBeamEnergy;
+ stopValue = 0;
+ } else {
+ stopTime = kTractorBeamTime;
+ stopValue = startValue - kTractorBeamEnergy;
+ }
+
+ FaderMoveSpec moveSpec;
+ moveSpec.makeTwoKnotFaderSpec(kTractorBeamScale, startTime, startValue, stopTime, stopValue);
+ startFader(moveSpec);
+}
+
+int32 ShuttleEnergyMeter::getEnergyValue() const {
+ return getFaderValue();
+}
+
+void ShuttleEnergyMeter::dropEnergyValue(const int32 delta) {
+ setEnergyValue(getFaderValue() - delta);
+}
+
+bool ShuttleEnergyMeter::enoughEnergyForTractorBeam() const {
+ return getEnergyValue() >= kTractorBeamEnergy;
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/mars/shuttleenergymeter.h b/engines/pegasus/neighborhood/mars/shuttleenergymeter.h
new file mode 100644
index 0000000000..51161e094e
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/shuttleenergymeter.h
@@ -0,0 +1,73 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_MARS_SHUTTLEENERGYMETER_H
+#define PEGASUS_NEIGHBORHOOD_MARS_SHUTTLEENERGYMETER_H
+
+#include "pegasus/fader.h"
+#include "pegasus/surface.h"
+
+namespace Pegasus {
+
+static const int32 kFullShuttleEnergy = 100;
+// Low is 20 percent
+static const int32 kLowShuttleEnergy = kFullShuttleEnergy * 20 / 100;
+
+static const int32 kMinDampingEnergy = 15;
+static const int32 kMinGravitonEnergy = 63;
+
+static const TimeScale kTractorBeamScale = kFifteenTicksPerSecond;
+static const TimeValue kTractorBeamTime = kFiveSeconds * kTractorBeamScale;
+static const int32 kTractorBeamEnergy = kLowShuttleEnergy;
+
+class ShuttleEnergyMeter : public FaderAnimation {
+public:
+ ShuttleEnergyMeter();
+ ~ShuttleEnergyMeter() {}
+
+ void initShuttleEnergyMeter();
+ void disposeShuttleEnergyMeter();
+
+ void powerUpMeter();
+
+ void setEnergyValue(const int32);
+ int32 getEnergyValue() const;
+
+ void dropEnergyValue(const int32);
+
+ void drainForTractorBeam();
+
+ bool enoughEnergyForTractorBeam() const;
+
+ void draw(const Common::Rect &);
+
+protected:
+ Surface _meterImage;
+ Surface _lowWarning;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/mars/shuttlehud.cpp b/engines/pegasus/neighborhood/mars/shuttlehud.cpp
new file mode 100644
index 0000000000..11e826278b
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/shuttlehud.cpp
@@ -0,0 +1,246 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/pegasus.h"
+#include "pegasus/neighborhood/mars/constants.h"
+#include "pegasus/neighborhood/mars/robotship.h"
+#include "pegasus/neighborhood/mars/shuttlehud.h"
+
+namespace Pegasus {
+
+static const CoordType kHUDTargetGridLeft = kShuttleWindowLeft + 16;
+static const CoordType kHUDTargetGridTop = kShuttleWindowTop + 8;
+static const CoordType kHUDTargetGridWidth = 328;
+static const CoordType kHUDTargetGridHeight = 206;
+
+static const CoordType kHUDRS232Left = kHUDTargetGridLeft + 264;
+static const CoordType kHUDRS232Top = kHUDTargetGridTop + 2;
+
+static const CoordType kHUDLockLeft = kShuttleWindowLeft + 101;
+static const CoordType kHUDLockTop = kShuttleWindowTop + 49;
+static const CoordType kHUDLockWidth = 145;
+static const CoordType kHUDLockHeight = 124;
+
+static const CoordType kTractorLockWidth = 50;
+static const CoordType kTractorLockHeight = 30;
+
+static const CoordType kTractorLockLeft = kShuttleWindowMidH - kTractorLockWidth / 2;
+static const CoordType kTractorLockTop = kShuttleWindowMidV - kTractorLockHeight / 2;
+static const CoordType kTractorLockRight = kTractorLockLeft + kTractorLockWidth;
+static const CoordType kTractorLockBottom = kTractorLockTop + kTractorLockHeight;
+
+static const uint16 s_RS232Data[] = {
+ 0xF0E1, 0xCE70,
+ 0xF9E1, 0xEF78,
+ 0x4900, 0x2108,
+ 0x79C0, 0xE738,
+ 0x70E1, 0xC770,
+ 0x5821, 0x0140,
+ 0x4DE1, 0xEF78,
+ 0x45C1, 0xEE78
+};
+
+static const uint16 s_lockData[] = {
+ 0xE007, 0xFE1F, 0xF8E0, 0x7000,
+ 0xE00F, 0xFF3F, 0xFCE0, 0xE000,
+ 0xE00E, 0x0738, 0x1CE1, 0xC000,
+ 0xE00E, 0x0738, 0x00FF, 0x8000,
+ 0xE00E, 0x0738, 0x00FF, 0x0000,
+ 0xE00E, 0x0738, 0x00E3, 0x8000,
+ 0xE00E, 0x0738, 0x1CE1, 0xC000,
+ 0xFFCF, 0xFF3F, 0xFCE0, 0xE000,
+ 0xFFC7, 0xFE1F, 0xF8E0, 0x7000
+};
+
+#define drawHUDLockLine(x1, y1, x2, y2, penX, penY, color) \
+ screen->drawThickLine((x1) + kHUDLockLeft, (y1) + kHUDLockTop, \
+ (x2) + kHUDLockLeft, (y2) + kHUDLockTop, penX, penY, color)
+
+#define drawHUDLockArrows(offset, color) \
+ drawHUDLockLine(63, 0 + (offset), 68, 5 + (offset), 1, 3, color); \
+ drawHUDLockLine(71, 8 + (offset), 77, 14 + (offset), 1, 3, color); \
+ drawHUDLockLine(78, 14 + (offset), 84, 8 + (offset), 1, 3, color); \
+ drawHUDLockLine(87, 5 + (offset), 92, 0 + (offset), 1, 3, color); \
+ drawHUDLockLine(63, 121 - (offset), 68, 116 - (offset), 1, 3, color); \
+ drawHUDLockLine(71, 113 - (offset), 77, 107 - (offset), 1, 3, color); \
+ drawHUDLockLine(78, 107 - (offset), 84, 113 - (offset), 1, 3, color); \
+ drawHUDLockLine(87, 116 - (offset), 92, 121 - (offset), 1, 3, color); \
+\
+ drawHUDLockLine(13 + (offset), 47, 18 + (offset), 52, 3, 1, color); \
+ drawHUDLockLine(21 + (offset), 55, 27 + (offset), 61, 3, 1, color); \
+ drawHUDLockLine(27 + (offset), 62, 21 + (offset), 68, 3, 1, color); \
+ drawHUDLockLine(18 + (offset), 71, 13 + (offset), 76, 3, 1, color); \
+ drawHUDLockLine(142 - (offset), 47, 137 - (offset), 52, 3, 1, color); \
+ drawHUDLockLine(134 - (offset), 55, 128 - (offset), 61, 3, 1, color); \
+ drawHUDLockLine(128 - (offset), 62, 134 - (offset), 68, 3, 1, color); \
+ drawHUDLockLine(137 - (offset), 71, 142 - (offset), 76, 3, 1, color)
+
+ShuttleHUD::ShuttleHUD() : DisplayElement(kNoDisplayElement) {
+ _lightGreen = g_system->getScreenFormat().RGBToColor(0, 204, 0);
+ _gridDarkGreen = g_system->getScreenFormat().RGBToColor(0, 85, 0);
+ _lockDarkGreen1 = g_system->getScreenFormat().RGBToColor(0, 68, 0);
+ _lockDarkGreen2 = g_system->getScreenFormat().RGBToColor(0, 65, 0);
+
+ _targetLocked = false;
+ setBounds(kShuttleWindowLeft, kShuttleWindowTop, kShuttleWindowLeft + kShuttleWindowWidth,
+ kShuttleWindowTop + kShuttleWindowHeight);
+ setDisplayOrder(kShuttleHUDOrder);
+}
+
+void ShuttleHUD::initShuttleHUD() {
+ startDisplaying();
+ startIdling();
+}
+
+void ShuttleHUD::cleanUpShuttleHUD() {
+ stopIdling();
+ stopDisplaying();
+}
+
+void ShuttleHUD::showTargetGrid() {
+ show();
+}
+
+void ShuttleHUD::hideTargetGrid() {
+ hide();
+ unlockOnTarget();
+}
+
+void ShuttleHUD::useIdleTime() {
+ if (isVisible()) {
+ Common::Rect r;
+ g_robotShip->getShuttleBounds(r);
+ if (r.left < kTractorLockRight && r.right > kTractorLockLeft && r.top < kTractorLockBottom && r.bottom > kTractorLockTop)
+ lockOnTarget();
+ else
+ unlockOnTarget();
+ }
+}
+
+void ShuttleHUD::lockOnTarget() {
+ if (!_targetLocked) {
+ _targetLocked = true;
+ triggerRedraw();
+ }
+}
+
+void ShuttleHUD::unlockOnTarget() {
+ if (_targetLocked) {
+ _targetLocked = false;
+ triggerRedraw();
+ }
+}
+
+void ShuttleHUD::draw(const Common::Rect &) {
+ Graphics::Surface *screen = ((PegasusEngine *)g_engine)->_gfx->getWorkArea();
+
+ for (int y = 0; y < 35; y++) {
+ Common::Rect r;
+
+ if (y & 1) {
+ if (y == 17) {
+ r = Common::Rect(0, 0, 4, 2);
+ r.moveTo(kHUDTargetGridLeft + 8, y * 6 + kHUDTargetGridTop);
+ screen->fillRect(r, _gridDarkGreen);
+ r.moveTo(kHUDTargetGridLeft + kHUDTargetGridWidth - 12, y * 6 + kHUDTargetGridTop);
+ screen->fillRect(r, _gridDarkGreen);
+
+ r = Common::Rect(0, 0, 6, 2);
+ r.moveTo(kHUDTargetGridLeft + 2, y * 6 + kHUDTargetGridTop);
+ screen->fillRect(r, _lightGreen);
+ r.moveTo(kHUDTargetGridLeft + kHUDTargetGridWidth - 8, y * 6 + kHUDTargetGridTop);
+ screen->fillRect(r, _lightGreen);
+
+ r = Common::Rect(0, 0, 23, 2);
+ r.moveTo(kHUDTargetGridLeft + 12, y * 6 + kHUDTargetGridTop);
+ screen->fillRect(r, _lightGreen);
+ r.moveTo(kHUDTargetGridLeft + kHUDTargetGridWidth - 35, y * 6 + kHUDTargetGridTop);
+ screen->fillRect(r, _lightGreen);
+ } else if (y == 1 || y == 15 || y == 19 || y == 33) {
+ r = Common::Rect(0, 0, 4, 2);
+ r.moveTo(kHUDTargetGridLeft + 2, y * 6 + kHUDTargetGridTop);
+ screen->fillRect(r, _gridDarkGreen);
+ r.moveTo(kHUDTargetGridLeft + kHUDTargetGridWidth - 6, y * 6 + kHUDTargetGridTop);
+ screen->fillRect(r, _gridDarkGreen);
+
+ r = Common::Rect(0, 0, 15, 2);
+ r.moveTo(kHUDTargetGridLeft + 8, y * 6 + kHUDTargetGridTop);
+ screen->fillRect(r, _gridDarkGreen);
+ r.moveTo(kHUDTargetGridLeft + kHUDTargetGridWidth - 23, y * 6 + kHUDTargetGridTop);
+ screen->fillRect(r, _gridDarkGreen);
+ } else {
+ r = Common::Rect(0, 0, 4, 2);
+ r.moveTo(kHUDTargetGridLeft + 2, y * 6 + kHUDTargetGridTop);
+ screen->fillRect(r, _gridDarkGreen);
+ r.moveTo(kHUDTargetGridLeft + kHUDTargetGridWidth - 6, y * 6 + kHUDTargetGridTop);
+ screen->fillRect(r, _gridDarkGreen);
+
+ r = Common::Rect(0, 0, 10, 2);
+ r.moveTo(kHUDTargetGridLeft + 8, y * 6 + kHUDTargetGridTop);
+ screen->fillRect(r, _gridDarkGreen);
+ r.moveTo(kHUDTargetGridLeft + kHUDTargetGridWidth - 18, y * 6 + kHUDTargetGridTop);
+ screen->fillRect(r, _gridDarkGreen);
+ }
+ } else {
+ r = Common::Rect(0, 0, 2, 2);
+ r.moveTo(kHUDTargetGridLeft, y * 6 + kHUDTargetGridTop);
+ screen->fillRect(r, _gridDarkGreen);
+ r.moveTo(kHUDTargetGridLeft + kHUDTargetGridWidth - 2, y * 6 + kHUDTargetGridTop);
+ screen->fillRect(r, _gridDarkGreen);
+
+ r = Common::Rect(0, 0, 4, 2);
+ r.moveTo(kHUDTargetGridLeft + 8, y * 6 + kHUDTargetGridTop);
+ screen->fillRect(r, _gridDarkGreen);
+ r.moveTo(kHUDTargetGridLeft + kHUDTargetGridWidth - 12, y * 6 + kHUDTargetGridTop);
+ screen->fillRect(r, _gridDarkGreen);
+ }
+ }
+
+ drawOneBitImageOr(screen, s_RS232Data, 2, Common::Rect(kHUDRS232Left, kHUDRS232Top,
+ kHUDRS232Left + 29, kHUDRS232Top + 8), _gridDarkGreen);
+
+ if (_targetLocked) {
+ drawHUDLockArrows(0, _lockDarkGreen2);
+ drawHUDLockArrows(12, _lockDarkGreen1);
+ drawHUDLockArrows(24, _lightGreen);
+ drawOneBitImageOr(screen, s_lockData, 4, Common::Rect(kHUDLockLeft, kHUDLockTop + 115,
+ kHUDLockLeft + 52, kHUDLockTop + 115 + 9), _lightGreen);
+ }
+}
+
+void ShuttleHUD::drawOneBitImageOr(Graphics::Surface *screen, const uint16 *data, int pitch, const Common::Rect &bounds, uint32 color) {
+ for (int y = 0; y < bounds.height(); y++) {
+ for (int x = 0; x < bounds.width(); x++) {
+ if ((data[y * pitch + x / 16] & (1 << (15 - (x % 16)))) != 0) {
+ if (screen->format.bytesPerPixel == 2)
+ WRITE_UINT16((byte *)screen->getBasePtr(x + bounds.left, y + bounds.top), color);
+ else
+ WRITE_UINT32((byte *)screen->getBasePtr(x + bounds.left, y + bounds.top), color);
+ }
+ }
+ }
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/mars/shuttlehud.h b/engines/pegasus/neighborhood/mars/shuttlehud.h
new file mode 100644
index 0000000000..f7dbbaeae8
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/shuttlehud.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.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_MARS_SHUTTLEHUD_H
+#define PEGASUS_NEIGHBORHOOD_MARS_SHUTTLEHUD_H
+
+#include "pegasus/elements.h"
+#include "pegasus/timers.h"
+
+namespace Pegasus {
+
+class ShuttleHUD : public DisplayElement, public Idler {
+public:
+ ShuttleHUD();
+
+ void showTargetGrid();
+ void hideTargetGrid();
+
+ void initShuttleHUD();
+ void cleanUpShuttleHUD();
+
+ bool isTargetLocked() { return _targetLocked; }
+
+ void draw(const Common::Rect &);
+
+protected:
+ void useIdleTime();
+ void lockOnTarget();
+ void unlockOnTarget();
+ void drawOneBitImageOr(Graphics::Surface *, const uint16 *, int, const Common::Rect &, uint32);
+
+ bool _targetLocked;
+ uint32 _lightGreen, _gridDarkGreen, _lockDarkGreen1, _lockDarkGreen2;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/mars/shuttleweapon.cpp b/engines/pegasus/neighborhood/mars/shuttleweapon.cpp
new file mode 100644
index 0000000000..b4c360b280
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/shuttleweapon.cpp
@@ -0,0 +1,129 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/neighborhood/mars/constants.h"
+#include "pegasus/neighborhood/mars/robotship.h"
+#include "pegasus/neighborhood/mars/shuttleweapon.h"
+#include "pegasus/neighborhood/mars/spacejunk.h"
+
+namespace Pegasus {
+
+ShuttleWeapon::ShuttleWeapon() : IdlerAnimation(kNoDisplayElement) {
+ setScale(kShuttleWeaponScale);
+ _weaponDuration = kShuttleWeaponScale * 2;
+ setSegment(0, _weaponDuration);
+ setBounds(kShuttleWindowLeft, kShuttleWindowTop, kShuttleWindowLeft + kShuttleWindowWidth,
+ kShuttleWindowTop + kShuttleWindowHeight);
+ setDisplayOrder(kShuttleWeaponFrontOrder);
+}
+
+void ShuttleWeapon::initShuttleWeapon() {
+ startDisplaying();
+}
+
+void ShuttleWeapon::cleanUpShuttleWeapon() {
+ stop();
+ hide();
+ stopDisplaying();
+}
+
+bool ShuttleWeapon::canFireWeapon() {
+ return !isRunning();
+}
+
+void ShuttleWeapon::fireWeapon(const CoordType hStop, const CoordType vStop) {
+ if (!isRunning()) {
+ stop();
+ setTime(0);
+ show();
+
+ Common::Point pt2D(hStop, vStop);
+ project2DTo3D(pt2D, kShuttleDistance, _weaponTarget);
+ _weaponTime = 0;
+ setDisplayOrder(kShuttleWeaponFrontOrder);
+ start();
+ }
+}
+
+void ShuttleWeapon::updateWeaponPosition() {
+ _weaponTime = (float)_lastTime / _weaponDuration;
+ linearInterp(_weaponOrigin, _weaponTarget, _weaponTime, _weaponLocation);
+
+ if (_weaponTime == 1.0) {
+ stop();
+ hide();
+ } else {
+ triggerRedraw();
+ }
+}
+
+void ShuttleWeapon::timeChanged(const TimeValue) {
+ updateWeaponPosition();
+
+ bool hit = false;
+ Common::Point impactPoint;
+
+ if (g_spaceJunk->isJunkFlying()) {
+ hit = collisionWithJunk(impactPoint);
+ if (hit) {
+ stop();
+ hide();
+ hitJunk(impactPoint);
+ }
+ }
+
+ if (!hit && _weaponTime == 1.0 && collisionWithShuttle(impactPoint))
+ hitShuttle(impactPoint);
+}
+
+bool ShuttleWeapon::collisionWithJunk(Common::Point &impactPoint) {
+ if (getDisplayOrder() == kShuttleWeaponFrontOrder) {
+ Point3D junkPosition;
+ g_spaceJunk->getJunkPosition(junkPosition);
+
+ if (junkPosition.z < _weaponLocation.z) {
+ setDisplayOrder(kShuttleWeaponBackOrder);
+ project3DTo2D(_weaponLocation, impactPoint);
+ return g_spaceJunk->pointInJunk(impactPoint);
+ }
+ }
+
+ return false;
+}
+
+bool ShuttleWeapon::collisionWithShuttle(Common::Point &impactPoint) {
+ project3DTo2D(_weaponLocation, impactPoint);
+ return g_robotShip->pointInShuttle(impactPoint);
+}
+
+void ShuttleWeapon::hitJunk(Common::Point impactPoint) {
+ g_spaceJunk->hitByEnergyBeam(impactPoint);
+}
+
+void ShuttleWeapon::hitShuttle(Common::Point impactPoint) {
+ g_robotShip->hitByEnergyBeam(impactPoint);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/mars/shuttleweapon.h b/engines/pegasus/neighborhood/mars/shuttleweapon.h
new file mode 100644
index 0000000000..38529c8919
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/shuttleweapon.h
@@ -0,0 +1,68 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_MARS_SHUTTLEWEAPON_H
+#define PEGASUS_NEIGHBORHOOD_MARS_SHUTTLEWEAPON_H
+
+#include "pegasus/elements.h"
+#include "pegasus/neighborhood/mars/spacechase3d.h"
+
+namespace Pegasus {
+
+// Can fire multiple times?
+// For now, no...
+// clone2727 adds: And now forever
+
+static const TimeScale kShuttleWeaponScale = kFifteenTicksPerSecond;
+
+class ShuttleWeapon : public IdlerAnimation {
+public:
+ ShuttleWeapon();
+ virtual ~ShuttleWeapon() {}
+
+ virtual void initShuttleWeapon();
+ virtual void cleanUpShuttleWeapon();
+
+ virtual void fireWeapon(const CoordType, const CoordType);
+
+ bool canFireWeapon();
+
+protected:
+ void timeChanged(const TimeValue);
+ virtual void updateWeaponPosition();
+ virtual bool collisionWithJunk(Common::Point &impactPoint);
+ bool collisionWithShuttle(Common::Point &impactPoint);
+ virtual void hitJunk(Common::Point impactPoint);
+ virtual void hitShuttle(Common::Point impactPoint);
+
+ Point3D _weaponOrigin, _weaponTarget;
+ Point3D _weaponLocation;
+ float _weaponTime;
+ TimeValue _weaponDuration;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/mars/spacechase3d.cpp b/engines/pegasus/neighborhood/mars/spacechase3d.cpp
new file mode 100644
index 0000000000..05f8233763
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/spacechase3d.cpp
@@ -0,0 +1,106 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/neighborhood/mars/spacechase3d.h"
+
+namespace Pegasus {
+
+void project3DTo2D(const Point3D &pt3D, Common::Point &pt2D) {
+ pt2D.x = (int)convertSpaceXToScreenH(pt3D.x, pt3D.z);
+ pt2D.y = (int)convertSpaceYToScreenV(pt3D.y, pt3D.z);
+}
+
+void project2DTo3D(const Common::Point &pt2D, const float screenDistance, Point3D &pt3D) {
+ pt3D.x = convertScreenHToSpaceX(pt2D.x, screenDistance);
+ pt3D.y = convertScreenVToSpaceY(pt2D.y, screenDistance);
+ pt3D.z = screenDistance;
+}
+
+void linearInterp(const Point3D &pt1, const Point3D &pt2, const float t, Point3D &pt3) {
+ pt3.x = pt1.x + (pt2.x - pt1.x) * t;
+ pt3.y = pt1.y + (pt2.y - pt1.y) * t;
+ pt3.z = pt1.z + (pt2.z - pt1.z) * t;
+}
+
+void linearInterp(const Point3D &pt1, const float x2, const float y2, const float z2, const float t, Point3D &pt3) {
+ pt3.x = pt1.x + (x2 - pt1.x) * t;
+ pt3.y = pt1.y + (y2 - pt1.y) * t;
+ pt3.z = pt1.z + (z2 - pt1.z) * t;
+}
+
+void linearInterp(const float x1, const float y1, const float z1, const Point3D &pt2, const float t, Point3D &pt3) {
+ pt3.x = x1 + (pt2.x - x1) * t;
+ pt3.y = y1 + (pt2.y - y1) * t;
+ pt3.z = z1 + (pt2.z - z1) * t;
+}
+
+void linearInterp(const float x1, const float y1, const float z1, const float x2, const float y2, const float z2,
+ const float t, Point3D &pt3) {
+ pt3.x = x1 + (x2 - x1) * t;
+ pt3.y = y1 + (y2 - y1) * t;
+ pt3.z = z1 + (z2 - z1) * t;
+}
+
+void linearInterp(const Common::Point &pt1, const Common::Point &pt2, const float t, Common::Point &pt3) {
+ pt3.x = (int)(pt1.x + (pt2.x - pt1.x) * t);
+ pt3.y = (int)(pt1.y + (pt2.y - pt1.y) * t);
+}
+
+void linearInterp(const Common::Point &pt1, const float h2, const float v2, const float t, Common::Point &pt3) {
+ pt3.x = (int)(pt1.x + (h2 - pt1.x) * t);
+ pt3.y = (int)(pt1.y + (v2 - pt1.y) * t);
+}
+
+void linearInterp(const float h1, const float v1, const Common::Point &pt2, const float t, Common::Point &pt3) {
+ pt3.x = (int)(h1 + (pt2.x - h1) * t);
+ pt3.y = (int)(v1 + (pt2.y - v1) * t);
+}
+
+void linearInterp(const float h1, const float v1, const float h2, const float v2, const float t, Common::Point &pt3) {
+ pt3.x = (int)(h1 + (h2 - h1) * t);
+ pt3.y = (int)(v1 + (v2 - v1) * t);
+}
+
+float linearInterp(const float arg1, const float arg2, const float t) {
+ return arg1 + (arg2 - arg1) * t;
+}
+
+bool isNegative(int a) {
+ return a < 0;
+}
+
+bool isPositive(int a) {
+ return a > 0;
+}
+
+int sign(int a) {
+ return isNegative(a) ? -1 : isPositive(a) ? 1 : 0;
+}
+
+bool sameSign(int a, int b) {
+ return sign(a) == sign(b);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/mars/spacechase3d.h b/engines/pegasus/neighborhood/mars/spacechase3d.h
new file mode 100644
index 0000000000..f6815e69bd
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/spacechase3d.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.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_MARS_SPACECHASE3D_H
+#define PEGASUS_NEIGHBORHOOD_MARS_SPACECHASE3D_H
+
+#include "pegasus/neighborhood/mars/constants.h"
+
+namespace Pegasus {
+
+// This is approximately right for a field of view of 72 degrees
+// (Should be set to the tangent of FOV).
+//static const float kTangentFOV = 0.76254;
+static const float kTangentFOV = 1.0;
+
+// Define these as macros and they can be used to define constants...
+#define convertSpaceXToScreenH(x, z) \
+ ((x) / (z) * (kScreenWidth / (2 * kTangentFOV)) + kShuttleWindowMidH)
+
+#define convertSpaceYToScreenV(y, z) \
+ (kShuttleWindowMidV - (y) / (z) * (kScreenWidth / (2 * kTangentFOV)))
+
+#define convertScreenHToSpaceX(x, d) \
+ (((2.0 * kTangentFOV) / kScreenWidth) * ((float)(x) - kShuttleWindowMidH) * (d))
+
+#define convertScreenVToSpaceY(y, d) \
+ (((2.0 * kTangentFOV) / kScreenWidth) * ((float)kShuttleWindowMidV - (y)) * (d))
+
+struct Point3D {
+ float x, y, z;
+
+ Point3D() : x(0), y(0), z(0) {}
+ Point3D(float x1, float y1, float z1) : x(x1), y(y1), z(z1) {}
+ bool operator==(const Point3D &p) const { return x == p.x && y == p.y && z == p.z; }
+ bool operator!=(const Point3D &p) const { return x != p.x || y != p.y || z != p.z; }
+
+ void translate(float dx, float dy, float dz) {
+ x += dx;
+ y += dy;
+ z += dz;
+ }
+};
+
+static const int kScreenWidth = kShuttleWindowWidth;
+
+bool isNegative(int a);
+bool isPositive(int a);
+int sign(int a);
+bool sameSign(int a, int b);
+
+void project3DTo2D(const Point3D &pt3D, Common::Point &pt2D);
+void project2DTo3D(const Common::Point &pt2D, const float screenDistance, Point3D &pt3D);
+
+void linearInterp(const Point3D &pt1, const Point3D &pt2, const float t, Point3D &pt3);
+void linearInterp(const Point3D &pt1, const float x2, const float y2, const float z2, const float t, Point3D &pt3);
+void linearInterp(const float x1, const float y1, const float z1, const Point3D &pt2, const float t, Point3D &pt3);
+void linearInterp(const float x1, const float y1, const float z1, const float x2,
+ const float y2, const float z2, const float t, Point3D &pt3);
+
+void linearInterp(const Common::Point &pt1, const Common::Point &pt2, const float t, Common::Point &pt3);
+void linearInterp(const Common::Point &pt1, const float h2, const float v2, const float t, Common::Point &pt3);
+void linearInterp(const float h1, const float v1, const Common::Point &pt2, const float t, Common::Point &pt3);
+void linearInterp(const float h1, const float v1, const float h2, const float v2, const float t, Common::Point &pt3);
+
+float linearInterp(const float arg1, const float arg2, const float t);
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/mars/spacejunk.cpp b/engines/pegasus/neighborhood/mars/spacejunk.cpp
new file mode 100644
index 0000000000..3912e659c2
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/spacejunk.cpp
@@ -0,0 +1,212 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/pegasus.h"
+#include "pegasus/neighborhood/mars/mars.h"
+#include "pegasus/neighborhood/mars/spacejunk.h"
+
+namespace Pegasus {
+
+static const CoordType kMaxBounceSize = 90;
+static const CoordType kBounceTargetHRange = 640 - kMaxBounceSize - 2;
+static const CoordType kBounceTargetVRange = 480 - kMaxBounceSize - 2;
+
+static const float kJunkXTarget = 0;
+static const float kJunkYTarget = 0;
+static const float kJunkZTarget = kJunkMinDistance;
+
+SpaceJunk *g_spaceJunk = 0;
+
+SpaceJunk::SpaceJunk(const DisplayElementID id) : ScalingMovie(id) {
+ _timer.setScale(kJunkTimeScale);
+ _bouncing = false;
+ g_spaceJunk = this;
+}
+
+SpaceJunk::~SpaceJunk() {
+ g_spaceJunk = 0;
+}
+
+void SpaceJunk::launchJunk(int16 whichJunk, CoordType xOrigin, CoordType yOrigin) {
+ _bouncing = false;
+ TimeValue startTime = whichJunk * 16 * 40;
+ TimeValue stopTime = startTime + 16 * 40;
+
+ _launchPoint = Point3D(convertScreenHToSpaceX(xOrigin, kJunkMaxDistance),
+ convertScreenVToSpaceY(yOrigin, kJunkMaxDistance), kJunkMaxDistance);
+ startIdling();
+ stop();
+ setFlags(0);
+ setSegment(startTime, stopTime);
+ setFlags(kLoopTimeBase);
+ setTime(startTime);
+ start();
+ show();
+ _timer.stop();
+ _timer.setSegment(0, kJunkTravelTime);
+ _timer.setTime(0);
+
+ // Force it to set up correctly from the get-go
+ useIdleTime();
+
+ _timer.start();
+}
+
+void SpaceJunk::setCenter(const CoordType centerX, const CoordType centerY) {
+ _center.x = centerX;
+ _center.y = centerY;
+
+ Common::Rect r;
+ getBounds(r);
+ r.moveTo(CLIP<int>(centerX - (r.width() >> 1), 0, 640 - r.width()), CLIP<int>(centerY - (r.height() >> 1), 0, 480 - r.height()));
+ setBounds(r);
+}
+
+void SpaceJunk::setScaleSize(const CoordType size) {
+ Common::Rect r;
+ r.left = _center.x - (size >> 1);
+ r.top = _center.y - (size >> 1);
+ r.right = r.left + size;
+ r.bottom = r.top + size;
+ setBounds(r);
+}
+
+void SpaceJunk::useIdleTime() {
+ if (_bouncing) {
+ TimeValue time = _timer.getTime();
+ Common::Point pt;
+ pt.x = linearInterp(0, _bounceTime, time, _bounceStart.x, _bounceStop.x);
+ pt.y = linearInterp(0, _bounceTime, time, _bounceStart.y, _bounceStop.y);
+ CoordType size = linearInterp(0, _bounceTime, time, _bounceSizeStart, _bounceSizeStop);
+ setCenter(pt.x, pt.y);
+ setScaleSize(size);
+
+ if (time == _bounceTime) {
+ stop();
+ stopIdling();
+ hide();
+ ((Mars *)g_neighborhood)->setUpNextDropTime();
+ }
+ } else {
+ float t = (float)_timer.getTime() / kJunkTravelTime;
+ linearInterp(_launchPoint, kJunkXTarget, kJunkYTarget, kJunkZTarget, t, _junkPosition);
+
+ Common::Point pt2D;
+ project3DTo2D(_junkPosition, pt2D);
+ setCenter(pt2D.x, pt2D.y);
+ setScaleSize((int)(convertSpaceYToScreenV(_junkPosition.y - kJunkSize / 2, _junkPosition.z) -
+ convertSpaceYToScreenV(_junkPosition.y + kJunkSize / 2, _junkPosition.z)));
+
+ if (t == 1.0) {
+ rebound(kCollisionReboundTime);
+ ((Mars *)g_neighborhood)->hitByJunk();
+ }
+ }
+}
+
+bool SpaceJunk::pointInJunk(const Common::Point &pt) {
+ Common::Rect r;
+ getBounds(r);
+
+ int dx = r.width() / 4;
+ int dy = r.height() / 4;
+
+ r.left += dx;
+ r.right -= dx;
+ r.top += dy;
+ r.top -= dy;
+
+ return r.contains(pt);
+}
+
+void SpaceJunk::rebound(const TimeValue reboundTime) {
+ Common::Rect bounds;
+ getBounds(bounds);
+
+ _bounceStart.x = (bounds.left + bounds.right) >> 1;
+ _bounceStart.y = (bounds.top + bounds.bottom) >> 1;
+
+ PegasusEngine *vm = (PegasusEngine *)g_engine;
+
+ switch (vm->getRandomNumber(3)) {
+ case 0:
+ _bounceStop.x = kMaxBounceSize / 2 + 1 + vm->getRandomNumber(kBounceTargetHRange - 1);
+ _bounceStop.y = kMaxBounceSize / 2 + 1;
+ break;
+ case 1:
+ _bounceStop.x = kMaxBounceSize / 2 + 1 + vm->getRandomNumber(kBounceTargetHRange - 1);
+ _bounceStop.y = 480 - kMaxBounceSize / 2 + 1;
+ break;
+ case 2:
+ _bounceStop.x = kMaxBounceSize / 2 + 1;
+ _bounceStop.y = kMaxBounceSize / 2 + 1 + vm->getRandomNumber(kBounceTargetVRange - 1);
+ break;
+ case 3:
+ _bounceStop.x = 640 - kMaxBounceSize / 2 + 1;
+ _bounceStop.y = kMaxBounceSize / 2 + 1 + vm->getRandomNumber(kBounceTargetVRange - 1);
+ break;
+ }
+
+ _bounceSizeStart = bounds.width();
+ _bounceSizeStop = MIN(_bounceSizeStart, kMaxBounceSize);
+
+ _timer.stop();
+ _timer.setSegment(0, reboundTime);
+ _bounceTime = reboundTime;
+ _timer.setTime(0);
+ _timer.start();
+
+ _bouncing = true;
+}
+
+void SpaceJunk::hitByEnergyBeam(Common::Point) {
+ rebound(kWeaponReboundTime);
+ setGlowing(true);
+ ((PegasusEngine *)g_engine)->delayShell(1, 3);
+ setGlowing(false);
+}
+
+void SpaceJunk::hitByGravitonCannon(Common::Point impactPoint) {
+ stop();
+ stopIdling();
+ hide();
+
+ Common::Rect r;
+ getBounds(r);
+ r = Common::Rect::center(impactPoint.x, impactPoint.y, r.width(), r.height());
+
+ ((Mars *)g_neighborhood)->showBigExplosion(r, kShuttleJunkOrder);
+ ((Mars *)g_neighborhood)->setUpNextDropTime();
+}
+
+void SpaceJunk::getJunkPosition(Point3D &position) {
+ position = _junkPosition;
+}
+
+bool SpaceJunk::isJunkFlying() {
+ return isIdling();
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/mars/spacejunk.h b/engines/pegasus/neighborhood/mars/spacejunk.h
new file mode 100644
index 0000000000..2ec9192513
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/spacejunk.h
@@ -0,0 +1,78 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_MARS_SPACEJUNK_H
+#define PEGASUS_NEIGHBORHOOD_MARS_SPACEJUNK_H
+
+#include "pegasus/movie.h"
+#include "pegasus/neighborhood/mars/constants.h"
+#include "pegasus/neighborhood/mars/spacechase3d.h"
+
+namespace Pegasus {
+
+static const CoordType kJunkMaxScreenSize = 250;
+
+static const float kJunkSize = convertScreenVToSpaceY(kShuttleWindowMidV - kJunkMaxScreenSize / 2, kJunkMinDistance) -
+ convertScreenVToSpaceY(kShuttleWindowMidV + kJunkMaxScreenSize / 2, kJunkMinDistance);
+
+class SpaceJunk : public ScalingMovie, public Idler {
+public:
+ SpaceJunk(const DisplayElementID);
+ virtual ~SpaceJunk();
+
+ void setCenter(const CoordType, const CoordType);
+ void setScaleSize(const CoordType);
+
+ void useIdleTime();
+
+ void launchJunk(int16, CoordType, CoordType);
+
+ void getJunkPosition(Point3D &);
+ bool isJunkFlying();
+
+ bool pointInJunk(const Common::Point &);
+
+ void hitByEnergyBeam(Common::Point impactPoint);
+ void hitByGravitonCannon(Common::Point impactPoint);
+
+ bool junkFlying() { return _timer.isRunning(); }
+
+protected:
+ void rebound(const TimeValue);
+
+ TimeBase _timer;
+ Point3D _launchPoint, _junkPosition;
+ Common::Point _center;
+ bool _bouncing;
+ Common::Point _bounceStart, _bounceStop;
+ CoordType _bounceSizeStart, _bounceSizeStop;
+ TimeValue _bounceTime;
+};
+
+extern SpaceJunk *g_spaceJunk;
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/mars/tractorbeam.cpp b/engines/pegasus/neighborhood/mars/tractorbeam.cpp
new file mode 100644
index 0000000000..d3f9c94328
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/tractorbeam.cpp
@@ -0,0 +1,139 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/pegasus.h"
+#include "pegasus/neighborhood/mars/constants.h"
+#include "pegasus/neighborhood/mars/tractorbeam.h"
+
+namespace Pegasus {
+
+TractorBeam::TractorBeam() : DisplayElement(kNoDisplayElement) {
+ setBounds(kShuttleTractorLeft, kShuttleTractorTop, kShuttleTractorLeft + kShuttleTractorWidth,
+ kShuttleTractorTop + kShuttleTractorHeight);
+ setDisplayOrder(kShuttleTractorBeamOrder);
+
+}
+
+static const int kHalfWidth = kShuttleTractorWidth >> 1;
+static const int kHalfHeight = kShuttleTractorHeight >> 1;
+
+static const int kW3Vert = kHalfHeight * kHalfHeight * kHalfHeight;
+static const int kW3Div2Vert = kW3Vert >> 1;
+
+static const int kW3Horiz = kHalfWidth * kHalfWidth * kHalfWidth;
+static const int kW3Div2Horiz = kW3Horiz >> 1;
+
+static const int kMaxLevel = 50;
+
+static const int kAVert = -2 * kMaxLevel;
+static const int kBVert = 3 * kMaxLevel * kHalfHeight;
+
+#define READ_PIXEL(ptr) \
+ if (screen->format.bytesPerPixel == 2) \
+ color = READ_UINT16(ptr); \
+ else \
+ color = READ_UINT32(ptr); \
+ screen->format.colorToRGB(color, r, g, b)
+
+#define WRITE_PIXEL(ptr) \
+ color = screen->format.RGBToColor(r, g, b); \
+ if (screen->format.bytesPerPixel == 2) \
+ WRITE_UINT16(ptr, color); \
+ else \
+ WRITE_UINT32(ptr, color)
+
+#define DO_BLEND(ptr) \
+ READ_PIXEL(ptr); \
+ g += (((0xff - g) * blendHoriz) >> 8); \
+ b += (((0xff - b) * blendHoriz) >> 8); \
+ WRITE_PIXEL(ptr)
+
+void TractorBeam::draw(const Common::Rect &) {
+ Graphics::Surface *screen = ((PegasusEngine *)g_engine)->_gfx->getWorkArea();
+
+ // Set up vertical DDA.
+ int blendVert = 0;
+ int dVert = 0;
+ int d1Vert = kAVert + kBVert;
+ int d2Vert = 6 * kAVert + 2 * kBVert;
+ int d3Vert = 6 * kAVert;
+
+ byte *rowPtrTop = (byte *)screen->getBasePtr(_bounds.left, _bounds.top);
+ byte *rowPtrBottom = (byte *)screen->getBasePtr(_bounds.left, _bounds.top + ((kHalfHeight << 1) - 1));
+
+ for (int y = kHalfHeight; y > 0; y--) {
+ // Set up horizontal DDA
+ int A = -2 * blendVert;
+ int B = 3 * blendVert * kHalfWidth;
+ int blendHoriz = 0;
+ int dHoriz = 0;
+ int d1Horiz = A + B;
+ int d2Horiz = 6 * A + 2 * B;
+ int d3Horiz = 6 * A;
+
+ byte *pTopLeft = rowPtrTop;
+ byte *pTopRight = rowPtrTop + (kHalfWidth * 2 - 1) * screen->format.bytesPerPixel;
+ byte *pBottomLeft = rowPtrBottom;
+ byte *pBottomRight = rowPtrBottom + (kHalfWidth * 2 - 1) * screen->format.bytesPerPixel;
+
+ for (int x = kHalfWidth; x > 0; x--) {
+ byte r, g, b;
+ uint32 color;
+
+ DO_BLEND(pTopLeft);
+ DO_BLEND(pTopRight);
+ DO_BLEND(pBottomLeft);
+ DO_BLEND(pBottomRight);
+
+ pTopLeft += screen->format.bytesPerPixel;
+ pBottomLeft += screen->format.bytesPerPixel;
+ pTopRight -= screen->format.bytesPerPixel;
+ pBottomRight -= screen->format.bytesPerPixel;
+
+ while (dHoriz > kW3Div2Horiz) {
+ blendHoriz++;
+ dHoriz -= kW3Horiz;
+ }
+
+ dHoriz += d1Horiz;
+ d1Horiz += d2Horiz;
+ d2Horiz += d3Horiz;
+ }
+
+ rowPtrTop += screen->pitch;
+ rowPtrBottom -= screen->pitch;
+
+ while (dVert > kW3Div2Vert) {
+ blendVert++;
+ dVert -= kW3Vert;
+ }
+
+ dVert += d1Vert;
+ d1Vert += d2Vert;
+ d2Vert += d3Vert;
+ }
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/mars/tractorbeam.h b/engines/pegasus/neighborhood/mars/tractorbeam.h
new file mode 100644
index 0000000000..cd87992d11
--- /dev/null
+++ b/engines/pegasus/neighborhood/mars/tractorbeam.h
@@ -0,0 +1,43 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_MARS_TRACTORBEAM_H
+#define PEGASUS_NEIGHBORHOOD_MARS_TRACTORBEAM_H
+
+#include "pegasus/elements.h"
+
+namespace Pegasus {
+
+class TractorBeam : public DisplayElement {
+public:
+ TractorBeam();
+ virtual ~TractorBeam() {}
+
+ void draw(const Common::Rect &);
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/neighborhood.cpp b/engines/pegasus/neighborhood/neighborhood.cpp
new file mode 100644
index 0000000000..07be62c957
--- /dev/null
+++ b/engines/pegasus/neighborhood/neighborhood.cpp
@@ -0,0 +1,1774 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/debug.h"
+#include "common/stream.h"
+
+#include "pegasus/compass.h"
+#include "pegasus/cursor.h"
+#include "pegasus/energymonitor.h"
+#include "pegasus/gamestate.h"
+#include "pegasus/graphics.h"
+#include "pegasus/input.h"
+#include "pegasus/interaction.h"
+#include "pegasus/interface.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/biochips/mapchip.h"
+#include "pegasus/neighborhood/neighborhood.h"
+#include "pegasus/neighborhood/tsa/fulltsa.h"
+#include "pegasus/neighborhood/tsa/tinytsa.h"
+
+namespace Pegasus {
+
+StriderCallBack::StriderCallBack(Neighborhood *neighborhood) {
+ _neighborhood = neighborhood;
+}
+
+void StriderCallBack::callBack() {
+ _neighborhood->checkStriding();
+}
+
+static const TimeValue kStridingSlop = 39;
+
+Neighborhood *g_neighborhood = 0;
+
+Neighborhood::Neighborhood(InputHandler *nextHandler, PegasusEngine *vm, const Common::String &resName, NeighborhoodID id)
+ : InputHandler(nextHandler), IDObject(id), _vm(vm), _resName(resName), _navMovie(kNavMovieID), _stridingCallBack(this),
+ _neighborhoodNotification(kNeighborhoodNotificationID, (NotificationManager *)vm), _pushIn(kNoDisplayElement),
+ _turnPush(kTurnPushID), _croppedMovie(kCroppedMovieID) {
+ GameState.setOpenDoorLocation(kNoRoomID, kNoDirection);
+ _currentAlternate = 0;
+ _currentActivation = kActivateHotSpotAlways;
+ _interruptionFilter = kFilterAllInput;
+ allowInput(true);
+ resetLastExtra();
+ g_neighborhood = this;
+ _currentInteraction = 0;
+ _doneWithInteraction = false;
+ _croppedMovie.setDisplayOrder(kCroppedMovieLayer);
+}
+
+Neighborhood::~Neighborhood() {
+ for (HotspotIterator it = _neighborhoodHotspots.begin(); it != _neighborhoodHotspots.end(); it++)
+ _vm->getAllHotspots().remove(*it);
+
+ _neighborhoodHotspots.deleteHotspots();
+ g_neighborhood = 0;
+
+ loadLoopSound1("");
+ loadLoopSound2("");
+ newInteraction(kNoInteractionID);
+
+ if (g_AIArea)
+ g_AIArea->removeAllRules();
+}
+
+void Neighborhood::init() {
+ _neighborhoodNotification.notifyMe(this, kNeighborhoodFlags, kNeighborhoodFlags);
+ _navMovieCallBack.setNotification(&_neighborhoodNotification);
+ _turnPushCallBack.setNotification(&_neighborhoodNotification);
+ _delayCallBack.setNotification(&_neighborhoodNotification);
+ _spotSoundCallBack.setNotification(&_neighborhoodNotification);
+
+ debug(0, "Loading '%s' neighborhood resources", _resName.c_str());
+
+ Common::SeekableReadStream *stream = _vm->_resFork->getResource(_doorTable.getResTag(), _resName);
+ if (!stream)
+ error("Failed to load doors");
+ _doorTable.loadFromStream(stream);
+ delete stream;
+
+ stream = _vm->_resFork->getResource(_exitTable.getResTag(), _resName);
+ if (!stream)
+ error("Failed to load exits");
+ _exitTable.loadFromStream(stream);
+ delete stream;
+
+ stream = _vm->_resFork->getResource(_extraTable.getResTag(), _resName);
+ if (!stream)
+ error("Failed to load extras");
+ _extraTable.loadFromStream(stream);
+ delete stream;
+
+ stream = _vm->_resFork->getResource(_hotspotInfoTable.getResTag(), _resName);
+ if (!stream)
+ error("Failed to load hotspot info");
+ _hotspotInfoTable.loadFromStream(stream);
+ delete stream;
+
+ stream = _vm->_resFork->getResource(_spotTable.getResTag(), _resName);
+ if (!stream)
+ error("Failed to load spots");
+ _spotTable.loadFromStream(stream);
+ delete stream;
+
+ stream = _vm->_resFork->getResource(_turnTable.getResTag(), _resName);
+ if (!stream)
+ error("Failed to load turns");
+ _turnTable.loadFromStream(stream);
+ delete stream;
+
+ stream = _vm->_resFork->getResource(_viewTable.getResTag(), _resName);
+ if (!stream)
+ error("Failed to load views");
+ _viewTable.loadFromStream(stream);
+ delete stream;
+
+ stream = _vm->_resFork->getResource(_zoomTable.getResTag(), _resName);
+ if (!stream)
+ error("Failed to load zooms");
+ _zoomTable.loadFromStream(stream);
+ delete stream;
+
+ createNeighborhoodSpots();
+
+ _navMovie.initFromMovieFile(getNavMovieName());
+ _navMovie.setVolume(_vm->getSoundFXLevel());
+
+ Common::String soundSpotsName = getSoundSpotsName();
+ if (soundSpotsName.empty()) {
+ _spotSounds.disposeSound();
+ } else {
+ _spotSounds.initFromQuickTime(getSoundSpotsName());
+ _spotSounds.setVolume(_vm->getSoundFXLevel());
+ }
+
+ _navMovie.setDisplayOrder(kNavMovieOrder);
+ _navMovie.startDisplaying();
+
+ Common::Rect bounds;
+ _navMovie.getBounds(bounds);
+ _pushIn.allocateSurface(bounds);
+
+ _turnPush.setInAndOutElements(&_pushIn, &_navMovie);
+ _turnPush.setDisplayOrder(kTurnPushOrder);
+ _turnPush.startDisplaying();
+ _navMovieCallBack.initCallBack(&_navMovie, kCallBackAtExtremes);
+ _stridingCallBack.initCallBack(&_navMovie, kCallBackAtTime);
+ _turnPushCallBack.initCallBack(&_turnPush, kCallBackAtExtremes);
+ _delayCallBack.initCallBack(&_delayTimer, kCallBackAtExtremes);
+ _spotSoundCallBack.initCallBack(&_spotSounds, kCallBackAtExtremes);
+
+ setUpAIRules();
+
+ if (g_compass)
+ g_compass->setFaderValue(getStaticCompassAngle(GameState.getCurrentRoom(), GameState.getCurrentDirection()));
+
+ _soundLoop1.attachFader(&_loop1Fader);
+ _soundLoop2.attachFader(&_loop2Fader);
+ startIdling();
+}
+
+void Neighborhood::start() {
+ GameState.setCurrentRoom(GameState.getLastRoom());
+ GameState.setCurrentDirection(GameState.getLastDirection());
+ arriveAt(GameState.getNextRoom(), GameState.getNextDirection());
+}
+
+void Neighborhood::receiveNotification(Notification *, const NotificationFlags flags) {
+ if ((flags & (kNeighborhoodMovieCompletedFlag | kTurnCompletedFlag)) != 0 && g_AIArea)
+ g_AIArea->unlockAI();
+ if (flags & kMoveForwardCompletedFlag)
+ arriveAt(GameState.getNextRoom(), GameState.getNextDirection());
+ if (flags & kTurnCompletedFlag)
+ turnTo(GameState.getNextDirection());
+ if (flags & kSpotCompletedFlag)
+ spotCompleted();
+ if (flags & kDoorOpenCompletedFlag)
+ doorOpened();
+ if (flags & kActionRequestCompletedFlag)
+ popActionQueue();
+ if (flags & kDeathExtraCompletedFlag)
+ die(_extraDeathReason);
+}
+
+void Neighborhood::arriveAt(const RoomID room, const DirectionConstant direction) {
+ if (g_map)
+ g_map->moveToMapLocation(GameState.getCurrentNeighborhood(), room, direction);
+
+ GameState.setCurrentNeighborhood(getObjectID());
+
+ _currentActivation = kActivateHotSpotAlways;
+ _interruptionFilter = kFilterAllInput;
+
+ if (room != GameState.getCurrentRoom() || direction != GameState.getCurrentDirection()) {
+ GameState.setCurrentRoom(room);
+ GameState.setCurrentDirection(direction);
+ loadAmbientLoops();
+ activateCurrentView(room, direction, kSpotOnArrivalMask);
+ } else {
+ loadAmbientLoops();
+ showViewFrame(getViewTime(GameState.getCurrentRoom(), GameState.getCurrentDirection()));
+ }
+
+ if (GameState.getOpenDoorRoom() != kNoRoomID) {
+ // Arriving always closes a door.
+ loadAmbientLoops();
+ closeDoorOffScreen(GameState.getOpenDoorRoom(), GameState.getOpenDoorDirection());
+ GameState.setOpenDoorLocation(kNoRoomID, kNoDirection);
+ }
+
+ if (g_compass)
+ g_compass->setFaderValue(getStaticCompassAngle(GameState.getCurrentRoom(), GameState.getCurrentDirection()));
+
+ if (g_AIArea)
+ g_AIArea->checkMiddleArea();
+
+ checkContinuePoint(room, direction);
+}
+
+// These functions can be overridden to tweak the exact frames used.
+
+void Neighborhood::getExitEntry(const RoomID room, const DirectionConstant direction, ExitTable::Entry &entry) {
+ entry = _exitTable.findEntry(room, direction, _currentAlternate);
+
+ if (entry.isEmpty())
+ entry = _exitTable.findEntry(room, direction, kNoAlternateID);
+}
+
+TimeValue Neighborhood::getViewTime(const RoomID room, const DirectionConstant direction) {
+ if (GameState.getOpenDoorRoom() == room && GameState.getOpenDoorDirection() == direction) {
+ // If we get here, the door entry for this location must exist.
+ DoorTable::Entry doorEntry = _doorTable.findEntry(room, direction, _currentAlternate);
+
+ if (doorEntry.isEmpty())
+ doorEntry = _doorTable.findEntry(room, direction, kNoAlternateID);
+
+ return doorEntry.movieEnd - 1;
+ }
+
+ ViewTable::Entry viewEntry = _viewTable.findEntry(room, direction, _currentAlternate);
+
+ if (viewEntry.isEmpty())
+ viewEntry = _viewTable.findEntry(room, direction, kNoAlternateID);
+
+ return viewEntry.time;
+}
+
+void Neighborhood::getDoorEntry(const RoomID room, const DirectionConstant direction, DoorTable::Entry &doorEntry) {
+ doorEntry = _doorTable.findEntry(room, direction, _currentAlternate);
+
+ if (doorEntry.isEmpty())
+ doorEntry = _doorTable.findEntry(room, direction, kNoAlternateID);
+}
+
+DirectionConstant Neighborhood::getTurnEntry(const RoomID room, const DirectionConstant direction, const TurnDirection turnDirection) {
+ TurnTable::Entry turnEntry = _turnTable.findEntry(room, direction, turnDirection, _currentAlternate);
+
+ if (turnEntry.isEmpty())
+ turnEntry = _turnTable.findEntry(room, direction, turnDirection, kNoAlternateID);
+
+ return turnEntry.endDirection;
+}
+
+void Neighborhood::findSpotEntry(const RoomID room, const DirectionConstant direction, SpotFlags flags, SpotTable::Entry &spotEntry) {
+ spotEntry = _spotTable.findEntry(room, direction, flags, _currentAlternate);
+
+ if (spotEntry.isEmpty())
+ spotEntry = _spotTable.findEntry(room, direction, flags, kNoAlternateID);
+}
+
+void Neighborhood::getZoomEntry(const HotSpotID id, ZoomTable::Entry &zoomEntry) {
+ zoomEntry = _zoomTable.findEntry(id);
+}
+
+void Neighborhood::getHotspotEntry(const HotSpotID id, HotspotInfoTable::Entry &hotspotEntry) {
+ hotspotEntry = _hotspotInfoTable.findEntry(id);
+}
+
+void Neighborhood::getExtraEntry(const uint32 id, ExtraTable::Entry &extraEntry) {
+ extraEntry = _extraTable.findEntry(id);
+}
+
+/////////////////////////////////////////////
+//
+// "Can" functions: Called to see whether or not a user is allowed to do something
+
+CanMoveForwardReason Neighborhood::canMoveForward(ExitTable::Entry &entry) {
+ DoorTable::Entry door;
+
+ getExitEntry(GameState.getCurrentRoom(), GameState.getCurrentDirection(), entry);
+ getDoorEntry(GameState.getCurrentRoom(), GameState.getCurrentDirection(), door);
+
+ // Fixed this so that doors that don't lead anywhere can be opened, but not walked
+ // through.
+ if (door.flags & kDoorPresentMask) {
+ if (GameState.isCurrentDoorOpen()) {
+ if (entry.exitRoom == kNoRoomID)
+ return kCantMoveBlocked;
+ else
+ return kCanMoveForward;
+ } else if (door.flags & kDoorLockedMask) {
+ return kCantMoveDoorLocked;
+ } else {
+ return kCantMoveDoorClosed;
+ }
+ } else if (entry.exitRoom == kNoRoomID) {
+ return kCantMoveBlocked;
+ }
+
+ return kCanMoveForward;
+}
+
+CanTurnReason Neighborhood::canTurn(TurnDirection turnDirection, DirectionConstant &nextDir) {
+ nextDir = getTurnEntry(GameState.getCurrentRoom(), GameState.getCurrentDirection(), turnDirection);
+
+ if (nextDir == kNoDirection)
+ return kCantTurnNoTurn;
+
+ return kCanTurn;
+}
+
+CanOpenDoorReason Neighborhood::canOpenDoor(DoorTable::Entry &entry) {
+ getDoorEntry(GameState.getCurrentRoom(), GameState.getCurrentDirection(), entry);
+
+ if (entry.flags & kDoorPresentMask) {
+ if (GameState.isCurrentDoorOpen())
+ return kCantOpenAlreadyOpen;
+
+ if (entry.flags & kDoorLockedMask)
+ return kCantOpenLocked;
+
+ return kCanOpenDoor;
+ }
+
+ return kCantOpenNoDoor;
+}
+
+void Neighborhood::createNeighborhoodSpots() {
+ Common::SeekableReadStream *hotspotList = _vm->_resFork->getResource(MKTAG('H', 'S', 'L', 's'), _resName);
+ if (!hotspotList)
+ error("Could not load neighborhood hotspots");
+
+ uint32 hotspotCount = hotspotList->readUint32BE();
+
+ while (hotspotCount--) {
+ uint16 id = hotspotList->readUint16BE();
+ uint32 flags = hotspotList->readUint32BE();
+ uint32 rgnSize = hotspotList->readUint32BE();
+
+ int32 startPos = hotspotList->pos();
+
+ debug(0, "Hotspot %d:", id);
+ Region region(hotspotList);
+
+ hotspotList->seek(startPos + rgnSize);
+
+ Hotspot *hotspot = new Hotspot(id);
+ hotspot->setHotspotFlags(flags);
+ hotspot->setArea(region);
+
+ _vm->getAllHotspots().push_back(hotspot);
+ _neighborhoodHotspots.push_back(hotspot);
+ }
+
+ delete hotspotList;
+}
+
+void Neighborhood::popActionQueue() {
+ if (!_actionQueue.empty()) {
+ QueueRequest topRequest = _actionQueue.pop();
+
+ switch (topRequest.requestType) {
+ case kNavExtraRequest:
+ _navMovie.stop();
+ break;
+ case kSpotSoundRequest:
+ _spotSounds.stopSound();
+ break;
+ case kDelayRequest:
+ _delayTimer.stop();
+ break;
+ }
+
+ serviceActionQueue();
+ }
+}
+
+void Neighborhood::serviceActionQueue() {
+ if (!_actionQueue.empty()) {
+ QueueRequest &topRequest = _actionQueue.front();
+
+ if (!topRequest.playing) {
+ topRequest.playing = true;
+ switch (topRequest.requestType) {
+ case kNavExtraRequest:
+ startExtraSequence(topRequest.extra, topRequest.flags, topRequest.interruptionFilter);
+ break;
+ case kSpotSoundRequest:
+ _spotSounds.stopSound();
+ _spotSounds.playSoundSegment(topRequest.start, topRequest.stop);
+ _interruptionFilter = topRequest.interruptionFilter;
+ _spotSoundCallBack.setCallBackFlag(topRequest.flags);
+ _spotSoundCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ break;
+ case kDelayRequest:
+ _delayTimer.stop();
+ _delayCallBack.setCallBackFlag(topRequest.flags);
+ _delayTimer.setSegment(0, topRequest.start, topRequest.stop);
+ _delayTimer.setTime(0);
+ _delayCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ _interruptionFilter = topRequest.interruptionFilter;
+ _delayTimer.start();
+ break;
+ }
+ }
+ } else {
+ _interruptionFilter = kFilterAllInput;
+ }
+}
+
+void Neighborhood::requestAction(const QueueRequestType requestType, const ExtraID extra, const TimeValue in, const TimeValue out,
+ const InputBits interruptionFilter, const NotificationFlags flags) {
+
+ QueueRequest request;
+
+ request.requestType = requestType;
+ request.extra = extra;
+ request.start = in;
+ request.stop = out;
+ request.interruptionFilter = interruptionFilter;
+ request.playing = false;
+ request.flags = flags | kActionRequestCompletedFlag;
+ request.notification = &_neighborhoodNotification;
+ _actionQueue.push(request);
+ if (_actionQueue.size() == 1)
+ serviceActionQueue();
+}
+
+void Neighborhood::requestExtraSequence(const ExtraID whichExtra, const NotificationFlags flags, const InputBits interruptionFilter) {
+ requestAction(kNavExtraRequest, whichExtra, 0, 0, interruptionFilter, flags);
+}
+
+void Neighborhood::requestSpotSound(const TimeValue in, const TimeValue out, const InputBits interruptionFilter, const NotificationFlags flags) {
+ requestAction(kSpotSoundRequest, 0xFFFFFFFF, in, out, interruptionFilter, flags);
+}
+
+void Neighborhood::playSpotSoundSync(const TimeValue in, const TimeValue out) {
+ // Let the action queue play out first...
+ while (!actionQueueEmpty()) {
+ _vm->checkCallBacks();
+ _vm->refreshDisplay();
+ _vm->checkNotifications();
+ _vm->_system->delayMillis(10);
+ }
+
+ _spotSounds.stopSound();
+ _spotSounds.playSoundSegment(in, out);
+
+ while (_spotSounds.isPlaying()) {
+ _vm->checkCallBacks();
+ _vm->refreshDisplay();
+ _vm->_system->delayMillis(10);
+ }
+}
+
+void Neighborhood::requestDelay(const TimeValue delayDuration, const TimeScale delayScale, const InputBits interruptionFilter, const NotificationFlags flags) {
+ requestAction(kDelayRequest, 0xFFFFFFFF, delayDuration, delayScale, interruptionFilter, flags);
+}
+
+bool operator==(const QueueRequest &arg1, const QueueRequest &arg2) {
+ return arg1.requestType == arg2.requestType && arg1.extra == arg2.extra &&
+ arg1.start == arg2.start && arg1.stop == arg2.stop;
+}
+
+bool operator!=(const QueueRequest &arg1, const QueueRequest &arg2) {
+ return !operator==(arg1, arg2);
+}
+
+Common::String Neighborhood::getBriefingMovie() {
+ if (_currentInteraction)
+ return _currentInteraction->getBriefingMovie();
+
+ return Common::String();
+}
+
+Common::String Neighborhood::getEnvScanMovie() {
+ if (_currentInteraction)
+ return _currentInteraction->getEnvScanMovie();
+
+ return Common::String();
+}
+
+uint Neighborhood::getNumHints() {
+ if (_currentInteraction)
+ return _currentInteraction->getNumHints();
+
+ return 0;
+}
+
+Common::String Neighborhood::getHintMovie(uint hintNum) {
+ if (_currentInteraction)
+ return _currentInteraction->getHintMovie(hintNum);
+
+ return Common::String();
+}
+
+bool Neighborhood::canSolve() {
+ if (_currentInteraction)
+ return _currentInteraction->canSolve();
+
+ return false;
+}
+
+void Neighborhood::doSolve() {
+ if (_currentInteraction)
+ _currentInteraction->doSolve();
+}
+
+bool Neighborhood::okayToJump() {
+ return !_vm->playerHasItemID(kGasCanister) && !_vm->playerHasItemID(kMachineGun);
+}
+
+AirQuality Neighborhood::getAirQuality(const RoomID) {
+ return kAirQualityGood;
+}
+
+void Neighborhood::checkStriding() {
+ if (stillMoveForward()) {
+ ExitTable::Entry nextExit;
+ getExitEntry(GameState.getNextRoom(), GameState.getNextDirection(), nextExit);
+ keepStriding(nextExit);
+ } else {
+ stopStriding();
+ }
+}
+
+bool Neighborhood::stillMoveForward() {
+ Input input;
+
+ InputHandler::readInputDevice(input);
+ return input.upButtonAnyDown();
+}
+
+void Neighborhood::keepStriding(ExitTable::Entry &nextExitEntry) {
+ FaderMoveSpec compassMove;
+
+ if (g_map)
+ g_map->moveToMapLocation(GameState.getCurrentNeighborhood(), GameState.getNextRoom(), GameState.getNextDirection());
+
+ if (g_compass)
+ getExitCompassMove(nextExitEntry, compassMove);
+
+ GameState.setCurrentRoom(GameState.getNextRoom());
+ GameState.setCurrentDirection(GameState.getNextDirection());
+ GameState.setNextRoom(nextExitEntry.exitRoom);
+ GameState.setNextDirection(nextExitEntry.exitDirection);
+
+ if (nextExitEntry.movieEnd == nextExitEntry.exitEnd)
+ scheduleNavCallBack(kNeighborhoodMovieCompletedFlag | kMoveForwardCompletedFlag);
+ else
+ scheduleStridingCallBack(nextExitEntry.movieEnd - kStridingSlop, kStrideCompletedFlag);
+
+ if (g_compass)
+ g_compass->startFader(compassMove);
+}
+
+void Neighborhood::stopStriding() {
+ _navMovie.stop();
+ _neighborhoodNotification.setNotificationFlags(kNeighborhoodMovieCompletedFlag |
+ kMoveForwardCompletedFlag, kNeighborhoodMovieCompletedFlag | kMoveForwardCompletedFlag);
+}
+
+// Compass support
+int16 Neighborhood::getStaticCompassAngle(const RoomID, const DirectionConstant dir) {
+ // North, south, east, west
+ static const int16 compassAngles[] = { 0, 180, 90, 270 };
+ return compassAngles[dir];
+}
+
+void Neighborhood::getExitCompassMove(const ExitTable::Entry &exitEntry, FaderMoveSpec &compassMove) {
+ int32 startAngle = getStaticCompassAngle(exitEntry.room, exitEntry.direction);
+ int32 stopAngle = getStaticCompassAngle(exitEntry.exitRoom, exitEntry.exitDirection);
+
+ if (startAngle > stopAngle) {
+ if (stopAngle + 180 < startAngle)
+ stopAngle += 360;
+ } else {
+ if (startAngle + 180 < stopAngle)
+ startAngle += 360;
+ }
+
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), exitEntry.movieStart, startAngle, exitEntry.movieEnd, stopAngle);
+}
+
+void Neighborhood::scheduleNavCallBack(NotificationFlags flags) {
+ _navMovieCallBack.cancelCallBack();
+
+ if (flags != 0) {
+ _navMovieCallBack.setCallBackFlag(flags);
+ _navMovieCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ }
+}
+
+void Neighborhood::scheduleStridingCallBack(const TimeValue strideStop, NotificationFlags flags) {
+ _stridingCallBack.cancelCallBack();
+
+ if (flags != 0)
+ _stridingCallBack.scheduleCallBack(kTriggerTimeFwd, strideStop, _navMovie.getScale());
+}
+
+void Neighborhood::moveNavTo(const CoordType h, const CoordType v) {
+ CoordType oldH, oldV;
+ _navMovie.getLocation(oldH, oldV);
+
+ CoordType offH = h - oldH;
+ CoordType offV = v - oldV;
+
+ _navMovie.moveElementTo(h, v);
+ _turnPush.moveElementTo(h, v);
+
+ if (offH != 0 || offV != 0)
+ for (HotspotList::iterator it = _neighborhoodHotspots.begin(); it != _neighborhoodHotspots.end(); it++)
+ if ((*it)->getHotspotFlags() & kNeighborhoodSpotFlag)
+ (*it)->moveSpot(offH, offV);
+}
+
+void Neighborhood::activateHotspots() {
+ InputHandler::activateHotspots();
+
+ for (HotspotInfoTable::iterator it = _hotspotInfoTable.begin(); it != _hotspotInfoTable.end(); it++) {
+ HotspotInfoTable::Entry entry = *it;
+
+ if (entry.hotspotRoom == GameState.getCurrentRoom() && entry.hotspotDirection == GameState.getCurrentDirection()
+ && (entry.hotspotActivation == _currentActivation || entry.hotspotActivation == kActivateHotSpotAlways)) {
+ Hotspot *hotspot = _vm->getAllHotspots().findHotspotByID(entry.hotspot);
+ if (hotspot)
+ activateOneHotspot(entry, hotspot);
+ }
+ }
+}
+
+void Neighborhood::clickInHotspot(const Input &input, const Hotspot *clickedSpot) {
+ HotSpotFlags flags = clickedSpot->getHotspotFlags();
+
+ if ((flags & (kPickUpItemSpotFlag | kPickUpBiochipSpotFlag)) != 0) {
+ ItemID itemID = kNoItemID;
+
+ for (HotspotInfoTable::iterator it = _hotspotInfoTable.begin(); it != _hotspotInfoTable.end(); it++) {
+ if (it->hotspot == clickedSpot->getObjectID()) {
+ itemID = it->hotspotItem;
+ break;
+ }
+ }
+
+ if (itemID != kNoItemID) {
+ Item *draggingItem = _vm->getAllItems().findItemByID(itemID);
+
+ if (draggingItem) {
+ takeItemFromRoom(draggingItem);
+
+ if ((flags & kPickUpItemSpotFlag) != 0)
+ _vm->dragItem(input, draggingItem, kDragInventoryPickup);
+ else
+ _vm->dragItem(input, draggingItem, kDragBiochipPickup);
+ }
+ }
+ } else {
+ // Check other flags here?
+ if ((flags & kZoomSpotFlags) != 0) {
+ zoomTo(clickedSpot);
+ } else if ((flags & kPlayExtraSpotFlag) != 0) {
+ HotspotInfoTable::Entry hotspotEntry;
+ getHotspotEntry(clickedSpot->getObjectID(), hotspotEntry);
+ startExtraSequence(hotspotEntry.hotspotExtra, kExtraCompletedFlag, kFilterNoInput);
+ } else if ((flags & kOpenDoorSpotFlag) != 0) {
+ openDoor();
+ } else {
+ InputHandler::clickInHotspot(input, clickedSpot);
+ }
+ }
+}
+
+void Neighborhood::cantMoveThatWay(CanMoveForwardReason reason) {
+ switch (reason) {
+ case kCantMoveDoorClosed:
+ case kCantMoveDoorLocked:
+ openDoor();
+ break;
+ case kCantMoveBlocked:
+ zoomUpOrBump();
+ break;
+ default:
+ bumpIntoWall();
+ break;
+ }
+}
+
+void Neighborhood::cantOpenDoor(CanOpenDoorReason) {
+ bumpIntoWall();
+}
+
+void Neighborhood::turnTo(const DirectionConstant direction) {
+ if (g_map)
+ g_map->moveToMapLocation(GameState.getCurrentNeighborhood(), GameState.getCurrentRoom(), direction);
+
+ // clone2727 says: Is this necessary?
+ _vm->_gfx->setCurSurface(_navMovie.getSurface());
+ _pushIn.copyToCurrentPort();
+ _vm->_gfx->setCurSurface(_vm->_gfx->getWorkArea());
+
+ // Added 2/10/97. Shouldn't this be here? Shouldn't we set the current activation to
+ // always when turning to a new view?
+ _currentActivation = kActivateHotSpotAlways;
+
+ _interruptionFilter = kFilterAllInput;
+
+ if (direction != GameState.getCurrentDirection()) {
+ GameState.setCurrentDirection(direction);
+ activateCurrentView(GameState.getCurrentRoom(), direction, kSpotOnTurnMask);
+ } else {
+ showViewFrame(getViewTime(GameState.getCurrentRoom(), GameState.getCurrentDirection()));
+ }
+
+ if (GameState.getOpenDoorRoom() != kNoRoomID) {
+ // Turning always closes a door.
+ loadAmbientLoops();
+ closeDoorOffScreen(GameState.getOpenDoorRoom(), GameState.getOpenDoorDirection());
+ GameState.setOpenDoorLocation(kNoRoomID, kNoDirection);
+ }
+
+ if (g_AIArea)
+ g_AIArea->checkMiddleArea();
+
+ checkContinuePoint(GameState.getCurrentRoom(), direction);
+
+ _vm->_cursor->hideUntilMoved();
+}
+
+void Neighborhood::spotCompleted() {
+ _interruptionFilter = kFilterAllInput;
+ showViewFrame(getViewTime(GameState.getCurrentRoom(), GameState.getCurrentDirection()));
+}
+
+void Neighborhood::doorOpened() {
+ _interruptionFilter = kFilterAllInput;
+
+ // 2/23/97
+ // Fixes funny bug with doors that are opened by dropping things on them...
+ setCurrentActivation(kActivateHotSpotAlways);
+
+ GameState.setOpenDoorLocation(GameState.getCurrentRoom(), GameState.getCurrentDirection());
+
+ SpotTable::Entry entry;
+ findSpotEntry(GameState.getCurrentRoom(), GameState.getCurrentDirection(), kSpotOnDoorOpenMask, entry);
+
+ if (entry.dstFlags & kSpotOnDoorOpenMask) {
+ startSpotOnceOnly(entry.movieStart, entry.movieEnd);
+ } else {
+ findSpotEntry(GameState.getCurrentRoom(), GameState.getCurrentDirection(), kSpotOnDoorOpenMask | kSpotLoopsMask, entry);
+
+ if (entry.dstFlags & kSpotOnDoorOpenMask)
+ startSpotLoop(entry.movieStart, entry.movieEnd);
+ }
+
+ loadAmbientLoops();
+
+ if (g_map)
+ g_map->moveToMapLocation(GameState.getCurrentNeighborhood(), GameState.getNextRoom(), GameState.getNextDirection());
+
+ if (g_AIArea)
+ g_AIArea->checkMiddleArea();
+}
+
+void Neighborhood::moveForward() {
+ ExitTable::Entry exitEntry;
+ CanMoveForwardReason moveReason = canMoveForward(exitEntry);
+
+ if (moveReason == kCanMoveForward)
+ startExitMovie(exitEntry);
+ else
+ cantMoveThatWay(moveReason);
+}
+
+void Neighborhood::turn(const TurnDirection turnDirection) {
+ DirectionConstant nextDir;
+ CanTurnReason turnReason = canTurn(turnDirection, nextDir);
+
+ if (turnReason == kCanTurn)
+ startTurnPush(turnDirection, getViewTime(GameState.getCurrentRoom(), nextDir), nextDir);
+ else
+ cantTurnThatWay(turnReason);
+}
+
+void Neighborhood::turnLeft() {
+ turn(kTurnLeft);
+}
+
+void Neighborhood::turnRight() {
+ turn(kTurnRight);
+}
+
+void Neighborhood::turnUp() {
+ turn(kTurnUp);
+}
+
+void Neighborhood::turnDown() {
+ turn(kTurnDown);
+}
+
+void Neighborhood::openDoor() {
+ DoorTable::Entry door;
+ CanOpenDoorReason doorReason = canOpenDoor(door);
+
+ if (doorReason == kCanOpenDoor)
+ startDoorOpenMovie(door.movieStart, door.movieEnd);
+ else
+ cantOpenDoor(doorReason);
+}
+
+void Neighborhood::zoomTo(const Hotspot *hotspot) {
+ ZoomTable::Entry zoomEntry;
+ getZoomEntry(hotspot->getObjectID(), zoomEntry);
+ if (!zoomEntry.isEmpty())
+ startZoomMovie(zoomEntry);
+}
+
+void Neighborhood::updateViewFrame() {
+ showViewFrame(getViewTime(GameState.getCurrentRoom(), GameState.getCurrentDirection()));
+}
+
+void Neighborhood::startSpotLoop(TimeValue startTime, TimeValue stopTime, NotificationFlags flags) {
+ _turnPush.hide();
+ startMovieSequence(startTime, stopTime, flags, true, kFilterAllInput);
+}
+
+void Neighborhood::showViewFrame(TimeValue viewTime) {
+ if ((int32)viewTime >= 0) {
+ _turnPush.hide();
+ _navMovie.stop();
+ _navMovie.setFlags(0);
+ _navMovie.setSegment(0, _navMovie.getDuration());
+ _navMovie.setTime(viewTime);
+
+ Common::Rect pushBounds;
+ _turnPush.getBounds(pushBounds);
+
+ _navMovie.moveElementTo(pushBounds.left, pushBounds.top);
+ _navMovie.show();
+ _navMovie.redrawMovieWorld();
+ }
+}
+
+void Neighborhood::startExtraSequence(const ExtraID extraID, const NotificationFlags flags, const InputBits interruptionFilter) {
+ ExtraTable::Entry entry;
+ getExtraEntry(extraID, entry);
+
+ if (entry.movieStart != 0xffffffff)
+ playExtraMovie(entry, flags, interruptionFilter);
+}
+
+bool Neighborhood::startExtraSequenceSync(const ExtraID extraID, const InputBits interruptionFilter) {
+ InputDevice.waitInput(interruptionFilter);
+ return prepareExtraSync(extraID) && waitMovieFinish(&_navMovie, interruptionFilter);
+}
+
+void Neighborhood::loopExtraSequence(const uint32 extraID, NotificationFlags flags) {
+ ExtraTable::Entry entry;
+ getExtraEntry(extraID, entry);
+
+ if (entry.movieStart != 0xffffffff) {
+ _lastExtra = extraID;
+ startSpotLoop(entry.movieStart, entry.movieEnd, flags);
+ }
+}
+
+bool Neighborhood::navMoviePlaying() {
+ return _navMovie.isRunning();
+}
+
+void Neighborhood::playDeathExtra(ExtraID extra, DeathReason deathReason) {
+ _extraDeathReason = deathReason;
+ startExtraSequence(extra, kDeathExtraCompletedFlag, kFilterNoInput);
+}
+
+void Neighborhood::die(const DeathReason deathReason) {
+ loadLoopSound1("");
+ loadLoopSound2("");
+ _vm->die(deathReason);
+}
+
+void Neighborhood::setSoundFXLevel(const uint16 fxLevel) {
+ if (_navMovie.isSurfaceValid())
+ _navMovie.setVolume(fxLevel);
+ if (_spotSounds.isSoundLoaded())
+ _spotSounds.setVolume(fxLevel);
+ if (_currentInteraction)
+ _currentInteraction->setSoundFXLevel(fxLevel);
+}
+
+void Neighborhood::setAmbienceLevel(const uint16 ambientLevel) {
+ if (_soundLoop1.isSoundLoaded())
+ _loop1Fader.setMasterVolume(_vm->getAmbienceLevel());
+ if (_soundLoop2.isSoundLoaded())
+ _loop2Fader.setMasterVolume(_vm->getAmbienceLevel());
+ if (_currentInteraction)
+ _currentInteraction->setAmbienceLevel(ambientLevel);
+}
+
+// Force the exit taken from (room, direction, alternate) to come to a stop.
+void Neighborhood::forceStridingStop(const RoomID room, const DirectionConstant direction, const AlternateID alternate) {
+ ExitTable::Entry entry = _exitTable.findEntry(room, direction, alternate);
+
+ if (entry.movieStart != 0xffffffff) {
+ TimeValue strideStop = entry.exitEnd;
+ TimeValue exitStop = entry.movieEnd;
+
+ if (strideStop != exitStop) {
+ for (ExitTable::iterator it = _exitTable.begin(); it != _exitTable.end(); it++) {
+ entry = *it;
+
+ if (entry.exitEnd == strideStop && entry.movieEnd <= exitStop) {
+ entry.exitEnd = exitStop;
+ *it = entry;
+ }
+ }
+ }
+ }
+}
+
+// Restore the exit taken from (room, direction, alternate) to stride.
+void Neighborhood::restoreStriding(const RoomID room, const DirectionConstant direction, const AlternateID alternate) {
+ ExitTable::Entry entry = _exitTable.findEntry(room, direction, alternate);
+
+ if (entry.movieStart != 0xffffffff) {
+ TimeValue strideStop = entry.exitEnd;
+ TimeValue exitStop = entry.movieEnd;
+
+ if (strideStop != entry.originalEnd) {
+ for (ExitTable::iterator it = _exitTable.begin(); it != _exitTable.end(); it++) {
+ entry = *it;
+
+ if (entry.exitEnd == strideStop && entry.movieEnd <= exitStop) {
+ entry.exitEnd = entry.originalEnd;
+ *it = entry;
+ }
+ }
+ }
+ }
+}
+
+HotspotInfoTable::Entry *Neighborhood::findHotspotEntry(const HotSpotID id) {
+ for (HotspotInfoTable::iterator it = _hotspotInfoTable.begin(); it != _hotspotInfoTable.end(); it++)
+ if (it->hotspot == id)
+ return &(*it);
+
+ return 0;
+}
+
+void Neighborhood::hideNav() {
+ _isRunning = _navMovie.isRunning();
+ _navMovie.stop();
+ _navMovie.hide();
+ _turnPush.stopFader();
+ _turnPush.hide();
+}
+
+void Neighborhood::showNav() {
+ _navMovie.show();
+ _turnPush.hide();
+ if (_isRunning)
+ _navMovie.start();
+}
+
+void Neighborhood::startExitMovie(const ExitTable::Entry &exitEntry) {
+ FaderMoveSpec compassMove;
+
+ if (g_compass)
+ getExitCompassMove(exitEntry, compassMove);
+
+ GameState.setNextRoom(exitEntry.exitRoom);
+ GameState.setNextDirection(exitEntry.exitDirection);
+
+ if (exitEntry.movieEnd == exitEntry.exitEnd) // Just a walk.
+ startMovieSequence(exitEntry.movieStart, exitEntry.movieEnd, kMoveForwardCompletedFlag, kFilterNoInput, false);
+ else // We're stridin'!
+ startMovieSequence(exitEntry.movieStart, exitEntry.exitEnd, kStrideCompletedFlag, kFilterNoInput, false, exitEntry.movieEnd);
+
+ if (g_compass)
+ g_compass->startFader(compassMove);
+}
+
+void Neighborhood::startZoomMovie(const ZoomTable::Entry &zoomEntry) {
+ FaderMoveSpec compassMove;
+
+ if (g_compass)
+ getZoomCompassMove(zoomEntry, compassMove);
+
+ GameState.setNextRoom(zoomEntry.room);
+ GameState.setNextDirection(zoomEntry.direction);
+
+ startMovieSequence(zoomEntry.movieStart, zoomEntry.movieEnd, kMoveForwardCompletedFlag, kFilterNoInput, false);
+
+ if (g_compass)
+ g_compass->startFader(compassMove);
+}
+
+void Neighborhood::startDoorOpenMovie(const TimeValue startTime, const TimeValue stopTime) {
+ startMovieSequence(startTime, stopTime, kDoorOpenCompletedFlag, kFilterNoInput, false);
+}
+
+void Neighborhood::startTurnPush(const TurnDirection turnDirection, const TimeValue newView, const DirectionConstant nextDir) {
+ if (g_AIArea)
+ g_AIArea->lockAIOut();
+
+ _vm->_cursor->hide();
+
+ GameState.setNextDirection(nextDir);
+
+ _interruptionFilter = kFilterNoInput;
+ _turnPush.stopFader();
+
+ // Set up callback.
+ _turnPushCallBack.setCallBackFlag(kTurnCompletedFlag);
+ _turnPushCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+
+ // Stop nav movie.
+ _navMovie.stop();
+ _navMovie.setFlags(0);
+
+ // Set segment of nav movie to whole movie, so that subsequent initFromMovieFrame
+ // will work.
+ _navMovie.setSegment(0, _navMovie.getDuration());
+
+ _pushIn.initFromMovieFrame(_navMovie.getMovie(), newView);
+
+ _navMovie.hide();
+
+ switch (turnDirection) {
+ case kTurnLeft:
+ _turnPush.setSlideDirection(kSlideRightMask);
+ break;
+ case kTurnRight:
+ _turnPush.setSlideDirection(kSlideLeftMask);
+ break;
+ case kTurnUp:
+ _turnPush.setSlideDirection(kSlideDownMask);
+ break;
+ case kTurnDown:
+ _turnPush.setSlideDirection(kSlideUpMask);
+ break;
+ }
+
+ _turnPush.show();
+
+ FaderMoveSpec moveSpec;
+ moveSpec.makeTwoKnotFaderSpec(60, 0, 0, 15, 1000);
+ _turnPush.startFader(moveSpec);
+
+ if (g_compass) {
+ _turnPush.pauseFader();
+
+ int32 startAngle = getStaticCompassAngle(GameState.getCurrentRoom(), GameState.getCurrentDirection());
+ int32 stopAngle = getStaticCompassAngle(GameState.getCurrentRoom(), nextDir);
+
+ if (turnDirection == kTurnLeft) {
+ if (startAngle < stopAngle)
+ startAngle += 360;
+ } else {
+ if (stopAngle < startAngle)
+ stopAngle += 360;
+ }
+
+ FaderMoveSpec turnSpec;
+ _turnPush.getCurrentFaderMove(turnSpec);
+
+ FaderMoveSpec compassMove;
+ compassMove.makeTwoKnotFaderSpec(turnSpec.getFaderScale(), turnSpec.getNthKnotTime(0), startAngle, turnSpec.getNthKnotTime(1), stopAngle);
+ g_compass->startFader(compassMove);
+ }
+
+ _turnPushCallBack.cancelCallBack();
+ _turnPush.continueFader();
+
+ do {
+ _vm->checkCallBacks();
+ _vm->refreshDisplay();
+ _vm->_system->delayMillis(10);
+ } while (_turnPush.isFading());
+
+ _turnPush.stopFader();
+ _neighborhoodNotification.setNotificationFlags(kTurnCompletedFlag, kTurnCompletedFlag);
+}
+
+void Neighborhood::playExtraMovie(const ExtraTable::Entry &extraEntry, const NotificationFlags flags, const InputBits interruptionInput) {
+ FaderMoveSpec compassMove;
+
+ if (g_compass)
+ getExtraCompassMove(extraEntry, compassMove);
+
+ _lastExtra = extraEntry.extra;
+ _turnPush.hide();
+ startMovieSequence(extraEntry.movieStart, extraEntry.movieEnd, flags, false, interruptionInput);
+
+ if (g_compass)
+ g_compass->startFader(compassMove);
+}
+
+void Neighborhood::activateCurrentView(const RoomID room, const DirectionConstant direction, SpotFlags flag) {
+ SpotTable::Entry entry;
+ findSpotEntry(room, direction, flag, entry);
+
+ if (entry.dstFlags & flag) {
+ startSpotOnceOnly(entry.movieStart, entry.movieEnd);
+ } else {
+ findSpotEntry(room, direction, flag | kSpotLoopsMask, entry);
+
+ if (entry.dstFlags & flag)
+ startSpotLoop(entry.movieStart, entry.movieEnd);
+ else
+ showViewFrame(getViewTime(room, direction));
+ }
+}
+
+void Neighborhood::activateOneHotspot(HotspotInfoTable::Entry &entry, Hotspot *hotspot) {
+ switch (_vm->getDragType()) {
+ case kDragInventoryUse:
+ if ((hotspot->getHotspotFlags() & kDropItemSpotFlag) != 0 &&
+ _vm->getDraggingItem()->getObjectID() == entry.hotspotItem)
+ hotspot->setActive();
+ break;
+ case kDragInventoryPickup:
+ case kDragBiochipPickup:
+ // Do nothing -- neighborhoods activate no hot spots in this case...
+ break;
+ default:
+ if ((hotspot->getHotspotFlags() & kPickUpBiochipSpotFlag) != 0) {
+ Item *item = _vm->getAllItems().findItemByID(entry.hotspotItem);
+ if (item && item->getItemNeighborhood() == getObjectID())
+ hotspot->setActive();
+ } else {
+ HotSpotFlags flags = hotspot->getHotspotFlags();
+
+ if ((flags & kNeighborhoodSpotFlag) != 0) {
+ if (flags & kOpenDoorSpotFlag) {
+ if (!GameState.isCurrentDoorOpen())
+ hotspot->setActive();
+ } else if ((flags & (kZoomSpotFlags | kClickSpotFlag | kPlayExtraSpotFlag)) != 0) {
+ hotspot->setActive();
+ } else if ((flags & kPickUpItemSpotFlag) != 0) {
+ // Changed this 2/19/96
+ // Should only light up this hot spot if the item's taken flag is not
+ // set. It's not based on neighborhood ID since that can be reset by the
+ // destroying process.
+
+ if (!GameState.isTakenItemID(entry.hotspotItem))
+ hotspot->setActive();
+ }
+ }
+ }
+ break;
+ }
+}
+
+void Neighborhood::startSpotOnceOnly(TimeValue startTime, TimeValue stopTime) {
+ _turnPush.hide();
+ startMovieSequence(startTime, stopTime, kSpotCompletedFlag, kFilterNoInput, false);
+}
+
+void Neighborhood::startMovieSequence(const TimeValue startTime, const TimeValue stopTime, NotificationFlags flags, bool loopSequence,
+ const InputBits interruptionInput, const TimeValue strideStop) {
+ if (!loopSequence && g_AIArea)
+ g_AIArea->lockAIOut();
+
+ _interruptionFilter = interruptionInput;
+
+ // Stop the movie before doing anything else
+ _navMovie.stop();
+
+ Common::Rect pushBounds;
+ _turnPush.getBounds(pushBounds);
+
+ _navMovie.moveElementTo(pushBounds.left, pushBounds.top);
+ _navMovie.show();
+ _navMovie.setFlags(0);
+ _navMovie.setSegment(startTime, stopTime);
+ _navMovie.setTime(startTime);
+
+ if (loopSequence)
+ _navMovie.setFlags(kLoopTimeBase);
+ else
+ flags |= kNeighborhoodMovieCompletedFlag;
+
+ if (strideStop != 0xffffffff)
+ // Subtract a little slop from the striding stop time to keep from "pumping" at the
+ // end of a walk.
+ // 40 is one frame (scale == 600, 15 fps).
+ scheduleStridingCallBack(strideStop - kStridingSlop, flags);
+ else
+ scheduleNavCallBack(flags);
+
+ _navMovie.start();
+}
+
+void Neighborhood::throwAwayInterface() {
+ _doorTable.clear();
+ _exitTable.clear();
+ _extraTable.clear();
+ _hotspotInfoTable.clear();
+ _spotTable.clear();
+ _turnTable.clear();
+ _viewTable.clear();
+ _zoomTable.clear();
+
+ _navMovie.stopDisplaying();
+ _navMovie.releaseMovie();
+ _pushIn.deallocateSurface();
+ _turnPush.stopDisplaying();
+ _turnPush.setInAndOutElements(0, 0);
+ _turnPush.disposeAllCallBacks();
+
+ for (HotspotList::iterator it = _neighborhoodHotspots.begin(); it != _neighborhoodHotspots.end(); it++)
+ _vm->getAllHotspots().remove(*it);
+
+ _neighborhoodHotspots.deleteHotspots();
+ _spotSounds.disposeSound();
+ _delayTimer.disposeAllCallBacks();
+
+ if (g_AIArea) {
+ g_AIArea->saveAIState();
+ g_AIArea->removeAllRules();
+ }
+
+ if (_currentInteraction)
+ newInteraction(kNoInteractionID);
+
+ _croppedMovie.releaseMovie();
+
+ loadLoopSound1("");
+ loadLoopSound2("");
+
+ if (g_energyMonitor) {
+ g_energyMonitor->stopEnergyDraining();
+ g_energyMonitor->saveCurrentEnergyValue();
+ }
+
+ delete g_interface;
+}
+
+bool Neighborhood::prepareExtraSync(const ExtraID extraID) {
+ ExtraTable::Entry extraEntry;
+ FaderMoveSpec compassMove;
+
+ if (g_compass) {
+ getExtraEntry(extraID, extraEntry);
+ getExtraCompassMove(extraEntry, compassMove);
+ }
+
+ ExtraTable::Entry entry;
+ getExtraEntry(extraID, entry);
+ bool result;
+
+ if (entry.movieStart != 0xffffffff) {
+ _turnPush.hide();
+
+ // Stop the movie before doing anything else
+ _navMovie.stop();
+
+ Common::Rect pushBounds;
+ _turnPush.getBounds(pushBounds);
+ _navMovie.moveElementTo(pushBounds.left, pushBounds.top);
+
+ _navMovie.show();
+ _navMovie.setFlags(0);
+ _navMovie.setSegment(entry.movieStart, entry.movieEnd);
+ _navMovie.setTime(entry.movieStart);
+ _navMovie.start();
+ result = true;
+ } else {
+ result = false;
+ }
+
+ if (result && g_compass)
+ g_compass->startFader(compassMove);
+
+ return result;
+}
+
+bool Neighborhood::waitMovieFinish(Movie *movie, const InputBits interruptionFilter) {
+ Input input;
+ bool result = true;
+ bool saveAllowed = _vm->swapSaveAllowed(false);
+ bool openAllowed = _vm->swapLoadAllowed(false);
+
+ while (movie->isRunning()) {
+ InputDevice.getInput(input, interruptionFilter);
+
+ if (input.anyInput() || _vm->shouldQuit()) {
+ result = false;
+ break;
+ }
+
+ _vm->checkCallBacks();
+ _vm->refreshDisplay();
+ _vm->_system->delayMillis(10);
+ }
+
+ movie->stop();
+ _vm->swapSaveAllowed(saveAllowed);
+ _vm->swapLoadAllowed(openAllowed);
+
+ return result;
+}
+
+InputBits Neighborhood::getInputFilter() {
+ return _interruptionFilter & InputHandler::getInputFilter();
+}
+
+void Neighborhood::getZoomCompassMove(const ZoomTable::Entry &zoomEntry, FaderMoveSpec &compassMove) {
+ int32 startAngle = getStaticCompassAngle(GameState.getCurrentRoom(), GameState.getCurrentDirection());
+ int32 stopAngle = getStaticCompassAngle(zoomEntry.room, zoomEntry.direction);
+
+ if (startAngle > stopAngle) {
+ if (stopAngle + 180 < startAngle)
+ stopAngle += 360;
+ } else {
+ if (startAngle + 180 < stopAngle)
+ startAngle += 360;
+ }
+
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), zoomEntry.movieStart, startAngle, zoomEntry.movieEnd, stopAngle);
+}
+
+void Neighborhood::getExtraCompassMove(const ExtraTable::Entry &, FaderMoveSpec &compassMove) {
+ compassMove.makeOneKnotFaderSpec(g_compass->getFaderValue());
+}
+
+void Neighborhood::setUpAIRules() {
+ // Set up default rules here:
+ // -- Energy warning rules.
+
+ if (g_AIArea) {
+ g_AIArea->forceAIUnlocked();
+
+ if (!_vm->isDemo() && (getObjectID() == kPrehistoricID || getObjectID() == kNoradAlphaID ||
+ getObjectID() == kNoradDeltaID || getObjectID() == kMarsID || getObjectID() == kWSCID)) {
+
+ AIEnergyMonitorCondition *condition50 = new AIEnergyMonitorCondition(kWorriedEnergy);
+ AIPlayMessageAction *message = new AIPlayMessageAction("Images/AI/Globals/XGLOB4A", false);
+ AIRule *rule50 = new AIRule(condition50, message);
+
+ AIEnergyMonitorCondition *condition25 = new AIEnergyMonitorCondition(kNervousEnergy);
+ AICompoundAction *compound = new AICompoundAction();
+ message = new AIPlayMessageAction("Images/AI/Globals/XGLOB4B", false);
+ compound->addAction(message);
+ AIDeactivateRuleAction *deactivate = new AIDeactivateRuleAction(rule50);
+ compound->addAction(deactivate);
+ AIRule *rule25 = new AIRule(condition25, compound);
+
+ AIEnergyMonitorCondition *condition5 = new AIEnergyMonitorCondition(kPanicStrickenEnergy);
+ compound = new AICompoundAction();
+ message = new AIPlayMessageAction("Images/AI/Globals/XGLOB4C", false);
+ compound->addAction(message);
+ deactivate = new AIDeactivateRuleAction(rule50);
+ compound->addAction(deactivate);
+ deactivate = new AIDeactivateRuleAction(rule25);
+ compound->addAction(deactivate);
+ AIRule *rule5 = new AIRule(condition5, compound);
+
+ g_AIArea->addAIRule(rule5);
+ g_AIArea->addAIRule(rule25);
+ g_AIArea->addAIRule(rule50);
+ }
+ }
+}
+
+GameInteraction *Neighborhood::makeInteraction(const InteractionID interactionID) {
+ if (interactionID == kNoInteractionID)
+ return 0;
+
+ return new GameInteraction(interactionID, this);
+}
+
+void Neighborhood::newInteraction(const InteractionID interactionID) {
+ GameInteraction *interaction = makeInteraction(interactionID);
+ _doneWithInteraction = false;
+
+ if (_currentInteraction) {
+ _currentInteraction->stopInteraction();
+ delete _currentInteraction;
+ }
+
+ _currentInteraction = interaction;
+
+ if (_currentInteraction)
+ _currentInteraction->startInteraction();
+
+ if (g_AIArea)
+ g_AIArea->checkMiddleArea();
+}
+
+void Neighborhood::bumpIntoWall() {
+ _vm->_gfx->shakeTheWorld(15, 30);
+}
+
+void Neighborhood::zoomUpOrBump() {
+ Hotspot *zoomSpot = 0;
+
+ for (HotspotList::iterator it = _vm->getAllHotspots().begin(); it != _vm->getAllHotspots().end(); it++) {
+ Hotspot *hotspot = *it;
+
+ if ((hotspot->getHotspotFlags() & (kNeighborhoodSpotFlag | kZoomInSpotFlag)) == (kNeighborhoodSpotFlag | kZoomInSpotFlag)) {
+ HotspotInfoTable::Entry *entry = findHotspotEntry(hotspot->getObjectID());
+
+ if (entry && entry->hotspotRoom == GameState.getCurrentRoom() && entry->hotspotDirection == GameState.getCurrentDirection()) {
+ if (zoomSpot) {
+ zoomSpot = 0;
+ break;
+ } else {
+ zoomSpot = hotspot;
+ }
+ }
+ }
+ }
+
+ if (zoomSpot)
+ zoomTo(zoomSpot);
+ else
+ bumpIntoWall();
+}
+
+void Neighborhood::loadLoopSound1(const Common::String &soundName, uint16 volume, TimeValue fadeOut, TimeValue fadeIn, TimeScale fadeScale) {
+ FaderMoveSpec faderMove;
+
+ if (!loop1Loaded(soundName)) {
+ _loop1SoundString = soundName;
+
+ if (_soundLoop1.isSoundLoaded()) {
+ faderMove.makeTwoKnotFaderSpec(fadeScale, 0, _loop1Fader.getFaderValue(), fadeOut, 0);
+ _loop1Fader.startFaderSync(faderMove);
+ }
+
+ if (!_loop1SoundString.empty()) {
+ _soundLoop1.initFromAIFFFile(_loop1SoundString);
+ _soundLoop1.loopSound();
+ _loop1Fader.setMasterVolume(_vm->getAmbienceLevel());
+ _loop1Fader.setFaderValue(0);
+ faderMove.makeTwoKnotFaderSpec(fadeScale, 0, 0, fadeIn, volume);
+ _loop1Fader.startFaderSync(faderMove);
+ } else {
+ _soundLoop1.disposeSound();
+ }
+ } else if (_loop1Fader.getFaderValue() != volume) {
+ faderMove.makeTwoKnotFaderSpec(fadeScale, 0, _loop1Fader.getFaderValue(), fadeIn, volume);
+ _loop1Fader.startFaderSync(faderMove);
+ }
+}
+
+void Neighborhood::loadLoopSound2(const Common::String &soundName, uint16 volume, TimeValue fadeOut, TimeValue fadeIn, TimeScale fadeScale) {
+ FaderMoveSpec faderMove;
+
+ if (!loop2Loaded(soundName)) {
+ _loop2SoundString = soundName;
+
+ if (_soundLoop2.isSoundLoaded()) {
+ faderMove.makeTwoKnotFaderSpec(fadeScale, 0, _loop2Fader.getFaderValue(), fadeOut, 0);
+ _loop2Fader.startFaderSync(faderMove);
+ }
+
+ if (!_loop2SoundString.empty()) {
+ _soundLoop2.initFromAIFFFile(_loop2SoundString);
+ _soundLoop2.loopSound();
+ _loop2Fader.setMasterVolume(_vm->getAmbienceLevel());
+ _loop2Fader.setFaderValue(0);
+ faderMove.makeTwoKnotFaderSpec(fadeScale, 0, 0, fadeIn, volume);
+ _loop2Fader.startFaderSync(faderMove);
+ } else {
+ _soundLoop2.disposeSound();
+ }
+ } else if (_loop2Fader.getFaderValue() != volume) {
+ faderMove.makeTwoKnotFaderSpec(fadeScale, 0, _loop2Fader.getFaderValue(), fadeIn, volume);
+ _loop2Fader.startFaderSync(faderMove);
+ }
+}
+
+void Neighborhood::takeItemFromRoom(Item *item) {
+ item->setItemRoom(kNoNeighborhoodID, kNoRoomID, kNoDirection);
+ // Also set the taken item flag. Do this before updating the view frame.
+ GameState.setTakenItem(item, true);
+ updateViewFrame();
+}
+
+void Neighborhood::dropItemIntoRoom(Item *item, Hotspot *) {
+ item->setItemRoom(getObjectID(), GameState.getCurrentRoom(), GameState.getCurrentDirection());
+ // Also set the taken item flag. Do this before updating the view frame.
+ GameState.setTakenItem(item, false);
+ updateViewFrame();
+}
+
+void Neighborhood::makeContinuePoint() {
+ _vm->makeContinuePoint();
+}
+
+void Neighborhood::startLoop1Fader(const FaderMoveSpec &faderMove) {
+ _loop1Fader.startFader(faderMove);
+}
+
+void Neighborhood::startLoop2Fader(const FaderMoveSpec &faderMove) {
+ _loop2Fader.startFader(faderMove);
+}
+
+// *** Revised 6/13/96 to use the last frame of the extra sequence.
+// Necessary for Cinepak buildup.
+void Neighborhood::showExtraView(uint32 extraID) {
+ ExtraTable::Entry entry;
+ getExtraEntry(extraID, entry);
+
+ if (entry.movieEnd != 0xffffffff)
+ showViewFrame(entry.movieEnd - 1);
+}
+
+void Neighborhood::startExtraLongSequence(const uint32 firstExtra, const uint32 lastExtra, NotificationFlags flags,
+ const InputBits interruptionFilter) {
+ ExtraTable::Entry firstEntry, lastEntry;
+ getExtraEntry(firstExtra, firstEntry);
+
+ if (firstEntry.movieStart != 0xffffffff) {
+ getExtraEntry(lastExtra, lastEntry);
+ _lastExtra = firstExtra;
+ _turnPush.hide();
+ startMovieSequence(firstEntry.movieStart, lastEntry.movieEnd, flags, kFilterNoInput, interruptionFilter);
+ }
+}
+
+void Neighborhood::openCroppedMovie(const Common::String &movieName, CoordType left, CoordType top) {
+ if (_croppedMovie.isMovieValid())
+ closeCroppedMovie();
+
+ _croppedMovie.initFromMovieFile(movieName);
+ _croppedMovie.moveElementTo(left, top);
+ _croppedMovie.startDisplaying();
+ _croppedMovie.show();
+}
+
+void Neighborhood::loopCroppedMovie(const Common::String &movieName, CoordType left, CoordType top) {
+ openCroppedMovie(movieName, left, top);
+ _croppedMovie.redrawMovieWorld();
+ _croppedMovie.setFlags(kLoopTimeBase);
+ _croppedMovie.start();
+}
+
+void Neighborhood::closeCroppedMovie() {
+ _croppedMovie.releaseMovie();
+}
+
+void Neighborhood::playCroppedMovieOnce(const Common::String &movieName, CoordType left, CoordType top, const InputBits interruptionFilter) {
+ openCroppedMovie(movieName, left, top);
+ _croppedMovie.redrawMovieWorld();
+ _croppedMovie.start();
+
+ InputBits oldInterruptionFilter = _interruptionFilter;
+ if (oldInterruptionFilter != kFilterNoInput)
+ _interruptionFilter = kFilterNoInput;
+
+ bool saveAllowed = _vm->swapSaveAllowed(false);
+ bool openAllowed = _vm->swapLoadAllowed(false);
+
+ Input input;
+ while (_croppedMovie.isRunning() && !_vm->shouldQuit()) {
+ _vm->processShell();
+ InputDevice.getInput(input, interruptionFilter);
+ if (input.anyInput() || _vm->saveRequested() || _vm->loadRequested() || _vm->shouldQuit())
+ break;
+ _vm->_system->delayMillis(10);
+ }
+
+ if (oldInterruptionFilter != kFilterNoInput)
+ _interruptionFilter = oldInterruptionFilter;
+
+ closeCroppedMovie();
+ _vm->swapSaveAllowed(saveAllowed);
+ _vm->swapLoadAllowed(openAllowed);
+}
+
+void Neighborhood::playMovieSegment(Movie *movie, TimeValue startTime, TimeValue stopTime) {
+ TimeValue oldStart, oldStop;
+ movie->getSegment(oldStart, oldStop);
+
+ if (stopTime == 0xffffffff)
+ stopTime = movie->getDuration();
+
+ movie->setSegment(startTime, stopTime);
+ movie->setTime(startTime);
+ movie->start();
+
+ while (movie->isRunning()) {
+ _vm->checkCallBacks();
+ _vm->refreshDisplay();
+ _vm->_system->delayMillis(10);
+ }
+
+ movie->stop();
+ movie->setSegment(oldStart, oldStop);
+}
+
+void Neighborhood::recallToTSASuccess() {
+ if (GameState.allTimeZonesFinished())
+ _vm->jumpToNewEnvironment(kFullTSAID, kTSA37, kNorth);
+ else
+ _vm->jumpToNewEnvironment(kTinyTSAID, kTinyTSA37, kNorth);
+}
+
+void Neighborhood::recallToTSAFailure() {
+ _vm->jumpToNewEnvironment(kTinyTSAID, kTinyTSA37, kNorth);
+}
+
+void Neighborhood::handleInput(const Input &input, const Hotspot *cursorSpot) {
+ if (_vm->getGameMode() == kModeNavigation) {
+ if (input.upButtonAnyDown())
+ upButton(input);
+ else if (input.downButtonAnyDown())
+ downButton(input);
+ else if (input.leftButtonAnyDown())
+ leftButton(input);
+ else if (input.rightButtonAnyDown())
+ rightButton(input);
+ }
+
+ InputHandler::handleInput(input, cursorSpot);
+}
+
+void Neighborhood::setHotspotFlags(const HotSpotID id, const HotSpotFlags flags) {
+ Hotspot *hotspot = _vm->getAllHotspots().findHotspotByID(id);
+ hotspot->setMaskedHotspotFlags(flags, flags);
+}
+
+void Neighborhood::setIsItemTaken(const ItemID id) {
+ GameState.setTakenItemID(id, _vm->playerHasItemID(id));
+}
+
+void Neighborhood::upButton(const Input &) {
+ moveForward();
+}
+
+void Neighborhood::leftButton(const Input &) {
+ turnLeft();
+}
+
+void Neighborhood::rightButton(const Input &) {
+ turnRight();
+}
+
+void Neighborhood::downButton(const Input &) {
+ if (_inputHandler->wantsCursor()) {
+ _vm->getAllHotspots().deactivateAllHotspots();
+ _inputHandler->activateHotspots();
+
+ for (HotspotList::iterator it = _vm->getAllHotspots().begin(); it != _vm->getAllHotspots().end(); it++) {
+ Hotspot *hotspot = *it;
+
+ if (hotspot->isSpotActive() && (hotspot->getHotspotFlags() & (kNeighborhoodSpotFlag | kZoomOutSpotFlag)) == (kNeighborhoodSpotFlag | kZoomOutSpotFlag)) {
+ HotspotInfoTable::Entry *entry = findHotspotEntry(hotspot->getObjectID());
+
+ if (entry && entry->hotspotRoom == GameState.getCurrentRoom() && entry->hotspotDirection == GameState.getCurrentDirection()) {
+ Input scratch;
+ _inputHandler->clickInHotspot(scratch, hotspot);
+ return;
+ }
+ }
+ }
+ }
+}
+
+void Neighborhood::initOnePicture(Picture *picture, const Common::String &pictureName, DisplayOrder order, CoordType left, CoordType top, bool show) {
+ picture->initFromPICTFile(pictureName);
+ picture->setDisplayOrder(order);
+ picture->moveElementTo(left, top);
+ picture->startDisplaying();
+ if (show)
+ picture->show();
+}
+
+void Neighborhood::initOneMovie(Movie *movie, const Common::String &movieName, DisplayOrder order, CoordType left, CoordType top, bool show) {
+ movie->initFromMovieFile(movieName);
+ movie->setDisplayOrder(order);
+ movie->moveElementTo(left, top);
+ movie->startDisplaying();
+
+ if (show)
+ movie->show();
+
+ movie->redrawMovieWorld();
+}
+
+void Neighborhood::reinstateMonocleInterface() {
+ _vm->_gfx->disableErase();
+
+ _vm->createInterface();
+
+ if (g_AIArea)
+ setNextHandler(g_AIArea);
+
+ init();
+
+ moveNavTo(kNavAreaLeft, kNavAreaTop);
+
+ if (g_interface)
+ g_interface->setDate(getDateResID());
+
+ if (g_AIArea)
+ g_AIArea->restoreAIState();
+}
+
+void Neighborhood::useIdleTime() {
+ if (_doneWithInteraction) {
+ newInteraction(kNoInteractionID);
+ loadAmbientLoops();
+ }
+}
+
+void Neighborhood::timerFunction() {
+ timerExpired(getTimerEvent());
+}
+
+void Neighborhood::scheduleEvent(const TimeValue time, const TimeScale scale, const uint32 eventType) {
+ _eventTimer.stopFuse();
+ _eventTimer.primeFuse(time, scale);
+ _timerEvent = eventType;
+ _eventTimer.setFunctor(new Common::Functor0Mem<void, Neighborhood>(this, &Neighborhood::timerFunction));
+ _eventTimer.lightFuse();
+}
+
+void Neighborhood::cancelEvent() {
+ _eventTimer.stopFuse();
+}
+
+void Neighborhood::pauseTimer() {
+ _eventTimer.pauseFuse();
+}
+
+void Neighborhood::resumeTimer() {
+ // NOTE: Yes, this function calls pauseFuse!
+ // Looks like an original game bug, will need
+ // to investigate how this affects gameplay.
+ _eventTimer.pauseFuse();
+}
+
+bool Neighborhood::timerPaused() {
+ return _eventTimer.isFusePaused();
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/neighborhood.h b/engines/pegasus/neighborhood/neighborhood.h
new file mode 100644
index 0000000000..3c1c5eac92
--- /dev/null
+++ b/engines/pegasus/neighborhood/neighborhood.h
@@ -0,0 +1,408 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_H
+#define PEGASUS_NEIGHBORHOOD_H
+
+#include "common/queue.h"
+#include "common/str.h"
+
+#include "pegasus/fader.h"
+#include "pegasus/hotspot.h"
+#include "pegasus/input.h"
+#include "pegasus/movie.h"
+#include "pegasus/notification.h"
+#include "pegasus/sound.h"
+#include "pegasus/timers.h"
+#include "pegasus/transition.h"
+#include "pegasus/util.h"
+#include "pegasus/neighborhood/door.h"
+#include "pegasus/neighborhood/exit.h"
+#include "pegasus/neighborhood/extra.h"
+#include "pegasus/neighborhood/hotspotinfo.h"
+#include "pegasus/neighborhood/spot.h"
+#include "pegasus/neighborhood/turn.h"
+#include "pegasus/neighborhood/view.h"
+#include "pegasus/neighborhood/zoom.h"
+
+namespace Pegasus {
+
+class PegasusEngine;
+
+// Pegasus Prime neighborhood id's
+static const NeighborhoodID kCaldoriaID = 0;
+static const NeighborhoodID kFullTSAID = 1;
+static const NeighborhoodID kFinalTSAID = 2;
+static const NeighborhoodID kTinyTSAID = 3;
+static const NeighborhoodID kPrehistoricID = 4;
+static const NeighborhoodID kMarsID = 5;
+static const NeighborhoodID kWSCID = 6;
+static const NeighborhoodID kNoradAlphaID = 7;
+static const NeighborhoodID kNoradDeltaID = 8;
+// The sub chase is not really a neighborhood, but we define a constant that is used
+// to allow an easy transition out of Norad Alpha.
+static const NeighborhoodID kNoradSubChaseID = 1000;
+
+static const TimeScale kDefaultLoopFadeScale = kThirtyTicksPerSecond;
+static const TimeValue kDefaultLoopFadeOut = kHalfSecondPerThirtyTicks;
+static const TimeValue kDefaultLoopFadeIn = kHalfSecondPerThirtyTicks;
+
+enum QueueRequestType {
+ kNavExtraRequest,
+ kSpotSoundRequest,
+ kDelayRequest
+};
+
+// For delay requests, start is interpreted as the total delay and stop is interpreted
+// as the scale the delay is in.
+// For extra requests, start and stop are not used.
+struct QueueRequest {
+ QueueRequestType requestType;
+ ExtraID extra;
+ TimeValue start, stop;
+ InputBits interruptionFilter;
+ bool playing;
+ NotificationFlags flags;
+ Notification *notification;
+};
+
+bool operator==(const QueueRequest &arg1, const QueueRequest &arg2);
+bool operator!=(const QueueRequest &arg1, const QueueRequest &arg2);
+
+class GameInteraction;
+class Item;
+class Neighborhood;
+
+class StriderCallBack : public TimeBaseCallBack {
+public:
+ StriderCallBack(Neighborhood *);
+ virtual ~StriderCallBack() {}
+
+protected:
+ virtual void callBack();
+
+ Neighborhood *_neighborhood;
+};
+
+typedef Common::Queue<QueueRequest> NeighborhoodActionQueue;
+
+class Neighborhood : public IDObject, public NotificationReceiver, public InputHandler, public Idler {
+friend class StriderCallBack;
+
+public:
+ Neighborhood(InputHandler *nextHandler, PegasusEngine *vm, const Common::String &resName, NeighborhoodID id);
+ virtual ~Neighborhood();
+
+ virtual void init();
+ virtual void start();
+ virtual void moveNavTo(const CoordType, const CoordType);
+ virtual void checkContinuePoint(const RoomID, const DirectionConstant) = 0;
+ void makeContinuePoint();
+
+ virtual void activateHotspots();
+ virtual void clickInHotspot(const Input &, const Hotspot *);
+
+ virtual CanMoveForwardReason canMoveForward(ExitTable::Entry &entry);
+ virtual CanTurnReason canTurn(TurnDirection turn, DirectionConstant &nextDir);
+ virtual CanOpenDoorReason canOpenDoor(DoorTable::Entry &entry);
+
+ virtual void cantMoveThatWay(CanMoveForwardReason);
+ virtual void cantTurnThatWay(CanTurnReason) {}
+ virtual void cantOpenDoor(CanOpenDoorReason);
+ virtual void arriveAt(const RoomID room, const DirectionConstant direction);
+ virtual void turnTo(const DirectionConstant);
+ virtual void spotCompleted();
+ virtual void doorOpened();
+ virtual void closeDoorOffScreen(const RoomID, const DirectionConstant) {}
+
+ virtual void moveForward();
+ virtual void turn(const TurnDirection);
+ virtual void turnLeft();
+ virtual void turnRight();
+ virtual void turnUp();
+ virtual void turnDown();
+ virtual void openDoor();
+ virtual void zoomTo(const Hotspot *);
+
+ virtual void updateViewFrame();
+
+ void requestExtraSequence(const ExtraID, const NotificationFlags, const InputBits interruptionFilter);
+ void requestSpotSound(const TimeValue, const TimeValue, const InputBits interruptionFilter, const NotificationFlags);
+ void playSpotSoundSync(const TimeValue in, const TimeValue out);
+ void requestDelay(const TimeValue, const TimeScale, const InputBits interruptionFilter, const NotificationFlags);
+
+ Notification *getNeighborhoodNotification() { return &_neighborhoodNotification; }
+
+ virtual void getExtraEntry(const uint32 id, ExtraTable::Entry &extraEntry);
+ virtual void startSpotLoop(TimeValue, TimeValue, NotificationFlags = 0);
+ virtual bool actionQueueEmpty() { return _actionQueue.empty(); }
+ virtual void showViewFrame(TimeValue);
+ virtual void findSpotEntry(const RoomID room, const DirectionConstant direction, SpotFlags flags, SpotTable::Entry &spotEntry);
+ virtual void startExtraSequence(const ExtraID, const NotificationFlags, const InputBits interruptionFilter);
+ bool startExtraSequenceSync(const ExtraID, const InputBits);
+ virtual void loopExtraSequence(const uint32, NotificationFlags = 0);
+ int32 getLastExtra() const { return _lastExtra; }
+ virtual void scheduleNavCallBack(NotificationFlags);
+
+ Movie *getNavMovie() { return &_navMovie; }
+ bool navMoviePlaying();
+
+ void setCurrentAlternate(const AlternateID alt) { _currentAlternate = alt; }
+ AlternateID getCurrentAlternate() const { return _currentAlternate; }
+
+ void setCurrentActivation(const HotSpotActivationID a) { _currentActivation = a; }
+ HotSpotActivationID getCurrentActivation() { return _currentActivation; }
+
+ virtual void playDeathExtra(ExtraID, DeathReason);
+ virtual void die(const DeathReason);
+
+ virtual void setSoundFXLevel(const uint16);
+ virtual void setAmbienceLevel(const uint16);
+
+ void forceStridingStop(const RoomID, const DirectionConstant, const AlternateID);
+ void restoreStriding(const RoomID, const DirectionConstant, const AlternateID);
+
+ HotspotInfoTable::Entry *findHotspotEntry(const HotSpotID);
+
+ Push *getTurnPush() { return &_turnPush; }
+ Picture *getTurnPushPicture() { return &_pushIn; }
+
+ void hideNav();
+ void showNav();
+
+ virtual void loadAmbientLoops() {}
+
+ virtual void flushGameState() {}
+
+ virtual Common::String getBriefingMovie();
+ virtual Common::String getEnvScanMovie();
+ virtual uint getNumHints();
+ virtual Common::String getHintMovie(uint);
+ virtual bool canSolve();
+ virtual void prepareForAIHint(const Common::String &) {}
+ virtual void cleanUpAfterAIHint(const Common::String &) {}
+ virtual void doSolve();
+
+ virtual bool okayToJump();
+
+ virtual AirQuality getAirQuality(const RoomID);
+ virtual void checkAirMask() {}
+ virtual void checkFlashlight() {}
+ virtual void shieldOn() {}
+ virtual void shieldOff() {}
+
+ virtual void loadLoopSound1(const Common::String &, const uint16 volume = 0x100,
+ const TimeValue fadeOut = kDefaultLoopFadeOut, const TimeValue fadeIn = kDefaultLoopFadeIn,
+ const TimeScale fadeScale = kDefaultLoopFadeScale);
+ virtual void loadLoopSound2(const Common::String &, const uint16 volume = 0x100,
+ const TimeValue fadeOut = kDefaultLoopFadeOut, const TimeValue fadeIn = kDefaultLoopFadeIn,
+ const TimeScale fadeScale = kDefaultLoopFadeScale);
+ bool loop1Loaded(const Common::String &soundName) { return _loop1SoundString == soundName; }
+ bool loop2Loaded(const Common::String &soundName) { return _loop2SoundString == soundName; }
+ void startLoop1Fader(const FaderMoveSpec &);
+ void startLoop2Fader(const FaderMoveSpec &);
+
+ virtual void takeItemFromRoom(Item *);
+ virtual void dropItemIntoRoom(Item *, Hotspot *);
+ virtual Hotspot *getItemScreenSpot(Item *, DisplayElement *) { return 0; }
+
+ virtual GameInteraction *makeInteraction(const InteractionID);
+ virtual void requestDeleteCurrentInteraction() { _doneWithInteraction = true; }
+
+ virtual uint16 getDateResID() const = 0;
+
+ virtual void showExtraView(uint32);
+ virtual void startExtraLongSequence(const uint32, const uint32, NotificationFlags, const InputBits interruptionFilter);
+
+ void openCroppedMovie(const Common::String &, CoordType, CoordType);
+ void loopCroppedMovie(const Common::String &, CoordType, CoordType);
+ void closeCroppedMovie();
+ void playCroppedMovieOnce(const Common::String &, CoordType, CoordType, const InputBits interruptionFilter = kFilterNoInput);
+
+ void playMovieSegment(Movie *, TimeValue = 0, TimeValue = 0xffffffff);
+
+ virtual void recallToTSASuccess();
+ virtual void recallToTSAFailure();
+
+ virtual void pickedUpItem(Item *) {}
+
+ virtual void handleInput(const Input &, const Hotspot *);
+protected:
+ PegasusEngine *_vm;
+ Common::String _resName;
+
+ virtual Common::String getSoundSpotsName() = 0;
+ virtual Common::String getNavMovieName() = 0;
+
+ // Notification function.
+ virtual void receiveNotification(Notification *, const NotificationFlags);
+
+ // Map info functions.
+ virtual void getExitEntry(const RoomID room, const DirectionConstant direction, ExitTable::Entry &entry);
+ virtual TimeValue getViewTime(const RoomID room, const DirectionConstant direction);
+ virtual void getDoorEntry(const RoomID room, const DirectionConstant direction, DoorTable::Entry &doorEntry);
+ virtual DirectionConstant getTurnEntry(const RoomID room, const DirectionConstant direction, const TurnDirection turn);
+ virtual void getZoomEntry(const HotSpotID id, ZoomTable::Entry &zoomEntry);
+ virtual void getHotspotEntry(const HotSpotID id, HotspotInfoTable::Entry &hotspotEntry);
+
+ // Nav movie sequences.
+ virtual void startExitMovie(const ExitTable::Entry &);
+ virtual void keepStriding(ExitTable::Entry &);
+ virtual void stopStriding();
+ virtual void checkStriding();
+ virtual bool stillMoveForward();
+ virtual void scheduleStridingCallBack(const TimeValue, NotificationFlags flags);
+ virtual void startZoomMovie(const ZoomTable::Entry &);
+ virtual void startDoorOpenMovie(const TimeValue, const TimeValue);
+ virtual void startTurnPush(const TurnDirection, const TimeValue, const DirectionConstant);
+ virtual void playExtraMovie(const ExtraTable::Entry &, const NotificationFlags, const InputBits interruptionFilter);
+
+ virtual void activateCurrentView(const RoomID, const DirectionConstant, SpotFlags);
+
+ virtual void activateOneHotspot(HotspotInfoTable::Entry &, Hotspot *);
+
+ virtual void startSpotOnceOnly(TimeValue, TimeValue);
+
+ virtual void startMovieSequence(const TimeValue, const TimeValue, NotificationFlags,
+ bool loopSequence, const InputBits interruptionFilter, const TimeValue strideStop = 0xffffffff);
+
+ virtual void createNeighborhoodSpots();
+
+ void resetLastExtra() { _lastExtra = -1; }
+
+ virtual void throwAwayInterface();
+
+ // Action queue stuff
+ void popActionQueue();
+ void serviceActionQueue();
+ void requestAction(const QueueRequestType, const ExtraID, const TimeValue, const TimeValue, const InputBits, const NotificationFlags);
+
+ virtual bool prepareExtraSync(const ExtraID);
+ virtual bool waitMovieFinish(Movie *, const InputBits);
+
+ virtual InputBits getInputFilter();
+
+ // Misc.
+ virtual int16 getStaticCompassAngle(const RoomID, const DirectionConstant dir);
+ virtual void getExitCompassMove(const ExitTable::Entry &, FaderMoveSpec &);
+ virtual void getZoomCompassMove(const ZoomTable::Entry &, FaderMoveSpec&);
+ virtual void getExtraCompassMove(const ExtraTable::Entry &, FaderMoveSpec&);
+
+ virtual void setUpAIRules();
+ virtual void setHotspotFlags(const HotSpotID, const HotSpotFlags);
+ virtual void setIsItemTaken(const ItemID);
+
+ virtual void upButton(const Input &);
+ virtual void leftButton(const Input &);
+ virtual void rightButton(const Input &);
+ virtual void downButton(const Input &);
+
+ void initOnePicture(Picture *, const Common::String &, DisplayOrder, CoordType, CoordType, bool);
+ void initOneMovie(Movie *, const Common::String &, DisplayOrder, CoordType, CoordType, bool);
+
+ void reinstateMonocleInterface();
+
+ virtual void newInteraction(const InteractionID);
+ virtual void useIdleTime();
+ virtual void bumpIntoWall();
+ virtual void zoomUpOrBump();
+
+ void scheduleEvent(const TimeValue, const TimeScale, const uint32);
+ void cancelEvent();
+ virtual void timerExpired(const uint32) {}
+ bool isEventTimerRunning() { return _eventTimer.isFuseLit(); }
+ uint32 getTimerEvent() { return _timerEvent; }
+ void timerFunction();
+
+ void pauseTimer();
+ void resumeTimer();
+ bool timerPaused();
+
+ // Navigation Data
+ DoorTable _doorTable;
+ ExitTable _exitTable;
+ ExtraTable _extraTable;
+ HotspotInfoTable _hotspotInfoTable;
+ SpotTable _spotTable;
+ TurnTable _turnTable;
+ ViewTable _viewTable;
+ ZoomTable _zoomTable;
+ AlternateID _currentAlternate;
+ HotSpotActivationID _currentActivation;
+
+ int32 _lastExtra;
+ DeathReason _extraDeathReason;
+
+ // Graphics
+ Movie _navMovie;
+ Picture _pushIn;
+ Push _turnPush;
+
+ // Callbacks
+ Notification _neighborhoodNotification;
+ NotificationCallBack _navMovieCallBack;
+ StriderCallBack _stridingCallBack;
+ NotificationCallBack _turnPushCallBack;
+ NotificationCallBack _spotSoundCallBack;
+ NotificationCallBack _delayCallBack;
+
+ // Hotspots
+ HotspotList _neighborhoodHotspots;
+
+ // Sounds
+ SoundTimeBase _spotSounds;
+
+ // Action queue
+ NeighborhoodActionQueue _actionQueue;
+ TimeBase _delayTimer;
+
+ // Interruptibility...
+ InputBits _interruptionFilter;
+
+ // Nav hiding (for info support...)
+ bool _isRunning;
+
+ GameInteraction *_currentInteraction;
+ bool _doneWithInteraction;
+ Movie _croppedMovie;
+
+ Sound _soundLoop1;
+ Common::String _loop1SoundString;
+ SoundFader _loop1Fader;
+
+ Sound _soundLoop2;
+ Common::String _loop2SoundString;
+ SoundFader _loop2Fader;
+
+ // The event timer...
+ FuseFunction _eventTimer;
+ uint32 _timerEvent;
+};
+
+extern Neighborhood *g_neighborhood;
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/norad/alpha/ecrmonitor.cpp b/engines/pegasus/neighborhood/norad/alpha/ecrmonitor.cpp
new file mode 100644
index 0000000000..e2a0267231
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/alpha/ecrmonitor.cpp
@@ -0,0 +1,219 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/pegasus.h"
+#include "pegasus/neighborhood/norad/constants.h"
+#include "pegasus/neighborhood/norad/norad.h"
+#include "pegasus/neighborhood/norad/alpha/ecrmonitor.h"
+
+namespace Pegasus {
+
+static const NotificationFlags kECRSection1FinishedFlag = 1;
+static const NotificationFlags kECRPanFinishedFlag = kECRSection1FinishedFlag << 1;
+static const NotificationFlags kECRSection2FinishedFlag = kECRPanFinishedFlag << 1;
+static const NotificationFlags kECRNotificationFlags = kECRSection1FinishedFlag |
+ kECRPanFinishedFlag |
+ kECRSection2FinishedFlag;
+
+static const TimeValue kSection1Start = 0;
+static const TimeValue kSection1Stop = 25;
+static const TimeValue kPanStart = 0;
+static const TimeValue kPanStop = 20;
+static const TimeValue kSection2Start = 26;
+static const TimeValue kSection2Stop = 1000;
+
+// Seems to be a good value for a 20 second pan.
+static const CoordType kPanPixelsPerFrame = 8;
+
+// Interesting times are in seconds.
+static const TimeValue s_ECRInterestingTimes[] = {
+ 0, 1, 2, 10, 25, 26, 56, 64, 72, 80, 88, 94, 102, 108, 116, 999
+};
+
+// Index into s_ECRInterestingTimes of interesting time before security pan.
+static const int kBeforePanTime = 3;
+
+// Index into s_ECRInterestingTimes of interesting time after security pan.
+static const int kAfterPanTime = 5;
+
+NoradAlphaECRMonitor::NoradAlphaECRMonitor(Neighborhood *nextHandler) : GameInteraction(kNoradECRMonitorInteractionID, nextHandler),
+ _ecrSlideShowNotification(kNoradECRNotificationID, (PegasusEngine *)g_engine), _ecrMovie(kECRSlideShowMovieID),
+ _ecrPan(kECRPanID) {
+}
+
+void NoradAlphaECRMonitor::receiveNotification(Notification *, const NotificationFlags flags) {
+ if (flags & kECRSection1FinishedFlag)
+ ecrSection1Finished();
+ else if (flags & kECRPanFinishedFlag)
+ ecrPanFinished();
+ else if (flags & kECRSection2FinishedFlag)
+ ecrSection2Finished();
+}
+
+int NoradAlphaECRMonitor::findCurrentInterestingTime() {
+ TimeValue time = _ecrMovie.getTime();
+ TimeScale scale = _ecrMovie.getScale();
+
+ for (int i = ARRAYSIZE(s_ECRInterestingTimes) - 1; i >= 0; i--)
+ if (time >= s_ECRInterestingTimes[i] * scale)
+ return i;
+
+ return 0;
+}
+
+void NoradAlphaECRMonitor::skipToNextInterestingTime() {
+ if (_ecrMovie.isRunning()) {
+ int interestingTime = findCurrentInterestingTime();
+ _ecrMovie.setTime(s_ECRInterestingTimes[interestingTime + 1] * _ecrMovie.getScale());
+ _ecrMovie.redrawMovieWorld();
+ } else if (_ecrPan.isRunning()) {
+ _ecrPanCallBack.cancelCallBack();
+ ecrPanFinished();
+ }
+}
+
+void NoradAlphaECRMonitor::skipToPreviousInterestingTime() {
+ if (_ecrPan.isRunning()) {
+ _ecrPan.stop();
+ _ecrPan.stopDisplaying();
+ _ecrPanCallBack.cancelCallBack();
+
+ _ecrMovieCallBack.setCallBackFlag(kECRSection1FinishedFlag);
+ _ecrMovieCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+
+ TimeScale scale = _ecrMovie.getScale();
+ _ecrMovie.setSegment(kSection1Start * scale, kSection1Stop * scale + 1);
+ _ecrMovie.setTime(s_ECRInterestingTimes[kBeforePanTime] * scale);
+ _ecrMovie.start();
+ } else {
+ int interestingTime = findCurrentInterestingTime();
+
+ if (interestingTime == kAfterPanTime) {
+ _ecrMovieCallBack.cancelCallBack();
+ TimeScale scale = _ecrMovie.getScale();
+ _ecrMovie.setSegment(kSection1Start * scale, kSection1Stop * scale + 1);
+ _ecrMovie.setTime(kSection1Stop * scale);
+ ecrSection1Finished();
+ } else if (interestingTime == 0) {
+ _ecrMovie.setTime(kSection1Start * _ecrMovie.getScale());
+ _ecrMovie.redrawMovieWorld();
+ } else {
+ _ecrMovie.setTime(s_ECRInterestingTimes[interestingTime - 1] * _ecrMovie.getScale());
+ _ecrMovie.redrawMovieWorld();
+ }
+ }
+}
+
+void NoradAlphaECRMonitor::handleInput(const Input &input, const Hotspot *cursorSpot) {
+ if (isInteracting()) {
+ if (input.rightButtonDown())
+ skipToNextInterestingTime();
+ else if (input.leftButtonDown())
+ skipToPreviousInterestingTime();
+ else
+ InputHandler::handleInput(input, cursorSpot);
+ } else {
+ InputHandler::handleInput(input, cursorSpot);
+ }
+}
+
+void NoradAlphaECRMonitor::ecrSection1Finished() {
+ _ecrMovie.stop();
+ _ecrPanCallBack.setNotification(&_ecrSlideShowNotification);
+ _ecrPanCallBack.initCallBack(&_ecrPan, kCallBackAtExtremes);
+ _ecrPanCallBack.setCallBackFlag(kECRPanFinishedFlag);
+ _ecrSlideShowNotification.notifyMe(this, kECRNotificationFlags, kECRNotificationFlags);
+ _ecrPanCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ _ecrPan.startDisplaying();
+ _ecrPan.show();
+
+ TimeScale scale = _ecrPan.getScale();
+ _ecrPan.setSegment(kPanStart * scale, kPanStop * scale);
+ _ecrPan.setTime(0);
+ _ecrPan.start();
+}
+
+void NoradAlphaECRMonitor::ecrPanFinished() {
+ _ecrPan.stop();
+ _ecrPan.stopDisplaying();
+ _ecrMovieCallBack.setCallBackFlag(kECRSection2FinishedFlag);
+ _ecrMovieCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+
+ TimeScale scale = _ecrMovie.getScale();
+ _ecrMovie.setSegment(kSection2Start * scale, kSection2Stop * scale);
+ _ecrMovie.start();
+}
+
+void NoradAlphaECRMonitor::ecrSection2Finished() {
+ _ecrMovie.stop();
+ _ecrMovie.stopDisplaying();
+}
+
+void NoradAlphaECRMonitor::openInteraction() {
+ // Initialize the security pan.
+ _ecrPan.initFromMovieFile("Images/Norad Alpha/Security Pan.pano");
+ _ecrPan.initMaskFromPICTFile("Images/Norad Alpha/Security Pan Mask");
+ _ecrPan.setBounds(Common::Rect(kECRPanLeft, kECRPanTop, kECRPanRight, kECRPanBottom));
+ _ecrPan.setDisplayOrder(kECRPanOrder);
+ _ecrPan.setScale(15); // 15 fps.
+
+ // Begin the lame ECR slide show.
+ // clone2727: I didn't say it :P
+ _ecrMovie.initFromMovieFile("Images/Norad Alpha/ECR Monitor Movie");
+
+ _ecrMovieCallBack.setNotification(&_ecrSlideShowNotification);
+ _ecrMovieCallBack.initCallBack(&_ecrMovie, kCallBackAtExtremes);
+ _ecrMovieCallBack.setCallBackFlag(kECRSection1FinishedFlag);
+
+ _ecrSlideShowNotification.notifyMe(this, kECRNotificationFlags, kECRNotificationFlags);
+ _ecrMovieCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+
+ _ecrMovie.moveElementTo(kECRSlideShowLeft, kECRSlideShowTop);
+ _ecrMovie.setDisplayOrder(kECRMonitorOrder);
+ _ecrMovie.startDisplaying();
+ _ecrMovie.show();
+ _ecrMovie.redrawMovieWorld();
+
+ TimeScale scale = _ecrMovie.getScale();
+ _ecrMovie.setSegment(kSection1Start * scale, kSection1Stop * scale + 1);
+
+ _ecrMovie.start();
+}
+
+void NoradAlphaECRMonitor::closeInteraction() {
+ _ecrMovieCallBack.releaseCallBack();
+ _ecrMovie.stop();
+ _ecrMovie.stopDisplaying();
+ _ecrMovie.releaseMovie();
+ _ecrMovieCallBack.releaseCallBack();
+
+ _ecrPanCallBack.releaseCallBack();
+ _ecrPan.stop();
+ _ecrPan.stopDisplaying();
+ _ecrPan.releasePanorama();
+ _ecrPanCallBack.releaseCallBack();
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/norad/alpha/ecrmonitor.h b/engines/pegasus/neighborhood/norad/alpha/ecrmonitor.h
new file mode 100644
index 0000000000..9e286ed337
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/alpha/ecrmonitor.h
@@ -0,0 +1,65 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_ecrMONITOR_H
+#define PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_ecrMONITOR_H
+
+#include "pegasus/interaction.h"
+#include "pegasus/notification.h"
+#include "pegasus/neighborhood/norad/alpha/panoramascroll.h"
+
+namespace Pegasus {
+
+class NoradAlphaECRMonitor : public GameInteraction, public NotificationReceiver {
+public:
+ NoradAlphaECRMonitor(Neighborhood *);
+ virtual ~NoradAlphaECRMonitor() {}
+
+ virtual void handleInput(const Input &, const Hotspot *);
+
+protected:
+ virtual void openInteraction();
+ virtual void closeInteraction();
+
+ virtual void receiveNotification(Notification *, const NotificationFlags);
+
+ void ecrSection1Finished();
+ void ecrPanFinished();
+ void ecrSection2Finished();
+
+ int findCurrentInterestingTime();
+ void skipToNextInterestingTime();
+ void skipToPreviousInterestingTime();
+
+ Notification _ecrSlideShowNotification;
+ Movie _ecrMovie;
+ NotificationCallBack _ecrMovieCallBack;
+ PanoramaScroll _ecrPan;
+ NotificationCallBack _ecrPanCallBack;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp b/engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp
new file mode 100644
index 0000000000..169f75f7d2
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp
@@ -0,0 +1,445 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/gamestate.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/items/inventory/airmask.h"
+#include "pegasus/neighborhood/norad/constants.h"
+#include "pegasus/neighborhood/norad/alpha/fillingstation.h"
+#include "pegasus/neighborhood/norad/alpha/noradalpha.h"
+
+namespace Pegasus {
+
+static const NotificationFlags kFSPowerUpFinishedFlag = 1;
+static const NotificationFlags kFSSplashFinishedFlag = kFSPowerUpFinishedFlag << 1;
+static const NotificationFlags kFSIntakeWarningFinishedFlag = kFSSplashFinishedFlag << 1;
+static const NotificationFlags kFSIntakeHiliteFinishedFlag = kFSIntakeWarningFinishedFlag << 1;
+static const NotificationFlags kFSDispenseHiliteFinishedFlag = kFSIntakeHiliteFinishedFlag << 1;
+static const NotificationFlags kFSArHiliteFinishedFlag = kFSDispenseHiliteFinishedFlag << 1;
+static const NotificationFlags kFSCO2HiliteFinishedFlag = kFSArHiliteFinishedFlag << 1;
+static const NotificationFlags kFSHeHiliteFinishedFlag = kFSCO2HiliteFinishedFlag << 1;
+static const NotificationFlags kFSOHiliteFinishedFlag = kFSHeHiliteFinishedFlag << 1;
+static const NotificationFlags kFSNHiliteFinishedFlag = kFSOHiliteFinishedFlag << 1;
+
+static const NotificationFlags kFSNotificationFlags = kFSPowerUpFinishedFlag |
+ kFSSplashFinishedFlag |
+ kFSIntakeWarningFinishedFlag |
+ kFSIntakeHiliteFinishedFlag |
+ kFSDispenseHiliteFinishedFlag |
+ kFSArHiliteFinishedFlag |
+ kFSCO2HiliteFinishedFlag |
+ kFSHeHiliteFinishedFlag |
+ kFSOHiliteFinishedFlag |
+ kFSNHiliteFinishedFlag;
+
+static const int16 kNoState = 0;
+static const int16 kMainMenu = 1;
+static const int16 kWaitingForAttach = 2;
+static const int16 kDispenseMenu = 3;
+static const int16 kWaitingForDispense = 4;
+
+// Dummy itemIDs
+static const ItemID kCO2Item = 10000;
+static const ItemID kHeItem = 10001;
+
+// Interactive points.
+static const TimeValue kFSPowerUpStartStart = 0;
+static const TimeValue kFSPowerUpStartStop = 600;
+static const TimeValue kFSSplashStart = 600;
+static const TimeValue kFSSplashStop = 7800;
+static const TimeValue kFSSplashIntakeStart = 7800;
+static const TimeValue kFSSplashIntakeStop = 18600;
+
+static const TimeValue kFSMainMenu = 18600;
+static const TimeValue kFSIntakeHiliteStart = 19200;
+static const TimeValue kFSIntakeHiliteStop = 19800;
+static const TimeValue kFSDispenseHiliteStart = 19800;
+static const TimeValue kFSDispenseHiliteStop = 20400;
+
+static const TimeValue kFSDispenseMenu = 20400;
+
+static const TimeValue kFSArHiliteStart = 21000;
+static const TimeValue kFSArHiliteStop = 21600;
+static const TimeValue kFSArAttach = 21600;
+static const TimeValue kFSArFilledStart = 22200;
+static const TimeValue kFSArFilledStop = 25200;
+static const TimeValue kFSArIncompatibleStart = 25200;
+static const TimeValue kFSArIncompatibleStop = 30000;
+
+static const TimeValue kFSCO2HiliteStart = 30000;
+static const TimeValue kFSCO2HiliteStop = 30600;
+static const TimeValue kFSCO2Attach = 30600;
+static const TimeValue kFSCO2FilledStart = 31200;
+static const TimeValue kFSCO2FilledStop = 34200;
+static const TimeValue kFSCO2IncompatibleStart = 34200;
+static const TimeValue kFSCO2IncompatibleStop = 39000;
+
+static const TimeValue kFSHeHiliteStart = 39000;
+static const TimeValue kFSHeHiliteStop = 39600;
+static const TimeValue kFSHeAttach = 39600;
+static const TimeValue kFSHeFilledStart = 40200;
+static const TimeValue kFSHeFilledStop = 43200;
+static const TimeValue kFSHeIncompatibleStart = 43200;
+static const TimeValue kFSHeIncompatibleStop = 48000;
+
+static const TimeValue kFSOHiliteStart = 48000;
+static const TimeValue kFSOHiliteStop = 48600;
+static const TimeValue kFSOAttach = 48600;
+static const TimeValue kFSOFilledStart = 49200;
+static const TimeValue kFSOFilledStop = 52200;
+static const TimeValue kFSOIncompatibleStart = 52200;
+static const TimeValue kFSOIncompatibleStop = 57000;
+
+static const TimeValue kFSNHiliteStart = 57000;
+static const TimeValue kFSNHiliteStop = 57600;
+static const TimeValue kFSNAttach = 57600;
+static const TimeValue kFSNFilledStart = 58200;
+static const TimeValue kFSNFilledStop = 61200;
+static const TimeValue kFSNIncompatibleStart = 61200;
+static const TimeValue kFSNIncompatibleStop = 66000;
+
+static const TimeValue kFSIntakeMenu = 66000;
+static const TimeValue kFSIntakeInProgressStart = 66600;
+static const TimeValue kFSIntakeInProgressStop = 69600;
+
+NoradAlphaFillingStation::NoradAlphaFillingStation(Neighborhood *owner) : GameInteraction(kNoradFillingStationInteractionID, owner),
+ _rightSideMovie(kN01RightSideID), _rightSideNotification(kNoradFillingStationNotificationID, ((PegasusEngine *)g_engine)) {
+ _state = kNoState;
+}
+
+void NoradAlphaFillingStation::openInteraction() {
+ _rightSideMovie.initFromMovieFile("Images/Norad Alpha/N01W Right Side");
+ _rightSideMovie.moveElementTo(kNoradAlpha01RightSideLeft, kNoradAlpha01RightSideTop);
+ _rightSideMovie.setDisplayOrder(kN01RightSideOrder);
+ _rightSideMovie.startDisplaying();
+ _rightSideCallBack.setNotification(&_rightSideNotification);
+ _rightSideCallBack.initCallBack(&_rightSideMovie, kCallBackAtExtremes);
+ _rightSideCallBack.setCallBackFlag(kFSPowerUpFinishedFlag);
+ _rightSideNotification.notifyMe(this, kFSNotificationFlags, kFSNotificationFlags);
+ _rightSideCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ _rightSideMovie.show();
+ _rightSideMovie.redrawMovieWorld();
+ _rightSideMovie.setSegment(kFSPowerUpStartStart, kFSPowerUpStartStop);
+}
+
+void NoradAlphaFillingStation::initInteraction() {
+ allowInput(false);
+
+ _rightSideMovie.setRate(2);
+}
+
+void NoradAlphaFillingStation::closeInteraction() {
+ _rightSideMovie.stop();
+ _rightSideMovie.stopDisplaying();
+ _rightSideMovie.releaseMovie();
+ _rightSideCallBack.releaseCallBack();
+ ((NoradAlpha *)getOwner())->turnOffFillingStation();
+}
+
+void NoradAlphaFillingStation::setStaticState(TimeValue time, int16 state) {
+ _rightSideMovie.stop();
+ _rightSideMovie.setSegment(0, _rightSideMovie.getDuration());
+ _rightSideMovie.setTime(time);
+ _rightSideMovie.redrawMovieWorld();
+ _state = state;
+ allowInput(true);
+}
+
+void NoradAlphaFillingStation::setSegmentState(TimeValue start, TimeValue stop, NotificationFlags flag, int16 state) {
+ _rightSideMovie.stop();
+ _rightSideMovie.setSegment(start, stop);
+ _rightSideMovie.setTime(start);
+ _rightSideCallBack.setCallBackFlag(flag);
+ _rightSideCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ _state = state;
+ allowInput(false);
+ _rightSideMovie.setRate(2);
+}
+
+void NoradAlphaFillingStation::powerUpFinished() {
+ ((NoradAlpha *)getOwner())->turnOnFillingStation();
+ setSegmentState(kFSSplashStart, kFSSplashStop, kFSSplashFinishedFlag, kNoState);
+}
+
+void NoradAlphaFillingStation::splashFinished() {
+ if (GameState.getNoradGassed())
+ setSegmentState(kFSSplashIntakeStart, kFSSplashIntakeStop, kFSIntakeWarningFinishedFlag, kNoState);
+ else
+ intakeWarningFinished();
+}
+
+void NoradAlphaFillingStation::intakeWarningFinished() {
+ setStaticState(kFSMainMenu, kMainMenu);
+}
+
+void NoradAlphaFillingStation::showIntakeInProgress(uint16 numSeconds) {
+ if (numSeconds == 0) {
+ setSegmentState(kFSIntakeInProgressStart, kFSIntakeInProgressStop, kFSIntakeWarningFinishedFlag, kNoState);
+ Item *item = ((NoradAlpha *)getOwner())->getFillingItem();
+
+ if (item->getObjectID() == kGasCanister) {
+ GameState.setNoradGassed(true);
+ ((NoradAlpha *)getOwner())->loadAmbientLoops();
+ getOwner()->restoreStriding(kNorad03, kEast, kAltNoradAlphaNormal);
+ }
+ } else {
+ setSegmentState(kFSIntakeInProgressStart, kFSIntakeInProgressStart + _rightSideMovie.getScale() * numSeconds,
+ kFSIntakeWarningFinishedFlag, kNoState);
+ }
+}
+
+void NoradAlphaFillingStation::intakeHighlightFinished() {
+ _rightSideMovie.stop();
+
+ if (GameState.getNoradGassed()) {
+ showIntakeInProgress(2);
+ } else {
+ Item *item = ((NoradAlpha *)getOwner())->getFillingItem();
+ if (item)
+ showIntakeInProgress(0);
+ else
+ setStaticState(kFSIntakeMenu, kWaitingForAttach);
+ }
+}
+
+void NoradAlphaFillingStation::dispenseHighlightFinished() {
+ setStaticState(kFSDispenseMenu, kDispenseMenu);
+}
+
+void NoradAlphaFillingStation::dispenseGas() {
+ Item *item = ((NoradAlpha *)getOwner())->getFillingItem();
+
+ if (item) {
+ if (item->getObjectID() != _dispenseItemID)
+ switch (_dispenseItemID) {
+ case kArgonCanister:
+ setSegmentState(kFSArIncompatibleStart, kFSArIncompatibleStop,
+ kFSIntakeWarningFinishedFlag, kNoState);
+ break;
+ case kCO2Item:
+ setSegmentState(kFSCO2IncompatibleStart, kFSCO2IncompatibleStop,
+ kFSIntakeWarningFinishedFlag, kNoState);
+ break;
+ case kHeItem:
+ setSegmentState(kFSHeIncompatibleStart, kFSHeIncompatibleStop,
+ kFSIntakeWarningFinishedFlag, kNoState);
+ break;
+ case kAirMask:
+ setSegmentState(kFSOIncompatibleStart, kFSOIncompatibleStop,
+ kFSIntakeWarningFinishedFlag, kNoState);
+ break;
+ case kNitrogenCanister:
+ setSegmentState(kFSNIncompatibleStart, kFSNIncompatibleStop,
+ kFSIntakeWarningFinishedFlag, kNoState);
+ break;
+ }
+ else {
+ if (_dispenseItemID == kArgonCanister) {
+ setSegmentState(kFSArFilledStart, kFSArFilledStop, kFSIntakeWarningFinishedFlag, kNoState);
+ item->setItemState(kArgonFull);
+ GameState.setScoringFilledArgonCanister(true);
+ } else if (_dispenseItemID == kAirMask) {
+ setSegmentState(kFSOFilledStart, kFSOFilledStop, kFSIntakeWarningFinishedFlag, kNoState);
+ ((AirMask *)item)->refillAirMask();
+ GameState.setScoringFilledOxygenCanister(true);
+ } else if (_dispenseItemID == kNitrogenCanister) {
+ setSegmentState(kFSNFilledStart, kFSNFilledStop, kFSIntakeWarningFinishedFlag, kNoState);
+ item->setItemState(kNitrogenFull);
+ }
+ }
+ } else {
+ switch (_dispenseItemID) {
+ case kArgonCanister:
+ setStaticState(kFSArAttach, kWaitingForDispense);
+ break;
+ case kCO2Item:
+ setStaticState(kFSCO2Attach, kWaitingForDispense);
+ break;
+ case kHeItem:
+ setStaticState(kFSHeAttach, kWaitingForDispense);
+ break;
+ case kAirMask:
+ setStaticState(kFSOAttach, kWaitingForDispense);
+ break;
+ case kNitrogenCanister:
+ setStaticState(kFSNAttach, kWaitingForDispense);
+ break;
+ }
+ }
+}
+
+void NoradAlphaFillingStation::ArHighlightFinished() {
+ _dispenseItemID = kArgonCanister;
+ dispenseGas();
+}
+
+void NoradAlphaFillingStation::CO2HighlightFinished() {
+ _dispenseItemID = kCO2Item;
+ dispenseGas();
+}
+
+void NoradAlphaFillingStation::HeHighlightFinished() {
+ _dispenseItemID = kHeItem;
+ dispenseGas();
+}
+
+void NoradAlphaFillingStation::OHighlightFinished() {
+ _dispenseItemID = kAirMask;
+ dispenseGas();
+}
+
+void NoradAlphaFillingStation::NHighlightFinished() {
+ _dispenseItemID = kNitrogenCanister;
+ dispenseGas();
+}
+
+void NoradAlphaFillingStation::receiveNotification(Notification *, const NotificationFlags flags) {
+ switch (flags) {
+ case kFSPowerUpFinishedFlag:
+ powerUpFinished();
+ break;
+ case kFSSplashFinishedFlag:
+ splashFinished();
+ break;
+ case kFSIntakeWarningFinishedFlag:
+ intakeWarningFinished();
+ break;
+ case kFSIntakeHiliteFinishedFlag:
+ intakeHighlightFinished();
+ break;
+ case kFSDispenseHiliteFinishedFlag:
+ dispenseHighlightFinished();
+ break;
+ case kFSArHiliteFinishedFlag:
+ ArHighlightFinished();
+ break;
+ case kFSCO2HiliteFinishedFlag:
+ CO2HighlightFinished();
+ break;
+ case kFSHeHiliteFinishedFlag:
+ HeHighlightFinished();
+ break;
+ case kFSOHiliteFinishedFlag:
+ OHighlightFinished();
+ break;
+ case kFSNHiliteFinishedFlag:
+ NHighlightFinished();
+ break;
+ }
+}
+
+void NoradAlphaFillingStation::handleInput(const Input &input, const Hotspot *cursorSpot) {
+ InputHandler::handleInput(input, cursorSpot);
+}
+
+void NoradAlphaFillingStation::clickInIntake() {
+ setSegmentState(kFSIntakeHiliteStart, kFSIntakeHiliteStop, kFSIntakeHiliteFinishedFlag, kNoState);
+}
+
+void NoradAlphaFillingStation::clickInDispense() {
+ setSegmentState(kFSDispenseHiliteStart, kFSDispenseHiliteStop, kFSDispenseHiliteFinishedFlag, kNoState);
+}
+
+void NoradAlphaFillingStation::clickInAr() {
+ setSegmentState(kFSArHiliteStart, kFSArHiliteStop, kFSArHiliteFinishedFlag, kNoState);
+}
+
+void NoradAlphaFillingStation::clickInCO2() {
+ setSegmentState(kFSCO2HiliteStart, kFSCO2HiliteStop, kFSCO2HiliteFinishedFlag, kNoState);
+}
+
+void NoradAlphaFillingStation::clickInHe() {
+ setSegmentState(kFSHeHiliteStart, kFSHeHiliteStop, kFSHeHiliteFinishedFlag, kNoState);
+}
+
+void NoradAlphaFillingStation::clickInO() {
+ setSegmentState(kFSOHiliteStart, kFSOHiliteStop, kFSOHiliteFinishedFlag, kNoState);
+}
+
+void NoradAlphaFillingStation::clickInN() {
+ setSegmentState(kFSNHiliteStart, kFSNHiliteStop, kFSNHiliteFinishedFlag, kNoState);
+}
+
+void NoradAlphaFillingStation::clickInHotspot(const Input &input, const Hotspot *spot) {
+ GameInteraction::clickInHotspot(input, spot);
+
+ switch (spot->getObjectID()) {
+ case kNorad01IntakeSpotID:
+ clickInIntake();
+ break;
+ case kNorad01DispenseSpotID:
+ clickInDispense();
+ break;
+ case kNorad01ArSpotID:
+ clickInAr();
+ break;
+ case kNorad01CO2SpotID:
+ clickInCO2();
+ break;
+ case kNorad01HeSpotID:
+ clickInHe();
+ break;
+ case kNorad01OSpotID:
+ clickInO();
+ break;
+ case kNorad01NSpotID:
+ clickInN();
+ break;
+ }
+}
+
+void NoradAlphaFillingStation::activateHotspots() {
+ GameInteraction::activateHotspots();
+
+ switch (_state) {
+ case kMainMenu:
+ g_allHotspots.activateOneHotspot(kNorad01IntakeSpotID);
+ g_allHotspots.activateOneHotspot(kNorad01DispenseSpotID);
+ break;
+ case kDispenseMenu:
+ g_allHotspots.activateOneHotspot(kNorad01ArSpotID);
+ g_allHotspots.activateOneHotspot(kNorad01CO2SpotID);
+ g_allHotspots.activateOneHotspot(kNorad01HeSpotID);
+ g_allHotspots.activateOneHotspot(kNorad01OSpotID);
+ g_allHotspots.activateOneHotspot(kNorad01NSpotID);
+ break;
+ }
+}
+
+void NoradAlphaFillingStation::newFillingItem(Item *item) {
+ switch (_state) {
+ case kWaitingForAttach:
+ if (item)
+ showIntakeInProgress(0);
+ break;
+ case kWaitingForDispense:
+ dispenseGas();
+ break;
+ default:
+ break;
+ }
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/norad/alpha/fillingstation.h b/engines/pegasus/neighborhood/norad/alpha/fillingstation.h
new file mode 100644
index 0000000000..eb2088e373
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/alpha/fillingstation.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.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_FILLINGSTATION_H
+#define PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_FILLINGSTATION_H
+
+#include "pegasus/interaction.h"
+#include "pegasus/movie.h"
+#include "pegasus/notification.h"
+
+namespace Pegasus {
+
+class Item;
+
+class NoradAlphaFillingStation : public GameInteraction, public NotificationReceiver {
+public:
+ NoradAlphaFillingStation(Neighborhood *);
+ virtual ~NoradAlphaFillingStation() {}
+
+ virtual void handleInput(const Input &, const Hotspot *);
+
+ virtual void clickInHotspot(const Input &, const Hotspot *);
+ virtual void activateHotspots();
+
+ void newFillingItem(Item *);
+
+protected:
+ void receiveNotification(Notification *, const NotificationFlags);
+
+ virtual void openInteraction();
+ virtual void initInteraction();
+ virtual void closeInteraction();
+
+ void powerUpFinished();
+ void splashFinished();
+ void intakeWarningFinished();
+ void intakeHighlightFinished();
+ void dispenseHighlightFinished();
+ void ArHighlightFinished();
+ void CO2HighlightFinished();
+ void HeHighlightFinished();
+ void OHighlightFinished();
+ void NHighlightFinished();
+
+ void showIntakeInProgress(uint16);
+
+ void clickInIntake();
+ void clickInDispense();
+ void clickInAr();
+ void clickInCO2();
+ void clickInHe();
+ void clickInO();
+ void clickInN();
+
+ void dispenseGas();
+
+ void setStaticState(TimeValue, int16);
+ void setSegmentState(TimeValue, TimeValue, NotificationFlags, int16);
+
+ Movie _rightSideMovie;
+ Notification _rightSideNotification;
+ NotificationCallBack _rightSideCallBack;
+ int16 _state;
+ ItemID _dispenseItemID;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/norad/alpha/noradalpha.cpp b/engines/pegasus/neighborhood/norad/alpha/noradalpha.cpp
new file mode 100644
index 0000000000..e4a5e26473
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/alpha/noradalpha.cpp
@@ -0,0 +1,763 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/energymonitor.h"
+#include "pegasus/gamestate.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/inventory/airmask.h"
+#include "pegasus/neighborhood/norad/constants.h"
+#include "pegasus/neighborhood/norad/subcontrolroom.h"
+#include "pegasus/neighborhood/norad/alpha/ecrmonitor.h"
+#include "pegasus/neighborhood/norad/alpha/fillingstation.h"
+#include "pegasus/neighborhood/norad/alpha/noradalpha.h"
+
+namespace Pegasus {
+
+const uint32 NoradAlpha::_noradAlphaClawExtras[22] = {
+ kN22ClawFromAToB,
+ kN22ClawALoop,
+ kN22ClawAPinch,
+ kN22ClawACounterclockwise,
+ kN22ClawAClockwise,
+ kN22ClawFromBToA,
+ kN22ClawFromBToC,
+ kN22ClawFromBToD,
+ kN22ClawBLoop,
+ kN22ClawBPinch,
+ kN22ClawBCounterclockwise,
+ kN22ClawBClockwise,
+ kN22ClawFromCToB,
+ kN22ClawCLoop,
+ kN22ClawCPinch,
+ kN22ClawCCounterclockwise,
+ kN22ClawCClockwise,
+ kN22ClawFromDToB,
+ kN22ClawDLoop,
+ kN22ClawDPinch,
+ kN22ClawDCounterclockwise,
+ kN22ClawDClockwise
+};
+
+NoradAlpha::NoradAlpha(InputHandler *nextHandler, PegasusEngine *owner) : Norad(nextHandler, owner, "Norad Alpha", kNoradAlphaID) {
+ _elevatorUpRoomID = kNorad11South;
+ _elevatorDownRoomID = kNorad12South;
+ _elevatorUpSpotID = kNorad12ElevatorUpSpotID;
+ _elevatorDownSpotID = kNorad11ElevatorDownSpotID;
+
+ _subRoomEntryRoom1 = kNorad10;
+ _subRoomEntryDir1 = kEast;
+ _subRoomEntryRoom2 = kNorad21;
+ _subRoomEntryDir2 = kWest;
+ _upperPressureDoorRoom = kNorad10East;
+ _lowerPressureDoorRoom = kNorad21West;
+
+ _upperPressureDoorUpSpotID = kAlphaUpperPressureDoorUpSpotID;
+ _upperPressureDoorDownSpotID = kAlphaUpperPressureDoorDownSpotID;
+ _upperPressureDoorAbortSpotID = kNorad10EastOutSpotID;
+
+ _lowerPressureDoorUpSpotID = kAlphaLowerPressureDoorUpSpotID;
+ _lowerPressureDoorDownSpotID = kAlphaLowerPressureDoorDownSpotID;
+ _lowerPressureDoorAbortSpotID = kNorad21WestOutSpotID;
+
+ _pressureSoundIn = kPressureDoorIntro1In;
+ _pressureSoundOut = kPressureDoorIntro1Out;
+ _equalizeSoundIn = kPressureDoorIntro2In;
+ _equalizeSoundOut = kPressureDoorIntro2Out;
+ _accessDeniedIn = kAlphaAccessDeniedIn;
+ _accessDeniedOut = kAlphaAccessDeniedOut;
+
+ _platformRoom = kNorad19West;
+ _subControlRoom = kNorad22West;
+
+ _subPrepFailed = false;
+
+ setIsItemTaken(kGasCanister);
+}
+
+void NoradAlpha::init() {
+ Norad::init();
+
+ Hotspot *hotspot = _vm->getAllHotspots().findHotspotByID(kN01GasCanisterSpotID);
+ hotspot->setMaskedHotspotFlags(kPickUpItemSpotFlag, kPickUpItemSpotFlag);
+ HotspotInfoTable::Entry *hotspotEntry = findHotspotEntry(kN01GasCanisterSpotID);
+ hotspotEntry->hotspotItem = kGasCanister;
+
+ hotspot = _vm->getAllHotspots().findHotspotByID(kN01ArgonCanisterSpotID);
+ hotspot->setMaskedHotspotFlags(kPickUpItemSpotFlag, kPickUpItemSpotFlag);
+ hotspotEntry = findHotspotEntry(kN01ArgonCanisterSpotID);
+ hotspotEntry->hotspotItem = kArgonCanister;
+
+ hotspot = _vm->getAllHotspots().findHotspotByID(kN01NitrogenCanisterSpotID);
+ hotspot->setMaskedHotspotFlags(kPickUpItemSpotFlag, kPickUpItemSpotFlag);
+ hotspotEntry = findHotspotEntry(kN01NitrogenCanisterSpotID);
+ hotspotEntry->hotspotItem = kNitrogenCanister;
+
+ hotspot = _vm->getAllHotspots().findHotspotByID(kN01AirMaskSpotID);
+ hotspot->setMaskedHotspotFlags(kPickUpItemSpotFlag, kPickUpItemSpotFlag);
+ hotspotEntry = findHotspotEntry(kN01AirMaskSpotID);
+ hotspotEntry->hotspotItem = kAirMask;
+
+ hotspot = _vm->getAllHotspots().findHotspotByID(kN01GasOutletSpotID);
+ hotspot->setMaskedHotspotFlags(kDropItemSpotFlag, kDropItemSpotFlag);
+}
+
+void NoradAlpha::start() {
+ if (g_energyMonitor) {
+ g_energyMonitor->stopEnergyDraining();
+ g_energyMonitor->restoreLastEnergyValue();
+ _vm->resetEnergyDeathReason();
+ g_energyMonitor->startEnergyDraining();
+ }
+
+ NeighborhoodID itemNeighborhood;
+ RoomID itemRoom;
+ DirectionConstant itemDirection;
+
+ Item *item = (Item *)_vm->getAllItems().findItemByID(kGasCanister);
+ item->getItemRoom(itemNeighborhood, itemRoom, itemDirection);
+
+ if (itemNeighborhood == getObjectID()) {
+ _fillingStationItem = item;
+ } else {
+ item = (Item *)_vm->getAllItems().findItemByID(kAirMask);
+ item->getItemRoom(itemNeighborhood, itemRoom, itemDirection);
+
+ if (itemNeighborhood == getObjectID()) {
+ _fillingStationItem = item;
+ } else {
+ item = (Item *)_vm->getAllItems().findItemByID(kNitrogenCanister);
+ item->getItemRoom(itemNeighborhood, itemRoom, itemDirection);
+
+ if (itemNeighborhood == getObjectID()) {
+ _fillingStationItem = item;
+ } else {
+ item = (Item *)_vm->getAllItems().findItemByID(kArgonCanister);
+ item->getItemRoom(itemNeighborhood, itemRoom, itemDirection);
+ if (itemNeighborhood == getObjectID())
+ _fillingStationItem = item;
+ else
+ _fillingStationItem = 0;
+ }
+ }
+ }
+
+ if (!GameState.getNoradGassed())
+ forceStridingStop(kNorad03, kEast, kAltNoradAlphaNormal);
+
+ GameState.setNoradArrivedFromSub(false);
+ Norad::start();
+}
+
+void NoradAlpha::setUpAIRules() {
+ Neighborhood::setUpAIRules();
+
+ if (g_AIArea) {
+ AIPlayMessageAction *messageAction = new AIPlayMessageAction("Images/AI/Norad/XN01WD1", false);
+ AIHasItemCondition *hasGasCanisterCondition = new AIHasItemCondition(kGasCanister);
+ AIRule *rule = new AIRule(hasGasCanisterCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+ }
+}
+
+bool NoradAlpha::okayToJump() {
+ bool result = Neighborhood::okayToJump();
+
+ if (!result)
+ playSpotSoundSync(kAlphaCantTransportIn, kAlphaCantTransportOut);
+
+ return result;
+}
+
+void NoradAlpha::getExtraCompassMove(const ExtraTable::Entry &entry, FaderMoveSpec &compassMove) {
+ if (entry.extra == kNorad19ExitToSub) {
+ compassMove.makeTwoKnotFaderSpec(kNoradAlphaMovieScale, entry.movieStart, 270 + kSubPlatformCompassAngle,
+ entry.movieEnd, 90 + 20 + 360);
+ compassMove.insertFaderKnot(entry.movieStart + 10 * kNoradAlphaFrameDuration, 270 + kSubPlatformCompassAngle);
+ compassMove.insertFaderKnot(entry.movieStart + 29 * kNoradAlphaFrameDuration, 270 + kSubPlatformCompassAngle + 20);
+ compassMove.insertFaderKnot(entry.movieStart + 52 * kNoradAlphaFrameDuration, 270 + kSubPlatformCompassAngle + 20);
+ compassMove.insertFaderKnot(entry.movieStart + 84 * kNoradAlphaFrameDuration, 360 + 90);
+ compassMove.insertFaderKnot(entry.movieStart + 198 * kNoradAlphaFrameDuration, 360 + 90);
+ compassMove.insertFaderKnot(entry.movieStart + 270 * kNoradAlphaFrameDuration, 360 + 90 + 15);
+ compassMove.insertFaderKnot(entry.movieStart + 280 * kNoradAlphaFrameDuration, 360 + 90 + 20);
+ } else {
+ Norad::getExtraCompassMove(entry, compassMove);
+ }
+}
+
+void NoradAlpha::playClawMonitorIntro() {
+ playSpotSoundSync(kLoadClawIntroIn, kLoadClawIntroOut);
+}
+
+GameInteraction *NoradAlpha::makeInteraction(const InteractionID interactionID) {
+ switch (interactionID) {
+ case kNoradECRMonitorInteractionID:
+ return new NoradAlphaECRMonitor(this);
+ case kNoradFillingStationInteractionID:
+ return new NoradAlphaFillingStation(this);
+ }
+
+ return Norad::makeInteraction(interactionID);
+}
+
+void NoradAlpha::loadAmbientLoops() {
+ // clone2727 would like to point out that the following comment does not quite
+ // match the code logic below
+
+/*
+ Logic:
+
+ loop sound 1:
+ if gassed,
+ play warning loop of some sort
+ else
+ play nothing
+ loop sound 2:
+ if gassed and not wearing air mask
+ if in ECR
+ play breathing water loop
+ else
+ play breathing
+ else
+ if in ECR
+ play water loop
+ if at N07 north
+ play unmanned loop
+*/
+
+ if (!GameState.getNoradSeenTimeStream())
+ return;
+
+ RoomID room = GameState.getCurrentRoom();
+ if (GameState.getNoradGassed()) {
+ if (room >= kNorad11 && room <= kNorad19West)
+ loadLoopSound1("Sounds/Norad/NEW SUB AMB.22K.AIFF", kNoradWarningVolume * 3);
+ else if (room >= kNorad21 && room <= kNorad22West)
+ loadLoopSound1("Sounds/Norad/SUB CONTRL LOOP.22K.AIFF", kNoradWarningVolume * 3);
+ else
+ loadLoopSound1("Sounds/Norad/WARNING LOOP.22K.AIFF", kNoradWarningVolume);
+ } else {
+ loadLoopSound1("");
+ }
+
+ if (GameState.getNoradGassed() && !g_airMask->isAirFilterOn()) {
+ if (room >= kNorad01 && room <= kNorad01West) {
+ loadLoopSound2("Sounds/Norad/Breathing Water.22K.AIFF", kNoradSuckWindVolume);
+ } else if (room == kNorad02) {
+ if (GameState.isCurrentDoorOpen())
+ loadLoopSound2("Sounds/Norad/Breathing Water.22K.AIFF", kNoradSuckWindVolume);
+ else
+ loadLoopSound2("Sounds/Norad/SUCKING WIND.22K.AIFF", kNoradSuckWindVolume, 0, 0);
+ } else {
+ loadLoopSound2("Sounds/Norad/SUCKING WIND.22K.AIFF", kNoradSuckWindVolume, 0, 0);
+ }
+ } else {
+ if (room >= kNorad01 && room <= kNorad01West) {
+ loadLoopSound2("Sounds/Norad/WATER FLOWING.AIFF", 0x100 / 2);
+ } else if (room == kNorad02) {
+ if (GameState.isCurrentDoorOpen())
+ loadLoopSound2("Sounds/Norad/WATER FLOWING.AIFF", 0x100 / 2);
+ else
+ loadLoopSound2("");
+ } else {
+ loadLoopSound2("");
+ }
+ }
+
+}
+
+void NoradAlpha::checkContinuePoint(const RoomID room, const DirectionConstant direction) {
+ switch (MakeRoomView(room, direction)) {
+ case MakeRoomView(kNorad02, kEast):
+ case MakeRoomView(kNorad06, kEast):
+ case MakeRoomView(kNorad11, kEast):
+ case MakeRoomView(kNorad15, kEast):
+ case MakeRoomView(kNorad19, kWest):
+ case MakeRoomView(kNorad21, kSouth):
+ makeContinuePoint();
+ break;
+ }
+}
+
+void NoradAlpha::arriveAt(const RoomID room, const DirectionConstant direction) {
+ Norad::arriveAt(room, direction);
+
+ switch (GameState.getCurrentRoom()) {
+ case kNorad01:
+ arriveAtNorad01();
+ break;
+ case kNorad01East:
+ arriveAtNorad01East();
+ break;
+ case kNorad01West:
+ arriveAtNorad01West();
+ break;
+ case kNorad04:
+ arriveAtNorad04();
+ break;
+ case kNorad07North:
+ GameState.setScoringSawUnconsciousOperator(true);
+ break;
+ case kNorad11:
+ GameState.setScoringWentThroughPressureDoor(true);
+ break;
+ case kNorad22:
+ arriveAtNorad22();
+ break;
+ }
+}
+
+void NoradAlpha::arriveAtNorad01() {
+ if (!GameState.getNoradSeenTimeStream() && GameState.getCurrentDirection() == kSouth) {
+ GameState.setNoradN22MessagePlayed(false);
+ requestExtraSequence(kNoradArriveFromTSA, kExtraCompletedFlag, kFilterNoInput);
+ // You are no match for me, human.
+ requestExtraSequence(kNorad01RobotTaunt, kExtraCompletedFlag, kFilterNoInput);
+ }
+}
+
+void NoradAlpha::arriveAtNorad01East() {
+ GameState.setScoringSawSecurityMonitor(true);
+ newInteraction(kNoradECRMonitorInteractionID);
+}
+
+void NoradAlpha::arriveAtNorad01West() {
+ newInteraction(kNoradFillingStationInteractionID);
+}
+
+void NoradAlpha::arriveAtNorad04() {
+ if (GameState.getCurrentDirection() == kEast && !GameState.getNoradGassed())
+ playDeathExtra(kNorad04EastDeath, kDeathWokeUpNorad);
+}
+
+void NoradAlpha::arriveAtNorad22() {
+ if (!GameState.getNoradN22MessagePlayed() && GameState.getCurrentDirection() == kSouth) {
+ startExtraSequence(kNorad22SouthIntro, kExtraCompletedFlag, kFilterNoInput);
+ GameState.setNoradN22MessagePlayed(true);
+ }
+}
+
+void NoradAlpha::bumpIntoWall() {
+ requestSpotSound(kAlphaBumpIntoWallIn, kAlphaBumpIntoWallOut, kFilterNoInput, 0);
+ Neighborhood::bumpIntoWall();
+}
+
+void NoradAlpha::receiveNotification(Notification *notification, const NotificationFlags flags) {
+ if ((flags & kExtraCompletedFlag) != 0) {
+ switch (_lastExtra) {
+ case kNoradArriveFromTSA:
+ GameState.setNoradSeenTimeStream(true);
+ loadAmbientLoops();
+ break;
+ case kNorad01RobotTaunt:
+ g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Norad/XN01SB", false, kWarningInterruption);
+ _interruptionFilter = kFilterAllInput;
+ makeContinuePoint();
+ break;
+ }
+ }
+
+ Norad::receiveNotification(notification, flags);
+
+ if ((flags & kExtraCompletedFlag) != 0) {
+ switch (_lastExtra) {
+ case kNorad22SouthIntro:
+ loopExtraSequence(kNorad22SouthReply);
+ playSpotSoundSync(kN22ReplyIn, kN22ReplyOut);
+ startExtraSequence(kNorad22SouthFinish, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kNorad22SouthFinish:
+ _interruptionFilter = kFilterAllInput;
+ // Force ArriveAt to do its thing...
+ GameState.setCurrentRoom(kNorad21);
+ arriveAt(kNorad22, kSouth);
+ break;
+ }
+ }
+
+ g_AIArea->checkMiddleArea();
+}
+
+void NoradAlpha::getZoomEntry(const HotSpotID spotID, ZoomTable::Entry &entry) {
+ Norad::getZoomEntry(spotID, entry);
+
+ ExtraTable::Entry extra;
+
+ if (spotID == kNorad01GasSpotID) {
+ if (_fillingStationItem) {
+ if (_fillingStationItem->getObjectID() == kGasCanister) {
+ getExtraEntry(kNorad01ZoomInWithGasCanister, extra);
+ entry.movieStart = extra.movieStart;
+ entry.movieEnd = extra.movieEnd;
+ } else {
+ entry.clear();
+ }
+ }
+ } else if (spotID == kNorad01GasOutSpotID) {
+ if (_fillingStationItem) {
+ if (_fillingStationItem->getObjectID() == kGasCanister) {
+ getExtraEntry(kNorad01ZoomOutWithGasCanister, extra);
+ entry.movieStart = extra.movieStart;
+ entry.movieEnd = extra.movieEnd;
+ } else {
+ entry.clear();
+ }
+ }
+ }
+}
+
+TimeValue NoradAlpha::getViewTime(const RoomID room, const DirectionConstant direction) {
+ ExtraTable::Entry entry;
+
+ if (room == kNorad01 && direction == kSouth && !GameState.getNoradSeenTimeStream()) {
+ getExtraEntry(kNoradArriveFromTSA, entry);
+ return entry.movieStart;
+ }
+
+ if (room == kNorad01 && direction == kWest) {
+ if (!_fillingStationItem) {
+ return Norad::getViewTime(room, direction);
+ } else {
+ getExtraEntry(kN01WGasCanister, entry);
+ return entry.movieStart;
+ }
+ } else if (room == kNorad01West && direction == kWest) {
+ uint32 extraID = 0xffffffff;
+ if (_fillingStationItem) {
+ switch (_fillingStationItem->getObjectID()) {
+ case kArgonCanister:
+ if (GameState.getNoradFillingStationOn())
+ extraID = kN01WZArgonCanisterLit;
+ else
+ extraID = kN01WZArgonCanisterDim;
+ break;
+ case kGasCanister:
+ if (GameState.getNoradFillingStationOn())
+ extraID = kN01WZGasCanisterLit;
+ else
+ extraID = kN01WZGasCanisterDim;
+ break;
+ case kAirMask:
+ if (GameState.getNoradFillingStationOn())
+ extraID = kN01WZAirMaskLit;
+ else
+ extraID = kN01WZAirMaskDim;
+ break;
+ case kNitrogenCanister:
+ if (GameState.getNoradFillingStationOn())
+ extraID = kN01WZNitrogenCanisterLit;
+ else
+ extraID = kN01WZNitrogenCanisterDim;
+ break;
+ default:
+ // Should never happen.
+ break;
+ }
+ } else if (GameState.getNoradFillingStationOn()) {
+ extraID = kN01WZEmptyLit;
+ }
+
+ if (extraID == 0xffffffff) {
+ return Norad::getViewTime(room, direction);
+ } else {
+ getExtraEntry(extraID, entry);
+ return entry.movieStart;
+ }
+ }
+
+ return Norad::getViewTime(room, direction);
+}
+
+void NoradAlpha::turnOnFillingStation() {
+ if (GameState.getCurrentRoom() == kNorad01West && !GameState.getNoradFillingStationOn()) {
+ GameState.setNoradFillingStationOn(true);
+ updateViewFrame();
+ }
+}
+
+void NoradAlpha::turnOffFillingStation() {
+ if (GameState.getCurrentRoom() == kNorad01West && GameState.getNoradFillingStationOn()) {
+ GameState.setNoradFillingStationOn(false);
+ updateViewFrame();
+ }
+}
+
+void NoradAlpha::activateHotspots() {
+ Norad::activateHotspots();
+
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kNorad01West, kWest):
+ if (_vm->getDragType() == kDragInventoryUse) {
+ if (!_fillingStationItem) {
+ ItemID itemID = _vm->getDraggingItem()->getObjectID();
+ if (itemID == kArgonCanister || itemID == kGasCanister || itemID == kAirMask ||
+ itemID == kNitrogenCanister)
+ _vm->getAllHotspots().activateOneHotspot(kN01GasOutletSpotID);
+ }
+ } else {
+ HotSpotID spotID;
+
+ if (_fillingStationItem) {
+ switch (_fillingStationItem->getObjectID()) {
+ case kArgonCanister:
+ spotID = kN01ArgonCanisterSpotID;
+ _vm->getAllHotspots().deactivateOneHotspot(kNorad01GasOutSpotID);
+ break;
+ case kGasCanister:
+ spotID = kN01GasCanisterSpotID;
+ break;
+ case kAirMask:
+ spotID = kN01AirMaskSpotID;
+ _vm->getAllHotspots().deactivateOneHotspot(kNorad01GasOutSpotID);
+ break;
+ case kNitrogenCanister:
+ spotID = kN01NitrogenCanisterSpotID;
+ _vm->getAllHotspots().deactivateOneHotspot(kNorad01GasOutSpotID);
+ break;
+ default:
+ // Should never happen.
+ spotID = kNoHotSpotID;
+ break;
+ }
+ _vm->getAllHotspots().activateOneHotspot(spotID);
+ }
+ }
+ break;
+ case MakeRoomView(kNorad10, kEast):
+ if (GameState.isCurrentDoorOpen())
+ _vm->getAllHotspots().deactivateOneHotspot(kNorad10DoorSpotID);
+ break;
+ case MakeRoomView(kNorad21, kWest):
+ if (GameState.isCurrentDoorOpen())
+ _vm->getAllHotspots().deactivateOneHotspot(kNorad21WestSpotID);
+ break;
+ }
+}
+
+void NoradAlpha::clickInHotspot(const Input &input, const Hotspot *cursorSpot) {
+ Norad::clickInHotspot(input, cursorSpot);
+
+ if (_vm->getDragType() == kDragInventoryUse) {
+ if (GameState.getCurrentRoomAndView() == MakeRoomView(kNorad01West, kWest)) {
+ Item *item = _vm->getDraggingItem();
+ if (item->getObjectID() == kAirMask || item->getObjectID() == kArgonCanister ||
+ item->getObjectID() == kNitrogenCanister || item->getObjectID() == kGasCanister) {
+ HotspotInfoTable::Entry *hotspotEntry = findHotspotEntry(kN01GasOutletSpotID);
+ hotspotEntry->hotspotItem = item->getObjectID();
+ }
+ }
+ }
+}
+
+void NoradAlpha::takeItemFromRoom(Item *item) {
+ if (GameState.getCurrentRoom() == kNorad01West) {
+ if (_fillingStationItem == item) {
+ _fillingStationItem = 0;
+ GameState.setNoradGassed(false);
+ loadAmbientLoops();
+ ((NoradAlphaFillingStation *)_currentInteraction)->newFillingItem(0);
+ forceStridingStop(kNorad03, kEast, kAltNoradAlphaNormal);
+ }
+ }
+
+ Norad::takeItemFromRoom(item);
+}
+
+void NoradAlpha::dropItemIntoRoom(Item *item, Hotspot *droppedSpot) {
+ if (GameState.getCurrentRoom() == kNorad01West) {
+ if (!_fillingStationItem) {
+ _fillingStationItem = item;
+ ((NoradAlphaFillingStation *)_currentInteraction)->newFillingItem(item);
+ }
+ }
+
+ Norad::dropItemIntoRoom(item, droppedSpot);
+}
+
+void NoradAlpha::getClawInfo(HotSpotID &outSpotID, HotSpotID &prepSpotID, HotSpotID &clawControlSpotID, HotSpotID &pinchClawSpotID,
+ HotSpotID &moveClawDownSpotID, HotSpotID &moveClawRightSpotID, HotSpotID &moveClawLeftSpotID, HotSpotID &moveClawUpSpotID,
+ HotSpotID &clawCCWSpotID, HotSpotID &clawCWSpotID, uint32 &clawPosition, const uint32 *&clawExtraIDs) {
+ outSpotID = kNorad22MonitorOutSpotID;
+ prepSpotID = kNorad22LaunchPrepSpotID;
+ clawControlSpotID = kNorad22ClawControlSpotID;
+ pinchClawSpotID = kNorad22ClawPinchSpotID;
+ moveClawDownSpotID = kNorad22ClawDownSpotID;
+ moveClawRightSpotID = kNorad22ClawRightSpotID;
+ moveClawLeftSpotID = kNorad22ClawLeftSpotID;
+ moveClawUpSpotID = kNorad22ClawUpSpotID;
+ clawCCWSpotID = kNorad22ClawCCWSpotID;
+ clawCWSpotID = kNorad22ClawCWSpotID;
+ clawPosition = kClawAtD;
+ clawExtraIDs = _noradAlphaClawExtras;
+}
+
+Hotspot *NoradAlpha::getItemScreenSpot(Item *item, DisplayElement *element) {
+ switch (item->getObjectID()) {
+ case kGasCanister:
+ return _vm->getAllHotspots().findHotspotByID(kN01GasCanisterSpotID);
+ case kAirMask:
+ return _vm->getAllHotspots().findHotspotByID(kN01AirMaskSpotID);
+ case kArgonCanister:
+ return _vm->getAllHotspots().findHotspotByID(kN01ArgonCanisterSpotID);
+ case kNitrogenCanister:
+ return _vm->getAllHotspots().findHotspotByID(kN01NitrogenCanisterSpotID);
+ }
+
+ return Norad::getItemScreenSpot(item, element);
+}
+
+Common::String NoradAlpha::getEnvScanMovie() {
+ Common::String movieName = Neighborhood::getEnvScanMovie();
+
+ if (movieName.empty()) {
+ RoomID room = GameState.getCurrentRoom();
+ if (room >= kNorad01 && room <= kNorad01West)
+ return "Images/AI/Norad/XNE1";
+ else if ((room >= kNorad02 && room <= kNorad19West))
+ return "Images/AI/Norad/XNE2";
+
+ return "Images/AI/Norad/XNE3";
+ }
+
+ return movieName;
+}
+
+uint NoradAlpha::getNumHints() {
+ uint numHints = Neighborhood::getNumHints();
+
+ if (numHints == 0) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kNorad01, kNorth):
+ case MakeRoomView(kNorad01, kSouth):
+ case MakeRoomView(kNorad01, kEast):
+ case MakeRoomView(kNorad01, kWest):
+ case MakeRoomView(kNorad01East, kEast):
+ case MakeRoomView(kNorad01West, kWest):
+ if (GameState.getNoradGassed()) {
+ if (g_airMask->isAirFilterOn())
+ numHints = 0;
+ else
+ numHints = 3;
+ } else {
+ numHints = 2;
+ }
+ break;
+ case MakeRoomView(kNorad19West, kWest):
+ if (getSubPrepFailed() && GameState.getNoradSubPrepState() != kSubPrepped)
+ numHints = 1;
+ break;
+ case MakeRoomView(kNorad22, kWest):
+ numHints = 1;
+ break;
+ }
+ }
+
+ return numHints;
+}
+
+Common::String NoradAlpha::getHintMovie(uint hintNum) {
+ Common::String movieName = Neighborhood::getHintMovie(hintNum);
+
+ if (movieName.empty()) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kNorad01, kNorth):
+ case MakeRoomView(kNorad01, kSouth):
+ case MakeRoomView(kNorad01, kEast):
+ case MakeRoomView(kNorad01, kWest):
+ case MakeRoomView(kNorad01East, kEast):
+ case MakeRoomView(kNorad01West, kWest):
+ switch (hintNum) {
+ case 1:
+ if (GameState.getNoradGassed())
+ return "Images/AI/Norad/XN01SW";
+
+ return "Images/AI/Norad/XN01WD2";
+ case 2:
+ if (GameState.getNoradGassed()) {
+ if (_vm->playerHasItemID(kAirMask))
+ // Mask must not be on if we get here...
+ return "Images/AI/Globals/XGLOB1A";
+
+ return "Images/AI/Globals/XGLOB3D";
+ }
+
+ return "Images/AI/Globals/XGLOB5C";
+ case 3:
+ return "Images/AI/Norad/XN01SH";
+ }
+ break;
+ case MakeRoomView(kNorad19West, kWest):
+ return "Images/AI/Norad/XN19NH";
+ case MakeRoomView(kNorad22, kWest):
+ return "Images/AI/Globals/XGLOB1C";
+ }
+ }
+
+ return movieName;
+}
+
+void NoradAlpha::closeDoorOffScreen(const RoomID room, const DirectionConstant) {
+ switch (room) {
+ case kNorad12:
+ case kNorad13:
+ case kNorad18:
+ case kNorad19:
+ playSpotSoundSync(kAlphaElevatorDoorCloseIn, kAlphaElevatorDoorCloseOut);
+ break;
+ default:
+ playSpotSoundSync(kAlphaRegDoorCloseIn, kAlphaRegDoorCloseOut);
+ break;
+ }
+}
+
+void NoradAlpha::findSpotEntry(const RoomID room, const DirectionConstant direction, SpotFlags flags, SpotTable::Entry &spotEntry) {
+ if (room == kNorad01 && direction == kSouth)
+ spotEntry.clear();
+ else
+ Norad::findSpotEntry(room, direction, flags, spotEntry);
+}
+
+bool NoradAlpha::canSolve() {
+ return Norad::canSolve() || getHintMovie(1) == "Images/AI/Norad/XN01SW";
+}
+
+void NoradAlpha::doSolve() {
+ Norad::doSolve();
+
+ if (getHintMovie(1) == "Images/AI/Norad/XN01SW") {
+ _vm->addItemToInventory(g_airMask);
+ g_airMask->putMaskOn();
+ }
+}
+
+Common::String NoradAlpha::getNavMovieName() {
+ return "Images/Norad Alpha/Norad Alpha.movie";
+}
+
+Common::String NoradAlpha::getSoundSpotsName() {
+ return "Sounds/Norad/Norad Alpha Spots";
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/norad/alpha/noradalpha.h b/engines/pegasus/neighborhood/norad/alpha/noradalpha.h
new file mode 100644
index 0000000000..582d6c2bb3
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/alpha/noradalpha.h
@@ -0,0 +1,115 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_NORADALPHA_H
+#define PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_NORADALPHA_H
+
+#include "pegasus/neighborhood/norad/norad.h"
+
+namespace Pegasus {
+
+class Item;
+
+class NoradAlpha : public Norad {
+public:
+ NoradAlpha(InputHandler *, PegasusEngine *);
+ virtual ~NoradAlpha() {}
+
+ virtual void init();
+ void start();
+
+ virtual bool okayToJump();
+
+ void playClawMonitorIntro();
+
+ void getExtraCompassMove(const ExtraTable::Entry &, FaderMoveSpec &);
+
+ void turnOnFillingStation();
+ void turnOffFillingStation();
+ Item *getFillingItem() { return _fillingStationItem; }
+ bool gasCanisterIntake();
+
+ virtual void takeItemFromRoom(Item *);
+ virtual void dropItemIntoRoom(Item *, Hotspot *);
+
+ virtual GameInteraction *makeInteraction(const InteractionID);
+
+ virtual void getClawInfo(HotSpotID &outSpotID, HotSpotID &prepSpotID, HotSpotID &clawControlSpotID,
+ HotSpotID &pinchClawSpotID, HotSpotID &moveClawDownSpotID, HotSpotID &moveClawRightSpotID,
+ HotSpotID &moveClawLeftSpotID, HotSpotID &moveClawUpSpotID, HotSpotID &clawCCWSpotID,
+ HotSpotID &clawCWSpotID, uint32 &, const uint32 *&);
+
+ void loadAmbientLoops();
+
+ Common::String getEnvScanMovie();
+ uint getNumHints();
+ Common::String getHintMovie(uint);
+ void setUpAIRules();
+
+ void setSubPrepFailed(bool value) { _subPrepFailed = value; }
+ bool getSubPrepFailed() { return _subPrepFailed; }
+
+ void closeDoorOffScreen(const RoomID, const DirectionConstant);
+ void findSpotEntry(const RoomID, const DirectionConstant, SpotFlags, SpotTable::Entry &);
+ void clickInHotspot(const Input &, const Hotspot *);
+
+ void checkContinuePoint(const RoomID, const DirectionConstant);
+
+ bool canSolve();
+ void doSolve();
+
+protected:
+ static const uint32 _noradAlphaClawExtras[22];
+
+ virtual void arriveAtNorad01();
+ virtual void arriveAtNorad01East();
+ virtual void arriveAtNorad01West();
+ virtual void arriveAtNorad04();
+ virtual void arriveAtNorad22();
+
+ virtual void arriveAt(const RoomID, const DirectionConstant);
+
+ virtual void getZoomEntry(const HotSpotID, ZoomTable::Entry &);
+ virtual TimeValue getViewTime(const RoomID, const DirectionConstant);
+
+ virtual void receiveNotification(Notification *, const NotificationFlags);
+
+ virtual void activateHotspots();
+
+ Hotspot *getItemScreenSpot(Item *, DisplayElement *);
+
+ void bumpIntoWall();
+
+ Item *_fillingStationItem;
+
+ bool _subPrepFailed;
+
+ Common::String getSoundSpotsName();
+ Common::String getNavMovieName();
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/norad/alpha/panorama.cpp b/engines/pegasus/neighborhood/norad/alpha/panorama.cpp
new file mode 100644
index 0000000000..5a717a84e7
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/alpha/panorama.cpp
@@ -0,0 +1,239 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/macresman.h"
+#include "common/stream.h"
+#include "pegasus/neighborhood/norad/alpha/panorama.h"
+
+namespace Pegasus {
+
+Panorama::Panorama() : _panoramaMovie(kNoDisplayElement) {
+ blankFields();
+}
+
+Panorama::~Panorama() {
+ releasePanorama();
+}
+
+void Panorama::blankFields() {
+ _viewBounds = Common::Rect();
+ _drawBounds = Common::Rect();
+ _mask = 0;
+ _panoramaWidth = 0;
+ _panoramaHeight = 0;
+ _stripWidth = 0;
+ _stripLeft = -1;
+ _stripRight = -1;
+}
+
+void Panorama::releasePanorama() {
+ if (_panoramaMovie.isMovieValid()) {
+ _panoramaMovie.releaseMovie();
+ _panoramaWorld.deallocateSurface();
+ blankFields();
+ }
+}
+
+static const uint32 kPanoramaResType = MKTAG('P', 'a', 'n', 'I'); // Panorama Information.
+static const uint16 kPanoramaResID = 128;
+
+void Panorama::initFromMovieFile(const Common::String &fileName) {
+ // First, we need the resource fork for other reasons -- PanI resource
+ Common::MacResManager *resFork = new Common::MacResManager();
+ if (!resFork->open(fileName) || !resFork->hasResFork())
+ error("Could not open the resource fork of '%s'", fileName.c_str());
+
+ Common::SeekableReadStream *resource = resFork->getResource(kPanoramaResType, kPanoramaResID);
+ if (!resource)
+ error("No panorama information in the resource fork of '%s'", fileName.c_str());
+
+ _panoramaWidth = resource->readUint16BE();
+ _panoramaHeight = resource->readUint16BE();
+ _stripWidth = resource->readUint16BE();
+
+ delete resource;
+ delete resFork;
+
+ // Now we open the movie like normal
+ _panoramaMovie.initFromMovieFile(fileName);
+}
+
+void Panorama::setMask(Surface *mask) {
+ _mask = mask;
+}
+
+// If the panorama is not open, do nothing and return.
+// Otherwise, set up the view bounds.
+void Panorama::setViewBounds(const Common::Rect &newView) {
+ if (!isPanoramaOpen())
+ return;
+
+ if (newView.isEmpty())
+ return;
+
+ Common::Rect r = newView;
+
+ if (r.width() > _panoramaWidth) {
+ r.left = 0;
+ r.right = _panoramaWidth;
+ } else {
+ if (r.right > _panoramaWidth)
+ r.translate(_panoramaWidth - r.right, 0);
+
+ if (r.left < 0)
+ r.translate(-r.left, 0);
+ }
+
+ if (r.height() > _panoramaHeight) {
+ r.top = 0;
+ r.bottom = _panoramaHeight;
+ } else {
+ if (r.bottom > _panoramaHeight)
+ r.translate(0, _panoramaHeight - r.bottom);
+
+ if (r.top < 0)
+ r.translate(0, -r.top);
+ }
+
+ if (_viewBounds != r) {
+ CoordType stripLeft = 0;
+
+ if (r.width() != _viewBounds.width() || !_panoramaWorld.isSurfaceValid()) {
+ _panoramaWorld.deallocateSurface();
+ makeNewSurface(r);
+ } else {
+ CoordType stripRight;
+ calcStripRange(r, stripLeft, stripRight);
+ loadStrips(stripLeft, stripRight);
+ }
+
+ _viewBounds = r;
+ _drawBounds = r;
+ _drawBounds.translate(-stripLeft * _stripWidth, 0);
+ }
+}
+
+void Panorama::getViewBounds(Common::Rect &r) const {
+ r = _viewBounds;
+}
+
+void Panorama::getPanoramaBounds(Common::Rect &r) const {
+ r = Common::Rect(0, 0, _panoramaWidth, _panoramaHeight);
+}
+
+void Panorama::drawPanorama(const Common::Rect &destRect) {
+ if (_panoramaWorld.isSurfaceValid()) {
+ if (_mask)
+ _panoramaWorld.copyToCurrentPortMasked(_drawBounds, destRect, _mask);
+ else
+ _panoramaWorld.copyToCurrentPortTransparent(_drawBounds, destRect);
+ }
+}
+
+// Make a new Surface big enough to show r, which is assumed to be a valid view bounds.
+// Assumptions:
+// r is a valid view bounds.
+// _panoramaWorld is not allocated.
+// _panoramaHeight, _stripWidth is correct.
+// _panoramaMovie is allocated.
+void Panorama::makeNewSurface(const Common::Rect& view) {
+ CoordType stripLeft, stripRight;
+ calcStripRange(view, stripLeft, stripRight);
+
+ Common::Rect r(0, 0, (stripRight - stripLeft + 1) * _stripWidth, _panoramaHeight);
+ _panoramaWorld.allocateSurface(r);
+ _panoramaMovie.shareSurface(&_panoramaWorld);
+ loadStrips(stripLeft, stripRight);
+}
+
+// Assumes view is not empty.
+void Panorama::calcStripRange(const Common::Rect &view, CoordType &stripLeft, CoordType &stripRight) {
+ stripLeft = view.left / _stripWidth;
+ stripRight = (view.left - view.left % _stripWidth + _stripWidth - 1 + view.width()) / _stripWidth;
+}
+
+// Load in all needed strips to put range (stripLeft, stripRight) into the
+// panorama's Surface. Try to optimize by saving any pixels already in the Surface.
+// Assumptions:
+// Surface is allocated and is big enough for maximum range of
+// stripLeft and stripRight
+void Panorama::loadStrips(CoordType stripLeft, CoordType stripRight) {
+ if (_stripLeft == -1) {
+ // Surface has just been allocated.
+ // Load in all strips.
+ for (CoordType i = stripLeft; i <= stripRight; i++)
+ loadOneStrip(i, stripLeft);
+
+ _stripLeft = stripLeft;
+ _stripRight = stripRight;
+ } else if (stripLeft != _stripLeft) {
+ CoordType overlapLeft = MAX(stripLeft, _stripLeft);
+ CoordType overlapRight = MIN(stripRight, _stripRight);
+
+ if (overlapLeft <= overlapRight) {
+ Common::Rect r1((overlapLeft - _stripLeft) * _stripWidth, 0,
+ (overlapRight - _stripLeft + 1) * _stripWidth, _panoramaHeight);
+
+ if (stripLeft < _stripLeft) {
+ Common::Rect bounds;
+ _panoramaWorld.getSurfaceBounds(bounds);
+ _panoramaWorld.getSurface()->move(bounds.right - r1.right, 0, _panoramaHeight);
+
+ for (CoordType i = stripLeft; i < _stripLeft; i++)
+ loadOneStrip(i, stripLeft);
+ } else {
+ _panoramaWorld.getSurface()->move(-r1.left, 0, _panoramaHeight);
+
+ for (CoordType i = _stripRight + 1; i <= stripRight; i++)
+ loadOneStrip(i, stripLeft);
+ }
+ } else {
+ // No overlap.
+ // Load everything.
+ for (CoordType i = stripLeft; i <= stripRight; i++)
+ loadOneStrip(i, stripLeft);
+ }
+
+ _stripLeft = stripLeft;
+ _stripRight = stripRight;
+ } else if (stripRight > _stripRight) {
+ // Need to add one or more strips.
+ for (CoordType i = _stripRight + 1; i <= stripRight; i++)
+ loadOneStrip(i, _stripLeft);
+
+ _stripRight = stripRight;
+ } else if (stripRight < _stripRight) {
+ // Need to chop off one strip.
+ _stripRight = stripRight;
+ }
+}
+
+void Panorama::loadOneStrip(CoordType stripToLoad, CoordType leftStrip) {
+ _panoramaMovie.moveMovieBoxTo((stripToLoad - leftStrip) * _stripWidth, 0);
+ _panoramaMovie.setTime(stripToLoad, 1);
+ _panoramaMovie.redrawMovieWorld();
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/norad/alpha/panorama.h b/engines/pegasus/neighborhood/norad/alpha/panorama.h
new file mode 100644
index 0000000000..87c7b3bd4e
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/alpha/panorama.h
@@ -0,0 +1,98 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_PANORAMA_H
+#define PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_PANORAMA_H
+
+#include "pegasus/movie.h"
+
+namespace Pegasus {
+
+/*
+
+ Panorama implements a wide image using a specially constructed movie file.
+ The movie holds the image as a series of vertical strips, say 16 or 32 pixels wide.
+
+ The panorama bounds defines the entire panorama. The view bounds represents the
+ area on the panorama that is kept in memory.
+
+ The panorama bounds is also stored in the movie file; it cannot be changed. The
+ view bounds must always be a subset of the panorama bounds.
+
+ In actuality, the area kept in memory is at least as wide as the view bounds (but
+ may be wider to coincide with the width of the movies slices), and is as tall as
+ the panorama bounds. The view bounds is used by the drawPanorama function to draw
+ a piece of the panorama to the current screen.
+
+ The panorama movie is built at a time scale of 1, with each strip lasting for one
+ second, so that strip number corresponds exactly with the time value at which the
+ strip is stored.
+
+ TO USE:
+
+ Call one initFromMovieFile to open the movie. Then set up a view rect by
+ calling setViewBounds. Once these two functions have been called, drawPanorama
+ will draw the panorama.
+
+*/
+
+class Panorama {
+public:
+ Panorama();
+ virtual ~Panorama();
+
+ void initFromMovieFile(const Common::String &);
+ void releasePanorama();
+ bool isPanoramaOpen() { return _panoramaMovie.isMovieValid(); }
+
+ void setViewBounds(const Common::Rect &);
+ void getViewBounds(Common::Rect &) const;
+
+ void setMask(Surface *);
+
+ void getPanoramaBounds(Common::Rect &) const;
+
+ void drawPanorama(const Common::Rect &);
+
+protected:
+ void blankFields();
+ void makeNewSurface(const Common::Rect &);
+ void calcStripRange(const Common::Rect &, CoordType &, CoordType &);
+ void loadStrips(CoordType, CoordType);
+ void loadOneStrip(CoordType, CoordType);
+
+ Movie _panoramaMovie;
+ Surface _panoramaWorld, *_mask;
+ Common::Rect _viewBounds;
+ Common::Rect _drawBounds;
+ CoordType _panoramaWidth, _panoramaHeight;
+ CoordType _stripWidth; // Pixels per strip.
+ CoordType _numStrips;
+ CoordType _stripLeft, _stripRight;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/norad/alpha/panoramascroll.cpp b/engines/pegasus/neighborhood/norad/alpha/panoramascroll.cpp
new file mode 100644
index 0000000000..7865bbb442
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/alpha/panoramascroll.cpp
@@ -0,0 +1,91 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/neighborhood/norad/alpha/panoramascroll.h"
+
+namespace Pegasus {
+
+PanoramaScroll::PanoramaScroll(const DisplayElementID id) : IdlerAnimation(id) {
+ _boundsWidth = 0;
+ _totalWidth = 0;
+}
+
+void PanoramaScroll::initFromMovieFile(const Common::String &fileName) {
+ _panorama.initFromMovieFile(fileName);
+
+ Common::Rect r;
+ _panorama.getPanoramaBounds(r);
+ _totalWidth = r.width();
+}
+
+void PanoramaScroll::initMaskFromPICTFile(const Common::String &fileName) {
+ if (!_panorama.isPanoramaOpen())
+ return;
+
+ _mask.getImageFromPICTFile(fileName);
+ _panorama.setMask(&_mask);
+}
+
+void PanoramaScroll::releasePanorama() {
+ if (_panorama.isPanoramaOpen())
+ _panorama.releasePanorama();
+
+ _mask.deallocateSurface();
+}
+
+void PanoramaScroll::setBounds(const Common::Rect &r) {
+ Animation::setBounds(r);
+
+ _boundsWidth = r.width();
+
+ Common::Rect r2;
+ _panorama.getViewBounds(r2);
+ r2.right = r2.left + _boundsWidth;
+ r2.bottom = r2.top + r.height();
+ _panorama.setViewBounds(r2);
+}
+
+void PanoramaScroll::draw(const Common::Rect &) {
+ _panorama.drawPanorama(_bounds);
+}
+
+void PanoramaScroll::timeChanged(const TimeValue newTime) {
+ CoordType leftPixel = (_totalWidth - _boundsWidth) * newTime / getDuration();
+
+ Common::Rect r;
+ _panorama.getViewBounds(r);
+ if (leftPixel != r.left) {
+ _panorama.getViewBounds(r);
+ r.moveTo(leftPixel, 0);
+ _panorama.setViewBounds(r);
+ triggerRedraw();
+ }
+}
+
+void PanoramaScroll::getPanoramaBounds(Common::Rect &r) const {
+ _panorama.getPanoramaBounds(r);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/norad/alpha/panoramascroll.h b/engines/pegasus/neighborhood/norad/alpha/panoramascroll.h
new file mode 100644
index 0000000000..6a3e1515e2
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/alpha/panoramascroll.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.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_PANORAMASCROLL_H
+#define PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_PANORAMASCROLL_H
+
+#include "pegasus/neighborhood/norad/alpha/panorama.h"
+
+namespace Pegasus {
+
+class PanoramaScroll : public IdlerAnimation {
+public:
+ PanoramaScroll(const DisplayElementID);
+ virtual ~PanoramaScroll() {}
+
+ void initFromMovieFile(const Common::String &);
+ void initMaskFromPICTFile(const Common::String &);
+
+ void releasePanorama();
+
+ bool isPanoramaOpen() { return _panorama.isPanoramaOpen(); }
+ void getPanoramaBounds(Common::Rect &) const;
+
+ void setBounds(const Common::Rect&);
+
+ void draw(const Common::Rect &);
+
+protected:
+ void timeChanged(const TimeValue);
+
+ Panorama _panorama;
+ Surface _mask;
+ CoordType _totalWidth, _boundsWidth;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/norad/constants.h b/engines/pegasus/neighborhood/norad/constants.h
new file mode 100644
index 0000000000..37c1769309
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/constants.h
@@ -0,0 +1,755 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_NORAD_CONSTANTS_H
+#define PEGASUS_NEIGHBORHOOD_NORAD_CONSTANTS_H
+
+#include "pegasus/constants.h"
+
+namespace Pegasus {
+
+// Norad Alpha spot constants
+
+static const TimeValue kAlphaBumpIntoWallIn = 0;
+static const TimeValue kAlphaBumpIntoWallOut = 303;
+
+static const TimeValue kAlphaAccessDeniedIn = 303;
+static const TimeValue kAlphaAccessDeniedOut = 3045;
+
+static const TimeValue kAlphaRegDoorCloseIn = 3045;
+static const TimeValue kAlphaRegDoorCloseOut = 4476;
+
+static const TimeValue kAlphaElevatorDoorCloseIn = 4476;
+static const TimeValue kAlphaElevatorDoorCloseOut = 5071;
+
+static const TimeValue kAlphaCantTransportIn = 5071;
+static const TimeValue kAlphaCantTransportOut = 9348;
+
+static const TimeValue kAlphaPressureDoorIntro1In = 9348;
+static const TimeValue kAlphaPressureDoorIntro1Out = 11061;
+
+static const TimeValue kAlphaPressureDoorIntro2In = 11061;
+static const TimeValue kAlphaPressureDoorIntro2Out = 14098;
+
+static const TimeValue kN22ReplyIn = 14098;
+static const TimeValue kN22ReplyOut = 18442;
+
+static const TimeValue kAlphaLoadClawIntroIn = 18442;
+static const TimeValue kAlphaLoadClawIntroOut = 20698;
+
+// Norad Delta spot constants
+
+static const TimeValue kDeltaBumpIntoWallIn = 0;
+static const TimeValue kDeltaBumpIntoWallOut = 303;
+
+static const TimeValue kDeltaAccessDeniedIn = 303;
+static const TimeValue kDeltaAccessDeniedOut = 3045;
+
+static const TimeValue kDeltaRegDoorCloseIn = 3045;
+static const TimeValue kDeltaRegDoorCloseOut = 4476;
+
+static const TimeValue kDeltaElevatorDoorCloseIn = 4476;
+static const TimeValue kDeltaElevatorDoorCloseOut = 5071;
+
+static const TimeValue kPressureDoorIntro1In = 5071;
+static const TimeValue kPressureDoorIntro1Out = 6784;
+
+static const TimeValue kPressureDoorIntro2In = 6784;
+static const TimeValue kPressureDoorIntro2Out = 9821;
+
+static const TimeValue kLoadClawIntroIn = 9821;
+static const TimeValue kLoadClawIntroOut = 12077;
+
+static const TimeValue kHoldForRetinalIn = 12077;
+static const TimeValue kHoldForRetinalOut = 14104;
+
+static const TimeValue kRetinalScanFailedIn = 14104;
+static const TimeValue kRetinalScanFailedOut = 17538;
+
+static const TimeValue kAddisAbabaIn = 17538;
+static const TimeValue kAddisAbabaOut = 19263;
+
+static const TimeValue kBangkokIn = 19263;
+static const TimeValue kBangkokOut = 20201;
+
+static const TimeValue kBonnIn = 20201;
+static const TimeValue kBonnOut = 20915;
+
+static const TimeValue kDublinIn = 20915;
+static const TimeValue kDublinOut = 21660;
+
+static const TimeValue kHonoluluIn = 21660;
+static const TimeValue kHonoluluOut = 22498;
+
+static const TimeValue kMadridIn = 22498;
+static const TimeValue kMadridOut = 23474;
+
+static const TimeValue kReykjavikIn = 23474;
+static const TimeValue kReykjavikOut = 24488;
+
+static const TimeValue kSanAntonioIn = 24488;
+static const TimeValue kSanAntonioOut = 25561;
+
+static const TimeValue kSeoulIn = 25561;
+static const TimeValue kSeoulOut = 26461;
+
+static const TimeValue kSvortalskIn = 26461;
+static const TimeValue kSvortalskOut = 27582;
+
+static const TimeValue kSiloBeepIn = 27582;
+static const TimeValue kSiloBeepOut = 27721;
+
+static const TimeValue kAllSilosDeactivatedIn = 27721;
+static const TimeValue kAllSilosDeactivatedOut = 28928;
+
+static const TimeValue kGlobalLaunchOverrideIn = 28928;
+static const TimeValue kGlobalLaunchOverrideOut = 30736;
+
+static const TimeValue kLaunchSiloSelectedIn = 30736;
+static const TimeValue kLaunchSiloSelectedOut = 31660;
+
+static const TimeValue kLaunchToProceedIn = 31660;
+static const TimeValue kLaunchToProceedOut = 32536;
+
+static const TimeValue kMaximumDeactivationIn = 32536;
+static const TimeValue kMaximumDeactivationOut = 34337;
+
+static const TimeValue kMissileLaunchedIn = 34337;
+static const TimeValue kMissileLaunchedOut = 35082;
+
+static const TimeValue kNewLaunchSiloIn = 35082;
+static const TimeValue kNewLaunchSiloOut = 36320;
+
+static const TimeValue kStrikeAuthorizedIn = 36320;
+static const TimeValue kStrikeAuthorizedOut = 37393;
+
+static const TimeValue kPrimaryTargetIn = 37393;
+static const TimeValue kPrimaryTargetOut = 38628;
+
+static const TimeValue kSiloDeactivatedIn = 38628;
+static const TimeValue kSiloDeactivatedOut = 39566;
+
+static const TimeValue kStrikeCodeRejectedIn = 39566;
+static const TimeValue kStrikeCodeRejectedOut = 41056;
+
+static const TimeValue kToDeactivateIn = 41056;
+static const TimeValue kToDeactivateOut = 46494;
+
+static const TimeValue kTwoMinutesIn = 46494;
+static const TimeValue kTwoMinutesOut = 47166;
+
+static const TimeValue kOneMinuteIn = 47166;
+static const TimeValue kOneMinuteOut = 47856;
+
+static const TimeValue kFiftySecondsIn = 47856;
+static const TimeValue kFiftySecondsOut = 48691;
+
+static const TimeValue kFortySecondsIn = 48691;
+static const TimeValue kFortySecondsOut = 49500;
+
+static const TimeValue kThirtySecondsIn = 49500;
+static const TimeValue kThirtySecondsOut = 50362;
+
+static const TimeValue kTwentySecondsIn = 50362;
+static const TimeValue kTwentySecondsOut = 51245;
+
+static const TimeValue kTenSecondsIn = 51245;
+static const TimeValue kTenSecondsOut = 52069;
+
+static const TimeValue kGiveUpHumanIn = 52069;
+static const TimeValue kGiveUpHumanOut = 55023;
+
+static const TimeValue kIJustBrokeIn = 55023;
+static const TimeValue kIJustBrokeOut = 59191;
+
+static const TimeValue kTheOnlyGoodHumanIn = 59191;
+static const TimeValue kTheOnlyGoodHumanOut = 62379;
+
+static const TimeValue kYouAreRunningIn = 62379;
+static const TimeValue kYouAreRunningOut = 64201;
+
+static const TimeValue kYouCannotPossiblyIn = 64201;
+static const TimeValue kYouCannotPossiblyOut = 65740;
+
+static const TimeValue kYouWillFailIn = 65740;
+static const TimeValue kYouWillFailOut = 67217;
+
+static const CanOpenDoorReason kCantOpenBadPressure = kCantOpenLastReason + 1;
+
+static const NotificationFlags kAirTimerExpiredFlag = kLastNeighborhoodNotificationFlag << 1;
+
+static const uint16 kNoradWarningVolume = 0x100 / 3;
+static const uint16 kNoradSuckWindVolume = 0x100 / 2;
+
+static const int16 kElevatorCompassAngle = -40;
+static const int16 kSubPlatformCompassAngle = 45;
+static const int16 kSubControlCompassAngle = -10;
+
+// Norad interactions.
+
+static const InteractionID kNoradGlobeGameInteractionID = 0;
+static const InteractionID kNoradECRMonitorInteractionID = 1;
+static const InteractionID kNoradFillingStationInteractionID = 2;
+static const InteractionID kNoradElevatorInteractionID = 3;
+static const InteractionID kNoradPressureDoorInteractionID = 4;
+static const InteractionID kNoradSubControlRoomInteractionID = 5;
+static const InteractionID kNoradSubPlatformInteractionID = 6;
+
+/////////////////////////////////////////////
+//
+// Norad Alpha
+
+static const CoordType kECRSlideShowLeft = kNavAreaLeft + 78;
+static const CoordType kECRSlideShowTop = kNavAreaTop + 1;
+
+static const CoordType kECRPanLeft = kNavAreaLeft + 78 + 5;
+static const CoordType kECRPanTop = kNavAreaTop + 1 + 4;
+static const CoordType kECRPanRight = kECRPanLeft + 213;
+static const CoordType kECRPanBottom = kECRPanTop + 241;
+
+static const CoordType kNoradAlphaElevatorControlsLeft = kNavAreaLeft + 332;
+static const CoordType kNoradAlphaElevatorControlsTop = kNavAreaTop + 127;
+
+static const CoordType kNoradAlpha01LeftSideLeft = kNavAreaLeft + 0;
+static const CoordType kNoradAlpha01LeftSideTop = kNavAreaTop + 0;
+
+static const CoordType kNoradAlpha01RightSideLeft = kNavAreaLeft + 240;
+static const CoordType kNoradAlpha01RightSideTop = kNavAreaTop + 12;
+
+static const CoordType kNoradUpperLevelsLeft = kNavAreaLeft + 98;
+static const CoordType kNoradUpperLevelsTop = kNavAreaTop + 31;
+
+static const CoordType kNoradUpperTypeLeft = kNoradUpperLevelsLeft + 114;
+static const CoordType kNoradUpperTypeTop = kNoradUpperLevelsTop + 8;
+
+static const CoordType kNoradUpperUpLeft = kNavAreaLeft + 361;
+static const CoordType kNoradUpperUpTop = kNavAreaTop + 32;
+
+static const CoordType kNoradUpperDownLeft = kNavAreaLeft + 367;
+static const CoordType kNoradUpperDownTop = kNavAreaTop + 66;
+
+static const CoordType kNoradLowerLevelsLeft = kNavAreaLeft + 74;
+static const CoordType kNoradLowerLevelsTop = kNavAreaTop + 157;
+
+static const CoordType kNoradLowerTypeLeft = kNoradLowerLevelsLeft + 144;
+static const CoordType kNoradLowerTypeTop = kNoradLowerLevelsTop + 9;
+
+static const CoordType kNoradLowerUpLeft = kNavAreaLeft + 380;
+static const CoordType kNoradLowerUpTop = kNavAreaTop + 164;
+
+static const CoordType kNoradLowerDownLeft = kNavAreaLeft + 388;
+static const CoordType kNoradLowerDownTop = kNavAreaTop + 212;
+
+static const CoordType kNoradPlatformLeft = kNavAreaLeft + 36;
+static const CoordType kNoradPlatformTop = kNavAreaTop + 87;
+
+static const CoordType kNoradSubControlLeft = kNavAreaLeft + 0;
+static const CoordType kNoradSubControlTop = kNavAreaTop + 84;
+
+static const CoordType kNoradSubControlPinchLeft = kNoradSubControlLeft + 106;
+static const CoordType kNoradSubControlPinchTop = kNoradSubControlTop + 86;
+
+static const CoordType kNoradSubControlDownLeft = kNoradSubControlLeft + 66;
+static const CoordType kNoradSubControlDownTop = kNoradSubControlTop + 106;
+
+static const CoordType kNoradSubControlRightLeft = kNoradSubControlLeft + 83;
+static const CoordType kNoradSubControlRightTop = kNoradSubControlTop + 90;
+
+static const CoordType kNoradSubControlLeftLeft = kNoradSubControlLeft + 56;
+static const CoordType kNoradSubControlLeftTop = kNoradSubControlTop + 91;
+
+static const CoordType kNoradSubControlUpLeft = kNoradSubControlLeft + 66;
+static const CoordType kNoradSubControlUpTop = kNoradSubControlTop + 81;
+
+static const CoordType kNoradSubControlCCWLeft = kNoradSubControlLeft + 29;
+static const CoordType kNoradSubControlCCWTop = kNoradSubControlTop + 88;
+
+static const CoordType kNoradSubControlCWLeft = kNoradSubControlLeft + 0;
+static const CoordType kNoradSubControlCWTop = kNoradSubControlTop + 89;
+
+static const CoordType kNoradClawMonitorLeft = kNavAreaLeft + 288;
+static const CoordType kNoradClawMonitorTop = kNavAreaTop + 97;
+
+static const CoordType kNoradGreenBallAtALeft = kNoradClawMonitorLeft + 179;
+static const CoordType kNoradGreenBallAtATop = kNoradClawMonitorTop + 82;
+
+static const CoordType kNoradGreenBallAtBLeft = kNoradClawMonitorLeft + 130;
+static const CoordType kNoradGreenBallAtBTop = kNoradClawMonitorTop + 73;
+
+static const CoordType kNoradGreenBallAtCLeft = kNoradClawMonitorLeft + 110;
+static const CoordType kNoradGreenBallAtCTop = kNoradClawMonitorTop + 26;
+
+static const CoordType kNoradGreenBallAtDLeft = kNoradClawMonitorLeft + 21;
+static const CoordType kNoradGreenBallAtDTop = kNoradClawMonitorTop + 49;
+
+/////////////////////////////////////////////
+//
+// Norad Delta
+
+static const CoordType kGlobeMonitorLeft = kNavAreaLeft + 360;
+static const CoordType kGlobeMonitorTop = kNavAreaTop + 144;
+
+static const CoordType kGlobeLeft = kNavAreaLeft + 172;
+static const CoordType kGlobeTop = kNavAreaTop;
+
+static const CoordType kGlobeCircleLeftLeft = kNavAreaLeft + 186;
+static const CoordType kGlobeCircleLeftTop = kNavAreaTop + 41;
+
+static const CoordType kGlobeCircleRightLeft = kNavAreaLeft + 321;
+static const CoordType kGlobeCircleRightTop = kNavAreaTop + 41;
+
+static const CoordType kGlobeCircleUpLeft = kNavAreaLeft + 220;
+static const CoordType kGlobeCircleUpTop = kNavAreaTop + 7;
+
+static const CoordType kGlobeCircleDownLeft = kNavAreaLeft + 220;
+static const CoordType kGlobeCircleDownTop = kNavAreaTop + 142;
+
+static const CoordType kGlobeUpperLeftHiliteLeft = kNavAreaLeft + 207;
+static const CoordType kGlobeUpperLeftHiliteTop = kNavAreaTop + 28;
+
+static const CoordType kGlobeUpperRightHiliteLeft = kNavAreaLeft + 307;
+static const CoordType kGlobeUpperRightHiliteTop = kNavAreaTop + 28;
+
+static const CoordType kGlobeLowerLeftHiliteLeft = kNavAreaLeft + 207;
+static const CoordType kGlobeLowerLeftHiliteTop = kNavAreaTop + 128;
+
+static const CoordType kGlobeLowerRightHiliteLeft = kNavAreaLeft + 307;
+static const CoordType kGlobeLowerRightHiliteTop = kNavAreaTop + 128;
+
+static const CoordType kGlobeLeftMotionHiliteLeft = kNavAreaLeft + 182;
+static const CoordType kGlobeLeftMotionHiliteTop = kNavAreaTop + 60;
+
+static const CoordType kGlobeRightMotionHiliteLeft = kNavAreaLeft + 331;
+static const CoordType kGlobeRightMotionHiliteTop = kNavAreaTop + 60;
+
+static const CoordType kGlobeUpMotionHiliteLeft = kNavAreaLeft + 239;
+static const CoordType kGlobeUpMotionHiliteTop = kNavAreaTop + 3;
+
+static const CoordType kGlobeDownMotionHiliteLeft = kNavAreaLeft + 239;
+static const CoordType kGlobeDownMotionHiliteTop = kNavAreaTop + 152;
+
+static const CoordType kGlobeUpperNamesLeft = kNavAreaLeft + 368;
+static const CoordType kGlobeUpperNamesTop = kNavAreaTop + 188;
+
+static const CoordType kGlobeLowerNamesLeft = kNavAreaLeft + 368;
+static const CoordType kGlobeLowerNamesTop = kNavAreaTop + 212;
+
+static const CoordType kGlobeCountdownLeft = kNavAreaLeft + 478;
+static const CoordType kGlobeCountdownTop = kNavAreaTop + 164;
+
+// Norad Alpha display IDs.
+
+static const DisplayElementID kECRSlideShowMovieID = kNeighborhoodDisplayID;
+static const DisplayElementID kECRPanID = kECRSlideShowMovieID + 1;
+static const DisplayElementID kNoradAlphaDeathMovieID = kECRPanID + 1;
+static const DisplayElementID kNoradElevatorControlsID = kNoradAlphaDeathMovieID + 1;
+static const DisplayElementID kN01LeftSideID = kNoradElevatorControlsID + 1;
+static const DisplayElementID kN01RightSideID = kN01LeftSideID + 1;
+static const DisplayElementID kPressureDoorLevelsID = kN01RightSideID + 1;
+static const DisplayElementID kPressureDoorTypeID = kPressureDoorLevelsID + 1;
+static const DisplayElementID kPressureDoorUpButtonID = kPressureDoorTypeID + 1;
+static const DisplayElementID kPressureDoorDownButtonID = kPressureDoorUpButtonID + 1;
+static const DisplayElementID kPlatformMonitorID = kPressureDoorDownButtonID + 1;
+static const DisplayElementID kSubControlMonitorID = kPlatformMonitorID + 1;
+static const DisplayElementID kClawMonitorID = kSubControlMonitorID + 1;
+static const DisplayElementID kSubControlPinchID = kClawMonitorID + 1;
+static const DisplayElementID kSubControlDownID = kSubControlPinchID + 1;
+static const DisplayElementID kSubControlRightID = kSubControlDownID + 1;
+static const DisplayElementID kSubControlLeftID = kSubControlRightID + 1;
+static const DisplayElementID kSubControlUpID = kSubControlLeftID + 1;
+static const DisplayElementID kSubControlCCWID = kSubControlUpID + 1;
+static const DisplayElementID kSubControlCWID = kSubControlCCWID + 1;
+static const DisplayElementID kClawMonitorGreenBallID = kSubControlCWID + 1;
+
+// Norad Delta display IDs.
+
+static const DisplayElementID kGlobeMonitorID = kNeighborhoodDisplayID;
+static const DisplayElementID kGlobeMovieID = kGlobeMonitorID + 14;
+static const DisplayElementID kGlobeCircleLeftID = kGlobeMovieID + 1;
+static const DisplayElementID kGlobeCircleRightID = kGlobeCircleLeftID + 1;
+static const DisplayElementID kGlobeCircleUpID = kGlobeCircleRightID + 1;
+static const DisplayElementID kGlobeCircleDownID = kGlobeCircleUpID + 1;
+static const DisplayElementID kMotionHiliteLeftID = kGlobeCircleDownID + 1;
+static const DisplayElementID kMotionHiliteRightID = kMotionHiliteLeftID + 1;
+static const DisplayElementID kMotionHiliteUpID = kMotionHiliteRightID + 1;
+static const DisplayElementID kMotionHiliteDownID = kMotionHiliteUpID + 1;
+static const DisplayElementID kTargetHiliteUpperLeftID = kMotionHiliteDownID + 1;
+static const DisplayElementID kTargetHiliteUpperRightID = kTargetHiliteUpperLeftID + 1;
+static const DisplayElementID kTargetHiliteLowerLeftID = kTargetHiliteUpperRightID + 1;
+static const DisplayElementID kTargetHiliteLowerRightID = kTargetHiliteLowerLeftID + 1;
+static const DisplayElementID kGlobeUpperNamesID = kTargetHiliteLowerRightID + 1;
+static const DisplayElementID kGlobeLowerNamesID = kGlobeUpperNamesID + 1;
+static const DisplayElementID kGlobeCountdownID = kGlobeLowerNamesID + 1;
+
+// Norad Alpha:
+
+static const DisplayOrder kECRMonitorOrder = kMonitorLayer;
+static const DisplayOrder kECRPanOrder = kECRMonitorOrder + 1;
+
+static const DisplayOrder kN01LeftSideOrder = kMonitorLayer;
+static const DisplayOrder kN01RightSideOrder = kN01LeftSideOrder + 1;
+
+static const DisplayOrder kElevatorControlsOrder = kMonitorLayer;
+
+static const DisplayOrder kPressureLevelsOrder = kMonitorLayer;
+static const DisplayOrder kPressureTypeOrder = kPressureLevelsOrder + 1;
+static const DisplayOrder kPressureUpOrder = kPressureTypeOrder + 1;
+static const DisplayOrder kPressureDownOrder = kPressureUpOrder + 1;
+
+static const DisplayOrder kPlatformOrder = kMonitorLayer;
+
+static const DisplayOrder kSubControlOrder = kMonitorLayer;
+static const DisplayOrder kClawMonitorOrder = kSubControlOrder + 1;
+static const DisplayOrder kSubControlPinchOrder = kClawMonitorOrder + 1;
+static const DisplayOrder kSubControlDownOrder = kSubControlPinchOrder + 1;
+static const DisplayOrder kSubControlRightOrder = kSubControlDownOrder + 1;
+static const DisplayOrder kSubControlLeftOrder = kSubControlRightOrder + 1;
+static const DisplayOrder kSubControlUpOrder = kSubControlLeftOrder + 1;
+static const DisplayOrder kSubControlCCWOrder = kSubControlUpOrder + 1;
+static const DisplayOrder kSubControlCWOrder = kSubControlCCWOrder + 1;
+static const DisplayOrder kClawMonitorGreenBallOrder = kSubControlCWOrder + 1;
+
+// Norad Delta:
+
+static const DisplayOrder kGlobeMonitorLayer = kMonitorLayer;
+static const DisplayOrder kGlobeMovieLayer = kGlobeMonitorLayer + 1;
+static const DisplayOrder kGlobeCircleLayer = kGlobeMovieLayer + 1;
+static const DisplayOrder kGlobeHilitesLayer = kGlobeCircleLayer + 1;
+static const DisplayOrder kGlobeUpperNamesLayer = kGlobeHilitesLayer + 1;
+static const DisplayOrder kGlobeLowerNamesLayer = kGlobeUpperNamesLayer + 1;
+static const DisplayOrder kGlobeCountdownLayer = kGlobeLowerNamesLayer + 1;
+
+// Norad Alpha Tables
+
+static const TimeScale kNoradAlphaMovieScale = 600;
+static const TimeScale kNoradAlphaFramesPerSecond = 15;
+static const TimeScale kNoradAlphaFrameDuration = 40;
+
+// Alternate IDs.
+
+static const AlternateID kAltNoradAlphaNormal = 0;
+
+// Room IDs.
+
+static const RoomID kNorad01 = 0;
+static const RoomID kNorad01East = 1;
+static const RoomID kNorad01West = 2;
+static const RoomID kNorad02 = 3;
+static const RoomID kNorad03 = 4;
+static const RoomID kNorad04 = 5;
+static const RoomID kNorad05 = 6;
+static const RoomID kNorad06 = 7;
+static const RoomID kNorad07 = 8;
+static const RoomID kNorad07North = 9;
+static const RoomID kNorad08 = 10;
+static const RoomID kNorad09 = 11;
+static const RoomID kNorad10 = 12;
+static const RoomID kNorad10East = 13;
+static const RoomID kNorad11 = 14;
+static const RoomID kNorad11South = 15;
+static const RoomID kNorad12 = 16;
+static const RoomID kNorad12South = 17;
+static const RoomID kNorad13 = 18;
+static const RoomID kNorad14 = 19;
+static const RoomID kNorad15 = 20;
+static const RoomID kNorad16 = 21;
+static const RoomID kNorad17 = 22;
+static const RoomID kNorad18 = 23;
+static const RoomID kNorad19 = 24;
+static const RoomID kNorad19West = 25;
+static const RoomID kNorad21 = 26;
+static const RoomID kNorad21West = 27;
+static const RoomID kNorad22 = 28;
+static const RoomID kNorad22West = 29;
+
+// Hot Spot Activation IDs.
+
+
+// Hot Spot IDs.
+
+static const HotSpotID kNorad01ECRSpotID = 5000;
+static const HotSpotID kNorad01GasSpotID = 5001;
+static const HotSpotID kNorad01ECROutSpotID = 5002;
+static const HotSpotID kNorad01GasOutSpotID = 5003;
+static const HotSpotID kNorad01MonitorSpotID = 5004;
+static const HotSpotID kNorad01IntakeSpotID = 5005;
+static const HotSpotID kNorad01DispenseSpotID = 5006;
+static const HotSpotID kNorad01ArSpotID = 5007;
+static const HotSpotID kNorad01CO2SpotID = 5008;
+static const HotSpotID kNorad01HeSpotID = 5009;
+static const HotSpotID kNorad01OSpotID = 5010;
+static const HotSpotID kNorad01NSpotID = 5011;
+static const HotSpotID kN01GasCanisterSpotID = 5012;
+static const HotSpotID kN01ArgonCanisterSpotID = 5013;
+static const HotSpotID kN01AirMaskSpotID = 5014;
+static const HotSpotID kN01NitrogenCanisterSpotID = 5015;
+static const HotSpotID kN01GasOutletSpotID = 5016;
+static const HotSpotID kNorad07DoorSpotID = 5017;
+static const HotSpotID kNorad07DoorOutSpotID = 5018;
+static const HotSpotID kNorad10DoorSpotID = 5019;
+static const HotSpotID kNorad10EastOutSpotID = 5020;
+static const HotSpotID kAlphaUpperPressureDoorUpSpotID = 5021;
+static const HotSpotID kAlphaUpperPressureDoorDownSpotID = 5022;
+static const HotSpotID kNorad11ElevatorSpotID = 5023;
+static const HotSpotID kNorad11ElevatorOutSpotID = 5024;
+static const HotSpotID kNorad11ElevatorDownSpotID = 5025;
+static const HotSpotID kNorad12ElevatorSpotID = 5026;
+static const HotSpotID kNorad12ElevatorOutSpotID = 5027;
+static const HotSpotID kNorad12ElevatorUpSpotID = 5028;
+static const HotSpotID kNorad19MonitorSpotID = 5029;
+static const HotSpotID kNorad19MonitorOutSpotID = 5030;
+static const HotSpotID kNorad19ActivateMonitorSpotID = 5031;
+static const HotSpotID kNorad21WestSpotID = 5032;
+static const HotSpotID kNorad21WestOutSpotID = 5033;
+static const HotSpotID kAlphaLowerPressureDoorUpSpotID = 5034;
+static const HotSpotID kAlphaLowerPressureDoorDownSpotID = 5035;
+static const HotSpotID kNorad22MonitorSpotID = 5036;
+static const HotSpotID kNorad22MonitorOutSpotID = 5037;
+static const HotSpotID kNorad22LaunchPrepSpotID = 5038;
+static const HotSpotID kNorad22ClawControlSpotID = 5039;
+static const HotSpotID kNorad22ClawPinchSpotID = 5040;
+static const HotSpotID kNorad22ClawDownSpotID = 5041;
+static const HotSpotID kNorad22ClawRightSpotID = 5042;
+static const HotSpotID kNorad22ClawLeftSpotID = 5043;
+static const HotSpotID kNorad22ClawUpSpotID = 5044;
+static const HotSpotID kNorad22ClawCCWSpotID = 5045;
+static const HotSpotID kNorad22ClawCWSpotID = 5046;
+
+// Extra sequence IDs.
+
+static const ExtraID kNoradArriveFromTSA = 0;
+static const ExtraID kNorad01RobotTaunt = 1;
+static const ExtraID kNorad01ZoomInWithGasCanister = 2;
+static const ExtraID kN01WGasCanister = 3;
+static const ExtraID kNorad01ZoomOutWithGasCanister = 4;
+static const ExtraID kN01WZEmptyLit = 5;
+static const ExtraID kN01WZGasCanisterDim = 6;
+static const ExtraID kN01WZGasCanisterLit = 7;
+static const ExtraID kN01WZArgonCanisterDim = 8;
+static const ExtraID kN01WZArgonCanisterLit = 9;
+static const ExtraID kN01WZAirMaskDim = 10;
+static const ExtraID kN01WZAirMaskLit = 11;
+static const ExtraID kN01WZNitrogenCanisterDim = 12;
+static const ExtraID kN01WZNitrogenCanisterLit = 13;
+static const ExtraID kNorad04EastDeath = 14;
+static const ExtraID kNorad19PrepSub = 15;
+static const ExtraID kNorad19ExitToSub = 16;
+static const ExtraID kNorad22SouthIntro = 17;
+static const ExtraID kNorad22SouthReply = 18;
+static const ExtraID kNorad22SouthFinish = 19;
+static const ExtraID kN22ClawFromAToB = 20;
+static const ExtraID kN22ClawALoop = 21;
+static const ExtraID kN22ClawAPinch = 22;
+static const ExtraID kN22ClawACounterclockwise = 23;
+static const ExtraID kN22ClawAClockwise = 24;
+static const ExtraID kN22ClawFromBToA = 25;
+static const ExtraID kN22ClawFromBToC = 26;
+static const ExtraID kN22ClawFromBToD = 27;
+static const ExtraID kN22ClawBLoop = 28;
+static const ExtraID kN22ClawBPinch = 29;
+static const ExtraID kN22ClawBCounterclockwise = 30;
+static const ExtraID kN22ClawBClockwise = 31;
+static const ExtraID kN22ClawFromCToB = 32;
+static const ExtraID kN22ClawCLoop = 33;
+static const ExtraID kN22ClawCPinch = 34;
+static const ExtraID kN22ClawCCounterclockwise = 35;
+static const ExtraID kN22ClawCClockwise = 36;
+static const ExtraID kN22ClawFromDToB = 37;
+static const ExtraID kN22ClawDLoop = 38;
+static const ExtraID kN22ClawDPinch = 39;
+static const ExtraID kN22ClawDCounterclockwise = 40;
+static const ExtraID kN22ClawDClockwise = 41;
+
+
+// Norad Delta Extra sequence IDs.
+
+static const ExtraID kArriveFromSubChase = 0;
+static const ExtraID kN59ZoomWithRobot = 1;
+static const ExtraID kN59RobotApproaches = 2;
+static const ExtraID kN59RobotPunchLoop = 3;
+static const ExtraID kN59PlayerWins1 = 4;
+static const ExtraID kN59PlayerWins2 = 5;
+static const ExtraID kN59RobotWins = 6;
+static const ExtraID kN59RobotHeadOpens = 7;
+static const ExtraID kN59Biochips111 = 8;
+static const ExtraID kN59Biochips011 = 9;
+static const ExtraID kN59Biochips101 = 10;
+static const ExtraID kN59Biochips001 = 11;
+static const ExtraID kN59Biochips110 = 12;
+static const ExtraID kN59Biochips010 = 13;
+static const ExtraID kN59Biochips100 = 14;
+static const ExtraID kN59Biochips000 = 15;
+static const ExtraID kN59RobotDisappears = 16;
+static const ExtraID kN60ClawFromAToB = 17;
+static const ExtraID kN60ClawALoop = 18;
+static const ExtraID kN60ClawAPinch = 19;
+static const ExtraID kN60ClawACounterclockwise = 20;
+static const ExtraID kN60ClawAClockwise = 21;
+static const ExtraID kN60ClawFromBToA = 22;
+static const ExtraID kN60ClawFromBToC = 23;
+static const ExtraID kN60ClawFromBToD = 24;
+static const ExtraID kN60ClawBLoop = 25;
+static const ExtraID kN60ClawBPinch = 26;
+static const ExtraID kN60ClawBCounterclockwise = 27;
+static const ExtraID kN60ClawBClockwise = 28;
+static const ExtraID kN60ClawFromCToB = 29;
+static const ExtraID kN60ClawCLoop = 30;
+static const ExtraID kN60ClawCPinch = 31;
+static const ExtraID kN60ClawCCounterclockwise = 32;
+static const ExtraID kN60ClawCClockwise = 33;
+static const ExtraID kN60ClawFromDToB = 34;
+static const ExtraID kN60ClawDLoop = 35;
+static const ExtraID kN60ClawDPinch = 36;
+static const ExtraID kN60ClawDCounterclockwise = 37;
+static const ExtraID kN60ClawDClockwise = 38;
+static const ExtraID kN60RobotApproaches = 39;
+static const ExtraID kN60FirstMistake = 40;
+static const ExtraID kN60ArmActivated = 41;
+static const ExtraID kN60SecondMistake = 42;
+static const ExtraID kN60ArmToPositionB = 43;
+static const ExtraID kN60ThirdMistake = 44;
+static const ExtraID kN60ArmGrabsRobot = 45;
+static const ExtraID kN60FourthMistake = 46;
+static const ExtraID kN60ArmCarriesRobotToPositionA = 47;
+static const ExtraID kN60PlayerFollowsRobotToDoor = 48;
+static const ExtraID kN60RobotHeadOpens = 49;
+static const ExtraID kN60Biochips111 = 50;
+static const ExtraID kN60Biochips011 = 51;
+static const ExtraID kN60Biochips101 = 52;
+static const ExtraID kN60Biochips001 = 53;
+static const ExtraID kN60Biochips110 = 54;
+static const ExtraID kN60Biochips010 = 55;
+static const ExtraID kN60Biochips100 = 56;
+static const ExtraID kN60Biochips000 = 57;
+static const ExtraID kN60RobotDisappears = 58;
+static const ExtraID kNoradDeltaRetinalScanBad = 59;
+static const ExtraID kNoradDeltaRetinalScanGood = 60;
+static const ExtraID kN79BrightView = 61;
+
+// Norad Delta Tables
+
+static const TimeScale kNoradDeltaMovieScale = 600;
+static const TimeScale kNoradDeltaFramesPerSecond = 15;
+static const TimeScale kNoradDeltaFrameDuration = 40;
+
+// Alternate IDs.
+
+static const AlternateID kAltNoradDeltaNormal = 0;
+
+// Room IDs.
+
+static const RoomID kNorad41 = 0;
+static const RoomID kNorad42 = 1;
+static const RoomID kNorad43 = 2;
+static const RoomID kNorad44 = 3;
+static const RoomID kNorad45 = 4;
+static const RoomID kNorad46 = 5;
+static const RoomID kNorad47 = 6;
+static const RoomID kNorad48 = 7;
+static const RoomID kNorad48South = 8;
+static const RoomID kNorad49 = 9;
+static const RoomID kNorad49South = 10;
+static const RoomID kNorad50 = 11;
+static const RoomID kNorad50East = 12;
+static const RoomID kNorad51 = 13;
+static const RoomID kNorad52 = 14;
+static const RoomID kNorad53 = 15;
+static const RoomID kNorad54 = 16;
+static const RoomID kNorad54North = 17;
+static const RoomID kNorad55 = 18;
+static const RoomID kNorad56 = 19;
+static const RoomID kNorad57 = 20;
+static const RoomID kNorad58 = 21;
+static const RoomID kNorad59 = 22;
+static const RoomID kNorad59West = 23;
+static const RoomID kNorad60 = 24;
+static const RoomID kNorad60West = 25;
+static const RoomID kNorad61 = 26;
+static const RoomID kNorad62 = 27;
+static const RoomID kNorad63 = 28;
+static const RoomID kNorad64 = 29;
+static const RoomID kNorad65 = 30;
+static const RoomID kNorad66 = 31;
+static const RoomID kNorad67 = 32;
+static const RoomID kNorad68 = 33;
+static const RoomID kNorad68West = 34;
+static const RoomID kNorad69 = 35;
+static const RoomID kNorad78 = 36;
+static const RoomID kNorad79 = 37;
+static const RoomID kNorad79West = 38;
+
+// Hot Spot Activation IDs.
+
+
+// Hot Spot IDs.
+
+static const HotSpotID kNorad48ElevatorSpotID = 5000;
+static const HotSpotID kNorad48ElevatorOutSpotID = 5001;
+static const HotSpotID kNorad48ElevatorUpSpotID = 5002;
+static const HotSpotID kNorad49ElevatorSpotID = 5003;
+static const HotSpotID kNorad49ElevatorOutSpotID = 5004;
+static const HotSpotID kNorad49ElevatorDownSpotID = 5005;
+static const HotSpotID kNorad50DoorSpotID = 5006;
+static const HotSpotID kNorad50DoorOutSpotID = 5007;
+static const HotSpotID kDeltaUpperPressureDoorUpSpotID = 5008;
+static const HotSpotID kDeltaUpperPressureDoorDownSpotID = 5009;
+static const HotSpotID kNorad54DoorSpotID = 5010;
+static const HotSpotID kNorad54DoorOutSpotID = 5011;
+static const HotSpotID kNorad59WestSpotID = 5012;
+static const HotSpotID kNorad59WestOutSpotID = 5013;
+static const HotSpotID kDeltaLowerPressureDoorUpSpotID = 5014;
+static const HotSpotID kDeltaLowerPressureDoorDownSpotID = 5015;
+static const HotSpotID kDelta59RobotHeadSpotID = 5016;
+static const HotSpotID kDelta59RobotShieldBiochipSpotID = 5017;
+static const HotSpotID kDelta59RobotOpMemBiochipSpotID = 5018;
+static const HotSpotID kDelta59RobotRetinalBiochipSpotID = 5019;
+static const HotSpotID kNorad60MonitorSpotID = 5020;
+static const HotSpotID kNorad60MonitorOutSpotID = 5021;
+static const HotSpotID kNorad60LaunchPrepSpotID = 5022;
+static const HotSpotID kNorad60ClawControlSpotID = 5023;
+static const HotSpotID kNorad60ClawPinchSpotID = 5024;
+static const HotSpotID kNorad60ClawDownSpotID = 5025;
+static const HotSpotID kNorad60ClawRightSpotID = 5026;
+static const HotSpotID kNorad60ClawLeftSpotID = 5027;
+static const HotSpotID kNorad60ClawUpSpotID = 5028;
+static const HotSpotID kNorad60ClawCCWSpotID = 5029;
+static const HotSpotID kNorad60ClawCWSpotID = 5030;
+static const HotSpotID kDelta60RobotHeadSpotID = 5031;
+static const HotSpotID kDelta60RobotShieldBiochipSpotID = 5032;
+static const HotSpotID kDelta60RobotOpMemBiochipSpotID = 5033;
+static const HotSpotID kDelta60RobotRetinalBiochipSpotID = 5034;
+static const HotSpotID kNorad68WestSpotID = 5035;
+static const HotSpotID kNorad68WestOutSpotID = 5036;
+static const HotSpotID kNorad79WestSpotID = 5037;
+static const HotSpotID kNorad79WestOutSpotID = 5038;
+static const HotSpotID kNorad79SpinLeftSpotID = 5039;
+static const HotSpotID kNorad79SpinRightSpotID = 5040;
+static const HotSpotID kNorad79SpinUpSpotID = 5041;
+static const HotSpotID kNorad79SpinDownSpotID = 5042;
+static const HotSpotID kNorad79SiloAreaSpotID = 5043;
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/norad/delta/globegame.cpp b/engines/pegasus/neighborhood/norad/delta/globegame.cpp
new file mode 100644
index 0000000000..06e40c2b3a
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/delta/globegame.cpp
@@ -0,0 +1,1062 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/cursor.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/neighborhood/norad/constants.h"
+#include "pegasus/neighborhood/norad/delta/globegame.h"
+#include "pegasus/neighborhood/norad/delta/noraddelta.h"
+
+namespace Pegasus {
+
+static const TimeValue kDurationPerFrame = 600 / 15;
+static const TimeValue kDurationPerRow = kNumLongSlices * kDurationPerFrame;
+static const short kVerticalDuration = 16;
+
+GlobeTracker::GlobeTracker(Movie *globeMovie, Picture *leftHighlight, Picture *rightHighlight,
+ Picture *upHighlight, Picture *downHighlight) {
+ _globeMovie = globeMovie;
+ _leftHighlight = leftHighlight;
+ _rightHighlight = rightHighlight;
+ _upHighlight = upHighlight;
+ _downHighlight = downHighlight;
+}
+
+void GlobeTracker::setTrackParameters(const Hotspot *trackSpot, GlobeTrackDirection direction) {
+ _trackSpot = trackSpot;
+ _trackDirection = direction;
+
+ TimeValue time, newTime, start;
+
+ switch (_trackDirection) {
+ case kTrackLeft:
+ time = _globeMovie->getTime();
+
+ if (((time / kDurationPerRow) & 1) == 0) {
+ start = (time / kDurationPerRow + 1) * kDurationPerRow;
+ newTime = start + kDurationPerRow - time % kDurationPerRow;
+ } else {
+ start = (time / kDurationPerRow) * kDurationPerRow;
+ newTime = time;
+ }
+
+ _globeMovie->setSegment(start, start + kDurationPerRow);
+
+ if (newTime != time) {
+ _globeMovie->setTime(newTime);
+ _globeMovie->redrawMovieWorld();
+ }
+
+ _globeMovie->setFlags(kLoopTimeBase);
+ break;
+ case kTrackRight:
+ time = _globeMovie->getTime();
+
+ if (((time / kDurationPerRow) & 1) == 0) {
+ start = (time / kDurationPerRow) * kDurationPerRow;
+ newTime = time;
+ } else {
+ start = (time / kDurationPerRow - 1) * kDurationPerRow;
+ newTime = start + kDurationPerRow - time % kDurationPerRow;
+ }
+
+ _globeMovie->setSegment(start, start + kDurationPerRow);
+
+ if (newTime != time) {
+ _globeMovie->setTime(newTime);
+ _globeMovie->redrawMovieWorld();
+ }
+
+ _globeMovie->setFlags(kLoopTimeBase);
+ break;
+ case kTrackUp:
+ case kTrackDown:
+ _globeMovie->setSegment(0, _globeMovie->getDuration());
+ _globeMovie->setFlags(0);
+ break;
+ }
+}
+
+void GlobeTracker::activateHotspots() {
+ Tracker::activateHotspots();
+
+ if (_trackSpot)
+ g_allHotspots.activateOneHotspot(_trackSpot->getObjectID());
+}
+
+bool GlobeTracker::stopTrackingInput(const Input &input) {
+ return !JMPPPInput::isPressingInput(input);
+}
+
+void GlobeTracker::continueTracking(const Input &input) {
+ Common::Point where;
+ input.getInputLocation(where);
+
+ if (g_allHotspots.findHotspot(where) == _trackSpot)
+ trackGlobeMovie();
+ else
+ stopGlobeMovie();
+}
+
+void GlobeTracker::startTracking(const Input &input) {
+ Tracker::startTracking(input);
+ trackGlobeMovie();
+}
+
+void GlobeTracker::stopTracking(const Input &input) {
+ Tracker::stopTracking(input);
+ stopGlobeMovie();
+}
+
+void GlobeTracker::trackGlobeMovie() {
+ TimeValue time;
+
+ switch (_trackDirection) {
+ case kTrackLeft:
+ if (!_globeMovie->isRunning())
+ _globeMovie->start();
+
+ _leftHighlight->show();
+ break;
+ case kTrackRight:
+ if (!_globeMovie->isRunning())
+ _globeMovie->start();
+
+ _rightHighlight->show();
+ break;
+ case kTrackUp:
+ time = _globeMovie->getTime();
+
+ if (_trackTime == 0) {
+ _trackTime = tickCount();
+ } else if ((int)time - (int)kDurationPerRow * 2 >= 0 && (int)tickCount() >= _trackTime + kVerticalDuration) {
+ _trackTime = tickCount();
+ _globeMovie->setTime(time - kDurationPerRow * 2);
+ _globeMovie->redrawMovieWorld();
+ }
+
+ _upHighlight->show();
+ break;
+ case kTrackDown:
+ time = _globeMovie->getTime();
+
+ if (_trackTime == 0) {
+ _trackTime = tickCount();
+ } else if (time + kDurationPerRow * 2 < _globeMovie->getDuration() && (int)tickCount() >= _trackTime + kVerticalDuration) {
+ _trackTime = tickCount();
+ _globeMovie->setTime(time + kDurationPerRow * 2);
+ _globeMovie->redrawMovieWorld();
+ }
+
+ _downHighlight->show();
+ break;
+ }
+}
+
+void GlobeTracker::stopGlobeMovie() {
+ switch (_trackDirection) {
+ case kTrackLeft:
+ _leftHighlight->hide();
+ _globeMovie->stop();
+ break;
+ case kTrackRight:
+ _rightHighlight->hide();
+ _globeMovie->stop();
+ break;
+ case kTrackUp:
+ _upHighlight->hide();
+ _trackTime = tickCount() - kVerticalDuration;
+ break;
+ case kTrackDown:
+ _downHighlight->hide();
+ _trackTime = tickCount() - kVerticalDuration;
+ break;
+ }
+}
+
+// Globe game PICTs:
+static const ResIDType kGlobeCircleLeftPICTID = 300;
+static const ResIDType kGlobeCircleRightPICTID = 301;
+static const ResIDType kGlobeCircleUpPICTID = 302;
+static const ResIDType kGlobeCircleDownPICTID = 303;
+static const ResIDType kTargetUpperLeftPICTID = 304;
+static const ResIDType kTargetUpperRightPICTID = 305;
+static const ResIDType kTargetLowerLeftPICTID = 306;
+static const ResIDType kTargetLowerRightPICTID = 307;
+static const ResIDType kMotionHiliteLeftPICTID = 308;
+static const ResIDType kMotionHiliteRightPICTID = 309;
+static const ResIDType kMotionHiliteUpPICTID = 310;
+static const ResIDType kMotionHiliteDownPICTID = 311;
+
+static const ResIDType kGlobeCountdownDigitsID = 350;
+
+static const int kGlobeCountdownWidth = 28;
+static const int kGlobeCountdownHeight = 12;
+static const int kGlobeCountdownOffset1 = 12;
+static const int kGlobeCountdownOffset2 = 20;
+
+GlobeCountdown::GlobeCountdown(const DisplayElementID id) : IdlerAnimation(id) {
+ _digits.getImageFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kGlobeCountdownDigitsID);
+
+ Common::Rect r;
+ _digits.getSurfaceBounds(r);
+ _digitOffset = r.width() / 10;
+ setScale(1);
+ sizeElement(kGlobeCountdownWidth, kGlobeCountdownHeight);
+}
+
+void GlobeCountdown::setDisplayOrder(const DisplayOrder order) {
+ IdlerAnimation::setDisplayOrder(order);
+}
+
+void GlobeCountdown::show() {
+ IdlerAnimation::show();
+}
+
+void GlobeCountdown::hide() {
+ IdlerAnimation::hide();
+}
+
+void GlobeCountdown::moveElementTo(const CoordType x, const CoordType y) {
+ IdlerAnimation::moveElementTo(x, y);
+}
+
+void GlobeCountdown::setCountdownTime(const int numSeconds) {
+ stop();
+ setSegment(0, numSeconds);
+ setTime(numSeconds);
+}
+
+void GlobeCountdown::startCountdown() {
+ setRate(-1);
+}
+
+void GlobeCountdown::stopCountdown() {
+ stop();
+}
+
+void GlobeCountdown::draw(const Common::Rect &) {
+ Common::Rect r1;
+ _digits.getSurfaceBounds(r1);
+ r1.right = r1.left + _digitOffset;
+ Common::Rect r2 = r1;
+ TimeValue time = getTime();
+
+ Common::Rect bounds;
+ getBounds(bounds);
+
+ if (time > 60 * 9 + 59) {
+ r2.moveTo(bounds.left, bounds.top);
+ r1.moveTo(9 * _digitOffset, 0);
+ _digits.copyToCurrentPort(r1, r2);
+
+ r2.moveTo(bounds.left + kGlobeCountdownOffset1, bounds.top);
+ r1.moveTo(5 * _digitOffset, 0);
+ _digits.copyToCurrentPort(r1, r2);
+
+ r2.moveTo(bounds.left + kGlobeCountdownOffset2, bounds.top);
+ r1.moveTo(9 * _digitOffset, 0);
+ _digits.copyToCurrentPort(r1, r2);
+ } else {
+ r2.moveTo(bounds.left, bounds.top);
+ r1.moveTo((time / 60) * _digitOffset, 0);
+ _digits.copyToCurrentPort(r1, r2);
+
+ time %= 60;
+ r2.moveTo(bounds.left + kGlobeCountdownOffset1, bounds.top);
+ r1.moveTo((time / 10) * _digitOffset, 0);
+ _digits.copyToCurrentPort(r1, r2);
+
+ r2.moveTo(bounds.left + kGlobeCountdownOffset2, bounds.top);
+ r1.moveTo((time % 10) * _digitOffset, 0);
+ _digits.copyToCurrentPort(r1, r2);
+ }
+}
+
+const int16 GlobeGame::_siloCoords[kNumAllSilos][2] = {
+ { 60, -151 }, // Anchorage, Alaska
+ { 6, 39 }, // Addis Ababa, Ethiopia
+ { -22, 44 }, // Antaro, Madagascar
+ { 30, -83 }, // Atlanta, Georgia
+ { -41, 173 }, // Auckland, New Zealand
+ { 39, -78 }, // Baltimore, Maryland
+ { 11, 101 }, // Bangkok, Thailand
+ { 2, -75 }, // Bogota, Colombia
+ { 46, 4 }, // Bonn, Germany
+ { 51, -7 }, // Dublin, Ireland
+ { 28, -1 }, // El Menia, Algeria
+ { 67, -111 }, // Ellesmere, Canada
+ { 43, -107 }, // Glasgow, Montana
+ { 61, -48 }, // Godthab, Greenland
+ { 19, -157 }, // Honolulu, Hawaii
+ { 6, 5 }, // Ibadan, Nigeria
+ { -29, 26 }, // Johannesburg, South Africa
+ { 46, 92 }, // Kobdo, Mongolia
+ { -15, -63 }, // La Paz, Bolivia
+ { -35, -61 }, // La Plata, Argentina
+ { -9, -76 }, // Lima, Peru
+ { 38, -4 }, // Madrid, Spain
+ { -8, -51 }, // Manaus, Brazil
+ { 13, 120 }, // Manila, Phillipines
+ { -35, 143 }, // Melbourne, Australia
+ { 60, -161 }, // Nome, Alaska
+ { -7, 142 }, // Papua, New Guinea
+ { -32, 117 }, // Perth, West Australia
+ { 34, -114 }, // Phoenix, Arizona
+ { 18, -71 }, // Port-Au-Prince, Haiti
+ { 42, -121 }, // Portland, Oregon
+ { 61, -20 }, // Reykjavik, Iceland
+ { -22, -46 }, // Rio de Janeiro
+ { 27, -101 }, // San Antonio, Texas
+ { 34, 126 }, // Seoul, Korea
+ { 37, -87 }, // Saint Louis, Missouri
+ { 60, 30 }, // Saint Petersberg, Russia
+ { 56, 12 }, // Stockholm, Sweden
+ { 51, 105 }, // Svortalsk, Siberia
+ { 36, -96 } // Tulsa, Oklahoma
+};
+
+const int16 GlobeGame::_targetSilo[kNumTargetSilos] = {
+ 14, 9, 1, 33, 6, 8, 34, 31, 38, 21
+};
+
+const short GlobeGame::_timeLimit[kNumTargetSilos] = {
+ 120, 110, 100, 90, 80, 70, 60, 50, 40, 30
+};
+
+const TimeValue GlobeGame::_siloName[kNumTargetSilos][2] = {
+ { kHonoluluIn, kHonoluluOut },
+ { kDublinIn, kDublinOut },
+ { kAddisAbabaIn, kAddisAbabaOut },
+ { kSanAntonioIn, kSanAntonioOut },
+ { kBangkokIn, kBangkokOut },
+ { kBonnIn, kBonnOut },
+ { kSeoulIn, kSeoulOut },
+ { kReykjavikIn, kReykjavikOut },
+ { kSvortalskIn, kSvortalskOut },
+ { kMadridIn, kMadridOut }
+};
+
+// From globe room models
+
+static const GlobeGame::Point3D kCameraLocation = { 0.53f, 4.4f, -0.86f };
+static const GlobeGame::Point3D kGlobeCenter = { -31.5f, 8.0f, 0.0f };
+static const float kGlobeRadius = 8.25f;
+static const int16 kDegreesPerLongSlice = 360 / kNumLongSlices;
+static const int16 kDegreesPerLatSlice = 25;
+static const int16 kLongOrigin = -95;
+
+// Other constants.
+
+static const float kTanFieldOfView = 0.7082373180482f;
+static const float kPicturePlaneDistance = 10.0f; // Completely arbitrary.
+static const int16 kLatError = 2;
+static const int16 kLongError = 2;
+static const TimeValue kGlobeMovieStartTime = 2 * 2 * kNumLongSlices * 600 / 15;
+
+static const TimeValue kTimePerGlobeFrame = 40;
+
+static const NotificationFlags kGlobeSplash1Finished = 1;
+static const NotificationFlags kGlobeTimerExpired = kGlobeSplash1Finished << 1;
+static const NotificationFlags kMaxDeactivatedFinished = kGlobeTimerExpired << 1;
+
+static const NotificationFlags kGlobeNotificationFlags = kGlobeSplash1Finished |
+ kGlobeTimerExpired |
+ kMaxDeactivatedFinished;
+
+static const int16 kSplash1End = 4;
+static const int16 kSplash2End = 5;
+static const int16 kSplash3Start = 8;
+static const int16 kSplash3Stop = 9;
+static const int16 kSplash4Start = 9;
+static const int16 kSplash4Stop = 10;
+static const int16 kNewLaunchSiloTime = 10;
+static const int16 kSiloDeactivatedTime = 11;
+static const int16 kMissileLaunchedTime = 12;
+static const int16 kMaxDeactivatedStart = 13;
+static const int16 kMaxDeactivatedStop = 23;
+
+static const int16 kGamePlaying = 1;
+static const int16 kGameOver = 2;
+
+enum {
+ kGameIntro,
+ kPlayingRobotIntro,
+ kPlayingStrikeAuthorized,
+ kPlayingPrimaryTarget,
+ kPlayingNewSilo1,
+ kPlayingNewSilo2,
+ kPlayingNewSilo3,
+ kPlayingTime,
+ kPlayingInstructions,
+ kWaitingForPlayer,
+ kSiloDeactivated,
+ kRobotTaunting,
+ kDelayingPlayer,
+ kPlayerWon1,
+ kPlayerWon2,
+ kPlayerLost1
+};
+
+// TODO: Use ScummVM equivalent
+static const float kPI = 3.1415926535f;
+
+float degreesToRadians(float angle) {
+ return (angle * kPI) / 180;
+}
+
+float radiansToDegrees(float angle) {
+ return (angle * 180) / kPI;
+}
+
+GlobeGame::GlobeGame(Neighborhood *handler) : GameInteraction(kNoradGlobeGameInteractionID, handler),
+ _monitorMovie(kGlobeMonitorID), _globeMovie(kGlobeMovieID), _upperNamesMovie(kGlobeUpperNamesID),
+ _lowerNamesMovie(kGlobeLowerNamesID), _globeNotification(kNoradGlobeNotificationID, (PegasusEngine *)g_engine),
+ _globeCircleLeft(kGlobeCircleLeftID), _globeCircleRight(kGlobeCircleRightID),
+ _globeCircleUp(kGlobeCircleUpID), _globeCircleDown(kGlobeCircleDownID),
+ _motionHighlightLeft(kMotionHiliteLeftID), _motionHighlightRight(kMotionHiliteRightID),
+ _motionHighlightUp(kMotionHiliteUpID), _motionHighlightDown(kMotionHiliteDownID),
+ _targetHighlightUpperLeft(kTargetHiliteUpperLeftID), _targetHighlightUpperRight(kTargetHiliteUpperRightID),
+ _targetHighlightLowerLeft(kTargetHiliteLowerLeftID), _targetHighlightLowerRight(kTargetHiliteLowerRightID),
+ _globeTracker(&_globeMovie, &_motionHighlightLeft, &_motionHighlightRight, &_motionHighlightUp,
+ &_motionHighlightDown), _countdown(kGlobeCountdownID) {
+ _neighborhoodNotification = handler->getNeighborhoodNotification();
+}
+
+void GlobeGame::openInteraction() {
+ _monitorMovie.initFromMovieFile("Images/Norad Delta/N79 Left Monitor");
+ _monitorMovie.moveElementTo(kGlobeMonitorLeft, kGlobeMonitorTop);
+ _monitorMovie.setDisplayOrder(kGlobeMonitorLayer);
+ _monitorMovie.startDisplaying();
+ _monitorMovie.setSegment(0, kSplash1End * _monitorMovie.getScale());
+ _monitorMovie.show();
+
+ _monitorCallBack.setNotification(&_globeNotification);
+ _monitorCallBack.initCallBack(&_monitorMovie, kCallBackAtExtremes);
+ _monitorCallBack.setCallBackFlag(kGlobeSplash1Finished);
+ _monitorCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+
+ _upperNamesMovie.initFromMovieFile("Images/Norad Delta/Upper Names");
+ _upperNamesMovie.moveElementTo(kGlobeUpperNamesLeft, kGlobeUpperNamesTop);
+ _upperNamesMovie.setDisplayOrder(kGlobeUpperNamesLayer);
+ _upperNamesMovie.startDisplaying();
+
+ _lowerNamesMovie.initFromMovieFile("Images/Norad Delta/Lower Names");
+ _lowerNamesMovie.moveElementTo(kGlobeLowerNamesLeft, kGlobeLowerNamesTop);
+ _lowerNamesMovie.setDisplayOrder(kGlobeLowerNamesLayer);
+ _lowerNamesMovie.startDisplaying();
+
+ _globeMovie.initFromMovieFile("Images/Norad Delta/Spinning Globe");
+ _globeMovie.moveElementTo(kGlobeLeft, kGlobeTop);
+ _globeMovie.setDisplayOrder(kGlobeMovieLayer);
+ _globeMovie.startDisplaying();
+ _globeMovie.setTime(kGlobeMovieStartTime);
+ _globeMovie.redrawMovieWorld();
+
+ _globeCircleLeft.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kGlobeCircleLeftPICTID, true);
+ _globeCircleLeft.moveElementTo(kGlobeCircleLeftLeft, kGlobeCircleLeftTop);
+ _globeCircleLeft.setDisplayOrder(kGlobeCircleLayer);
+ _globeCircleLeft.startDisplaying();
+
+ _globeCircleRight.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kGlobeCircleRightPICTID, true);
+ _globeCircleRight.moveElementTo(kGlobeCircleRightLeft, kGlobeCircleRightTop);
+ _globeCircleRight.setDisplayOrder(kGlobeCircleLayer);
+ _globeCircleRight.startDisplaying();
+
+ _globeCircleUp.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kGlobeCircleUpPICTID, true);
+ _globeCircleUp.moveElementTo(kGlobeCircleUpLeft, kGlobeCircleUpTop);
+ _globeCircleUp.setDisplayOrder(kGlobeCircleLayer);
+ _globeCircleUp.startDisplaying();
+
+ _globeCircleDown.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kGlobeCircleDownPICTID, true);
+ _globeCircleDown.moveElementTo(kGlobeCircleDownLeft, kGlobeCircleDownTop);
+ _globeCircleDown.setDisplayOrder(kGlobeCircleLayer);
+ _globeCircleDown.startDisplaying();
+
+ _motionHighlightLeft.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kMotionHiliteLeftPICTID, true);
+ _motionHighlightLeft.moveElementTo(kGlobeLeftMotionHiliteLeft, kGlobeLeftMotionHiliteTop);
+ _motionHighlightLeft.setDisplayOrder(kGlobeHilitesLayer);
+ _motionHighlightLeft.startDisplaying();
+
+ _motionHighlightRight.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kMotionHiliteRightPICTID, true);
+ _motionHighlightRight.moveElementTo(kGlobeRightMotionHiliteLeft, kGlobeRightMotionHiliteTop);
+ _motionHighlightRight.setDisplayOrder(kGlobeCircleLayer);
+ _motionHighlightRight.startDisplaying();
+
+ _motionHighlightUp.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kMotionHiliteUpPICTID, true);
+ _motionHighlightUp.moveElementTo(kGlobeUpMotionHiliteLeft, kGlobeUpMotionHiliteTop);
+ _motionHighlightUp.setDisplayOrder(kGlobeHilitesLayer);
+ _motionHighlightUp.startDisplaying();
+
+ _motionHighlightDown.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kMotionHiliteDownPICTID, true);
+ _motionHighlightDown.moveElementTo(kGlobeDownMotionHiliteLeft, kGlobeDownMotionHiliteTop);
+ _motionHighlightDown.setDisplayOrder(kGlobeHilitesLayer);
+ _motionHighlightDown.startDisplaying();
+
+ _targetHighlightUpperLeft.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kTargetUpperLeftPICTID, true);
+ _targetHighlightUpperLeft.moveElementTo(kGlobeUpperLeftHiliteLeft, kGlobeUpperLeftHiliteTop);
+ _targetHighlightUpperLeft.setDisplayOrder(kGlobeHilitesLayer);
+ _targetHighlightUpperLeft.startDisplaying();
+
+ _targetHighlightUpperRight.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kTargetUpperRightPICTID, true);
+ _targetHighlightUpperRight.moveElementTo(kGlobeUpperRightHiliteLeft, kGlobeUpperRightHiliteTop);
+ _targetHighlightUpperRight.setDisplayOrder(kGlobeHilitesLayer);
+ _targetHighlightUpperRight.startDisplaying();
+
+ _targetHighlightLowerLeft.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kTargetLowerLeftPICTID, true);
+ _targetHighlightLowerLeft.moveElementTo(kGlobeLowerLeftHiliteLeft, kGlobeLowerLeftHiliteTop);
+ _targetHighlightLowerLeft.setDisplayOrder(kGlobeHilitesLayer);
+ _targetHighlightLowerLeft.startDisplaying();
+
+ _targetHighlightLowerRight.initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kTargetLowerRightPICTID, true);
+ _targetHighlightLowerRight.moveElementTo(kGlobeLowerRightHiliteLeft, kGlobeLowerRightHiliteTop);
+ _targetHighlightLowerRight.setDisplayOrder(kGlobeHilitesLayer);
+ _targetHighlightLowerRight.startDisplaying();
+
+ _countdown.setDisplayOrder(kGlobeCountdownLayer);
+ _countdown.moveElementTo(kGlobeCountdownLeft, kGlobeCountdownTop);
+ _countdown.startDisplaying();
+ _countdown.setCountdownTime(_timeLimit[0]);
+
+ _countdownCallBack.setNotification(&_globeNotification);
+ _countdownCallBack.initCallBack(&_countdown, kCallBackAtExtremes);
+ _countdownCallBack.setCallBackFlag(kGlobeTimerExpired);
+ _countdownCallBack.scheduleCallBack(kTriggerAtStart, 0, 0);
+
+ _globeNotification.notifyMe(this, kGlobeNotificationFlags, kGlobeNotificationFlags);
+
+ _gameState = kGameIntro;
+ _currentSiloIndex = 0;
+ _playedInstructions = false;
+
+ _neighborhoodNotification->notifyMe(this, kDelayCompletedFlag | kSpotSoundCompletedFlag, kDelayCompletedFlag | kSpotSoundCompletedFlag);
+}
+
+void GlobeGame::initInteraction() {
+ _monitorMovie.start();
+ _monitorMovie.redrawMovieWorld();
+}
+
+void GlobeGame::closeInteraction() {
+ _monitorMovie.stop();
+ _monitorMovie.stopDisplaying();
+ _monitorMovie.releaseMovie();
+ _monitorCallBack.releaseCallBack();
+
+ _globeMovie.stop();
+ _globeMovie.stopDisplaying();
+ _globeMovie.releaseMovie();
+ _globeNotification.cancelNotification(this);
+
+ _upperNamesMovie.stop();
+ _upperNamesMovie.stopDisplaying();
+ _upperNamesMovie.releaseMovie();
+
+ _lowerNamesMovie.stop();
+ _lowerNamesMovie.stopDisplaying();
+ _lowerNamesMovie.releaseMovie();
+
+ _countdown.hide();
+ _countdown.stopDisplaying();
+ _countdownCallBack.releaseCallBack();
+
+ _globeCircleLeft.stopDisplaying();
+ _globeCircleLeft.deallocateSurface();
+ _globeCircleRight.stopDisplaying();
+ _globeCircleRight.deallocateSurface();
+ _globeCircleUp.stopDisplaying();
+ _globeCircleUp.deallocateSurface();
+ _globeCircleDown.stopDisplaying();
+ _globeCircleDown.deallocateSurface();
+
+ _motionHighlightLeft.stopDisplaying();
+ _motionHighlightLeft.deallocateSurface();
+ _motionHighlightRight.stopDisplaying();
+ _motionHighlightRight.deallocateSurface();
+ _motionHighlightUp.stopDisplaying();
+ _motionHighlightUp.deallocateSurface();
+ _motionHighlightDown.stopDisplaying();
+ _motionHighlightDown.deallocateSurface();
+
+ _targetHighlightUpperLeft.stopDisplaying();
+ _targetHighlightUpperLeft.deallocateSurface();
+ _targetHighlightUpperRight.stopDisplaying();
+ _targetHighlightUpperRight.deallocateSurface();
+ _targetHighlightLowerLeft.stopDisplaying();
+ _targetHighlightLowerLeft.deallocateSurface();
+ _targetHighlightLowerRight.stopDisplaying();
+ _targetHighlightLowerRight.deallocateSurface();
+
+ _neighborhoodNotification->cancelNotification(this);
+}
+
+void GlobeGame::receiveNotification(Notification *notification, const NotificationFlags flags) {
+ TimeScale scale = _monitorMovie.getScale();
+
+ if (notification == _neighborhoodNotification) {
+ switch (_gameState) {
+ case kPlayingRobotIntro:
+ _monitorMovie.stop();
+ _monitorMovie.setSegment(0, _monitorMovie.getDuration());
+ _monitorMovie.setTime(kSplash2End * scale - 1);
+ _monitorMovie.setFlags(0);
+
+ _owner->requestDelay(1, 2, kFilterNoInput, 0);
+ _owner->requestSpotSound(kStrikeAuthorizedIn, kStrikeAuthorizedOut,
+ kFilterNoInput, kSpotSoundCompletedFlag);
+ _gameState = kPlayingStrikeAuthorized;
+ break;
+ case kPlayingStrikeAuthorized:
+ _monitorMovie.setSegment(kSplash3Start * scale, kSplash3Stop * scale);
+ _monitorMovie.setTime(kSplash3Start * scale);
+ _monitorMovie.redrawMovieWorld();
+
+ _owner->requestDelay(1, 3, kFilterNoInput, 0);
+ _owner->requestSpotSound(kPrimaryTargetIn, kPrimaryTargetOut, kFilterNoInput, 0);
+ _owner->requestDelay(1, 5, kFilterNoInput, kDelayCompletedFlag);
+ _monitorMovie.start();
+ _gameState = kPlayingPrimaryTarget;
+ break;
+ case kPlayingPrimaryTarget:
+ _monitorMovie.stop();
+ _monitorMovie.setSegment(0, _monitorMovie.getDuration());
+ _monitorMovie.setTime(kNewLaunchSiloTime * scale);
+ _owner->requestSpotSound(kNewLaunchSiloIn, kNewLaunchSiloOut, kFilterNoInput,
+ kSpotSoundCompletedFlag);
+ _gameState = kPlayingNewSilo1;
+ break;
+ case kPlayingNewSilo1:
+ _monitorMovie.stop();
+ _monitorMovie.setSegment(0, _monitorMovie.getDuration());
+ _owner->requestDelay(1, 3, kFilterNoInput, kDelayCompletedFlag);
+ _gameState = kPlayingNewSilo2;
+ break;
+ case kPlayingNewSilo2:
+ _upperNamesMovie.show();
+ _upperNamesMovie.setTime(_currentSiloIndex * _upperNamesMovie.getScale());
+ _upperNamesMovie.redrawMovieWorld();
+ _monitorMovie.setTime(kSplash4Stop * scale - 1);
+ _monitorMovie.redrawMovieWorld();
+ _owner->requestSpotSound(_siloName[_currentSiloIndex][0], _siloName[_currentSiloIndex][1], kFilterNoInput, 0);
+ _owner->requestDelay(1, 3, kFilterNoInput, 0);
+ _owner->requestSpotSound(kLaunchToProceedIn, kLaunchToProceedOut, kFilterNoInput, 0);
+ _owner->requestDelay(1, 5, kFilterNoInput, kDelayCompletedFlag);
+ _gameState = kPlayingNewSilo3;
+ break;
+ case kPlayingNewSilo3:
+ _countdown.stopCountdown();
+ _countdown.setCountdownTime(_timeLimit[_currentSiloIndex]);
+ _countdown.show();
+ _gameState = kPlayingTime;
+
+ if (_timeLimit[_currentSiloIndex] >= 120)
+ _owner->requestSpotSound(kTwoMinutesIn, kTwoMinutesOut, kFilterNoInput, 0);
+ else if (_timeLimit[_currentSiloIndex] >= 60)
+ _owner->requestSpotSound(kOneMinuteIn, kOneMinuteOut, kFilterNoInput, 0);
+
+ switch (_timeLimit[_currentSiloIndex] % 60) {
+ case 0:
+ _owner->requestDelay(1, 5, kFilterNoInput, kDelayCompletedFlag);
+ break;
+ case 10:
+ _owner->requestDelay(1, 5, kFilterNoInput, 0);
+ _owner->requestSpotSound(kTenSecondsIn, kTenSecondsOut, kFilterNoInput,
+ kSpotSoundCompletedFlag);
+ break;
+ case 20:
+ _owner->requestDelay(1, 5, kFilterNoInput, 0);
+ _owner->requestSpotSound(kTwentySecondsIn, kTwentySecondsOut,
+ kFilterNoInput, kSpotSoundCompletedFlag);
+ break;
+ case 30:
+ _owner->requestDelay(1, 5, kFilterNoInput, 0);
+ _owner->requestSpotSound(kThirtySecondsIn, kThirtySecondsOut,
+ kFilterNoInput, kSpotSoundCompletedFlag);
+ break;
+ case 40:
+ _owner->requestDelay(1, 5, kFilterNoInput, 0);
+ _owner->requestSpotSound(kFortySecondsIn, kFortySecondsOut,
+ kFilterNoInput, kSpotSoundCompletedFlag);
+ break;
+ case 50:
+ _owner->requestDelay(1, 5, kFilterNoInput, 0);
+ _owner->requestSpotSound(kFiftySecondsIn, kFiftySecondsOut,
+ kFilterNoInput, kSpotSoundCompletedFlag);
+ break;
+ }
+ case kPlayingTime:
+ _gameState = kPlayingInstructions;
+ _globeMovie.show();
+ _globeCircleLeft.show();
+ _globeCircleRight.show();
+ _globeCircleUp.show();
+ _globeCircleDown.show();
+
+ if (_playedInstructions) {
+ receiveNotification(notification, flags);
+ } else {
+ _owner->requestSpotSound(kToDeactivateIn, kToDeactivateOut, kFilterNoInput,
+ kSpotSoundCompletedFlag);
+ _playedInstructions = true;
+ }
+ break;
+ case kPlayingInstructions:
+ _gameState = kWaitingForPlayer;
+ _countdown.startCountdown();
+ break;
+ case kSiloDeactivated:
+ _gameState = kRobotTaunting;
+
+ switch (_currentSiloIndex) {
+ case 3:
+ _owner->requestSpotSound(kYouCannotPossiblyIn, kYouCannotPossiblyOut,
+ kFilterNoInput, kSpotSoundCompletedFlag);
+ break;
+ case 5:
+ _owner->requestSpotSound(kYouWillFailIn, kYouWillFailOut, kFilterNoInput,
+ kSpotSoundCompletedFlag);
+ break;
+ case 7:
+ _owner->requestSpotSound(kGiveUpHumanIn, kGiveUpHumanOut, kFilterNoInput,
+ kSpotSoundCompletedFlag);
+ break;
+ case 9:
+ _owner->requestSpotSound(kYouAreRunningIn, kYouAreRunningOut,
+ kFilterNoInput, kSpotSoundCompletedFlag);
+ break;
+ default:
+ _owner->requestSpotSound(kNewLaunchSiloIn, kNewLaunchSiloOut,
+ kFilterNoInput, kSpotSoundCompletedFlag);
+ _monitorMovie.setTime(kNewLaunchSiloTime * scale);
+ _monitorMovie.redrawMovieWorld();
+ _gameState = kPlayingNewSilo1;
+ break;
+ }
+ break;
+ case kRobotTaunting:
+ _owner->requestDelay(1, 1, kFilterNoInput, 0);
+ _owner->requestSpotSound(kNewLaunchSiloIn, kNewLaunchSiloOut, kFilterNoInput, kSpotSoundCompletedFlag);
+ _monitorMovie.setTime(kNewLaunchSiloTime * scale);
+ _monitorMovie.redrawMovieWorld();
+ _gameState = kPlayingNewSilo1;
+ break;
+ case kDelayingPlayer:
+ _gameState = kWaitingForPlayer;
+ break;
+ case kPlayerLost1:
+ _owner->recallToTSAFailure();
+ break;
+ case kPlayerWon2:
+ ((NoradDelta *)_owner)->finishedGlobeGame();
+ _owner->requestDeleteCurrentInteraction();
+ break;
+ default:
+ break;
+ }
+ } else if (notification == &_globeNotification) {
+ ExtraTable::Entry entry;
+
+ switch (flags) {
+ case kGlobeSplash1Finished:
+ _owner->getExtraEntry(kN79BrightView, entry);
+ _monitorMovie.stop();
+ _monitorMovie.setSegment(kSplash1End * scale, kSplash2End * scale);
+ _monitorMovie.setFlags(kLoopTimeBase);
+ _monitorMovie.start();
+ _owner->showViewFrame(entry.movieStart);
+ _owner->requestSpotSound(kIJustBrokeIn, kIJustBrokeOut, kFilterNoInput, 0);
+ _owner->requestDelay(1, 2, kFilterNoInput, kDelayCompletedFlag);
+ _gameState = kPlayingRobotIntro;
+ break;
+ case kGlobeTimerExpired:
+ // Missile launched, player loses.
+ _owner->requestSpotSound(kMissileLaunchedIn, kMissileLaunchedOut, kFilterNoInput, kSpotSoundCompletedFlag);
+ _gameState = kPlayerLost1;
+ break;
+ case kMaxDeactivatedFinished:
+ _monitorMovie.stop();
+ _monitorMovie.setSegment(0, _monitorMovie.getDuration());
+ _owner->requestDelay(1, 2, kFilterNoInput, 0);
+ _owner->requestSpotSound(kTheOnlyGoodHumanIn, kTheOnlyGoodHumanOut, kFilterNoInput, 0);
+ _owner->requestDelay(1, 2, kFilterNoInput, kDelayCompletedFlag);
+ _gameState = kPlayerWon2;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+// Prevent the player from getting up until the game is over.
+
+void GlobeGame::handleInput(const Input &input, const Hotspot *cursorSpot) {
+ Common::Point where;
+ input.getInputLocation(where);
+ Hotspot *spot = g_allHotspots.findHotspot(where);
+
+ if (((PegasusEngine *)g_engine)->_cursor->isVisible() && spot != 0 &&
+ spot->getObjectID() == kNorad79SiloAreaSpotID && findClickedSilo(input) != -1) {
+ _targetHighlightUpperLeft.show();
+ _targetHighlightUpperRight.show();
+ _targetHighlightLowerLeft.show();
+ _targetHighlightLowerRight.show();
+ } else {
+ _targetHighlightUpperLeft.hide();
+ _targetHighlightUpperRight.hide();
+ _targetHighlightLowerLeft.hide();
+ _targetHighlightLowerRight.hide();
+ }
+
+ // Interrupt certain inputs to prevent player from switching modes.
+ InputHandler::handleInput(input, cursorSpot);
+}
+
+int16 GlobeGame::findClickedSilo(const Input &input) {
+ Common::Point screenPoint;
+ input.getInputLocation(screenPoint);
+ screenPoint.x -= kNavAreaLeft;
+ screenPoint.y -= kNavAreaTop;
+
+ Line3D ray;
+ screenPointTo3DPoint(screenPoint.x, screenPoint.y, ray.pt2);
+ ray.pt1 = kCameraLocation;
+
+ Point3D globePoint;
+ if (lineHitsGlobe(ray, globePoint)) {
+ int16 latOrigin, longOrigin, latitude, longitude;
+ globeMovieFrameToOrigin(_globeMovie.getTime() / kTimePerGlobeFrame, latOrigin, longOrigin);
+ globePointToLatLong(globePoint, latOrigin, longOrigin, latitude, longitude);
+
+ for (int16 i = 0; i < kNumAllSilos; i++)
+ if (_siloCoords[i][0] >= latitude - kLatError && _siloCoords[i][0] <= latitude + kLatError &&
+ _siloCoords[i][1] >= longitude - kLongError && _siloCoords[i][1] <= longitude + kLongError)
+ return i;
+ }
+
+ return -1;
+}
+
+void GlobeGame::spinGlobe(const Input &input, const Hotspot *spot, GlobeTrackDirection trackDirection) {
+ _globeTracker.setTrackParameters(spot, trackDirection);
+ _globeTracker.startTracking(input);
+}
+
+void GlobeGame::clickGlobe(const Input &input) {
+ int16 newSilo = findClickedSilo(input);
+
+ if (newSilo != -1) {
+ _targetHighlightUpperLeft.hide();
+ _targetHighlightUpperRight.hide();
+ _targetHighlightLowerLeft.hide();
+ _targetHighlightLowerRight.hide();
+ _lowerNamesMovie.show();
+ _lowerNamesMovie.setTime(newSilo * _lowerNamesMovie.getScale());
+ _lowerNamesMovie.redrawMovieWorld();
+ _owner->requestSpotSound(kSiloBeepIn, kSiloBeepOut, kFilterNoInput, 0);
+
+ if (newSilo == _targetSilo[_currentSiloIndex]) {
+ _currentSiloIndex++;
+ _countdown.stopCountdown();
+ _owner->requestSpotSound(kSiloDeactivatedIn, kSiloDeactivatedOut, kFilterNoInput, 0);
+
+ if (_currentSiloIndex == kNumTargetSilos) {
+ // Player won.
+ _owner->requestDelay(1, 2, kFilterNoInput, 0);
+ _upperNamesMovie.hide();
+ _lowerNamesMovie.hide();
+ _countdown.hide();
+ _monitorMovie.setSegment(kMaxDeactivatedStart * _monitorMovie.getScale(),
+ kMaxDeactivatedStop * _monitorMovie.getScale());
+ _monitorMovie.setTime(kMaxDeactivatedStart * _monitorMovie.getScale());
+ _monitorCallBack.setCallBackFlag(kMaxDeactivatedFinished);
+ _monitorCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ _monitorMovie.start();
+ _owner->requestSpotSound(kMaximumDeactivationIn, kMaximumDeactivationOut,
+ kFilterNoInput, kSpotSoundCompletedFlag);
+ _gameState = kPlayerWon1;
+ } else {
+ _owner->requestDelay(2, 1, kFilterNoInput, kDelayCompletedFlag);
+ _upperNamesMovie.hide();
+ _lowerNamesMovie.hide();
+ _countdown.hide();
+ _monitorMovie.setTime(kSiloDeactivatedTime * _monitorMovie.getScale());
+ _monitorMovie.redrawMovieWorld();
+ _gameState = kSiloDeactivated;
+ }
+ } else {
+ _owner->requestDelay(5, 1, kFilterNoInput, kDelayCompletedFlag);
+ _gameState = kDelayingPlayer;
+ // Play "incorrect" sound?
+ }
+ }
+}
+
+void GlobeGame::clickInHotspot(const Input &input, const Hotspot *spot) {
+ switch (spot->getObjectID()) {
+ case kNorad79SpinLeftSpotID:
+ spinGlobe(input, spot, kTrackLeft);
+ break;
+ case kNorad79SpinRightSpotID:
+ spinGlobe(input, spot, kTrackRight);
+ break;
+ case kNorad79SpinUpSpotID:
+ spinGlobe(input, spot, kTrackUp);
+ break;
+ case kNorad79SpinDownSpotID:
+ spinGlobe(input, spot, kTrackDown);
+ break;
+ case kNorad79SiloAreaSpotID:
+ clickGlobe(input);
+ break;
+ default:
+ GameInteraction::clickInHotspot(input, spot);
+ break;
+ }
+}
+
+void GlobeGame::activateHotspots() {
+ GameInteraction::activateHotspots();
+
+ switch (_gameState) {
+ case kWaitingForPlayer:
+ g_allHotspots.deactivateOneHotspot(kNorad79WestOutSpotID);
+ g_allHotspots.activateOneHotspot(kNorad79SpinLeftSpotID);
+ g_allHotspots.activateOneHotspot(kNorad79SpinRightSpotID);
+ g_allHotspots.activateOneHotspot(kNorad79SpinUpSpotID);
+ g_allHotspots.activateOneHotspot(kNorad79SpinDownSpotID);
+ g_allHotspots.activateOneHotspot(kNorad79SiloAreaSpotID);
+ break;
+ default:
+ g_allHotspots.deactivateOneHotspot(kNorad79WestOutSpotID);
+ break;
+ }
+}
+
+void GlobeGame::globeMovieFrameToOrigin(int16 frameNum, int16 &latOrigin, int16 &longOrigin) {
+ latOrigin = kDegreesPerLatSlice * 2 - (frameNum / (kNumLongSlices * 2)) * kDegreesPerLatSlice;
+ frameNum %= kNumLongSlices * 2;
+
+ if (frameNum >= kNumLongSlices)
+ longOrigin = kLongOrigin + (kNumLongSlices * 2 - 1 - frameNum) * kDegreesPerLongSlice;
+ else
+ longOrigin = kLongOrigin + frameNum * kDegreesPerLongSlice;
+
+ if (longOrigin > 180)
+ longOrigin -= 360;
+}
+
+void GlobeGame::globePointToLatLong(const GlobeGame::Point3D &pt, int16 latOrigin, int16 longOrigin,
+ int16 &latitude, int16 &longitude) {
+ Point3D scratch = pt;
+
+ // Translate globe center to origin.
+ scratch.x -= kGlobeCenter.x;
+ scratch.y -= kGlobeCenter.y;
+ scratch.z -= kGlobeCenter.z;
+
+ // Rotate around z axis latOrigin degrees to bring equator parallel with XZ plane
+ float theta = degreesToRadians(latOrigin);
+ float s = sin(theta);
+ float c = cos(theta);
+ float x = scratch.x * c - scratch.y * s;
+ float y = scratch.y * c + scratch.x * s;
+ scratch.x = x;
+ scratch.y = y;
+
+ // Calculate latitude
+ latitude = (int16)radiansToDegrees(asin(scratch.y / kGlobeRadius));
+
+ // Rotate around y axis longOrigin degrees to bring longitude 0 to positive X axis
+ theta = degreesToRadians(longOrigin);
+ s = sin(theta);
+ c = cos(theta);
+ x = scratch.x * c - scratch.z * s;
+ float z = scratch.z * c + scratch.x * s;
+ scratch.x = x;
+ scratch.z = z;
+
+ // Calculate longitude
+ longitude = (int16)radiansToDegrees(acos(scratch.x / sqrt(scratch.x * scratch.x + scratch.z * scratch.z)));
+
+ if (scratch.z < 0)
+ longitude = -longitude;
+}
+
+// h, v in [0, 511][0, 255]
+// Looking down negative x axis.
+void GlobeGame::screenPointTo3DPoint(int16 h, int16 v, GlobeGame::Point3D &pt) {
+ pt.x = kCameraLocation.x - kPicturePlaneDistance;
+ pt.y = kCameraLocation.y + (128 - v) * kPicturePlaneDistance * kTanFieldOfView / 256;
+ pt.z = kCameraLocation.z + (h - 256) * kPicturePlaneDistance * kTanFieldOfView / 256;
+}
+
+// Fundamentals of Three-Dimensional Graphics, by Alan Watt
+// pp. 163-164
+bool GlobeGame::lineHitsGlobe(const GlobeGame::Line3D &line, GlobeGame::Point3D &pt) {
+ float i = line.pt2.x - line.pt1.x;
+ float j = line.pt2.y - line.pt1.y;
+ float k = line.pt2.z - line.pt1.z;
+ float a = i * i + j * j + k * k;
+ float b = 2 * i * (line.pt1.x - kGlobeCenter.x) + 2 * j * (line.pt1.y - kGlobeCenter.y) +
+ 2 * k * (line.pt1.z - kGlobeCenter.z);
+ float c = kGlobeCenter.x * kGlobeCenter.x + kGlobeCenter.y * kGlobeCenter.y +
+ kGlobeCenter.z * kGlobeCenter.z + line.pt1.x * line.pt1.x + line.pt1.y * line.pt1.y +
+ line.pt1.z * line.pt1.z + -2 * (kGlobeCenter.x * line.pt1.x + kGlobeCenter.y * line.pt1.y +
+ kGlobeCenter.z * line.pt1.z) - kGlobeRadius * kGlobeRadius;
+
+ // Solve quadratic equation of a, b, c.
+ float t = b * b - 4 * a * c;
+
+ if (t >= 0.0f) {
+ // Return smaller root, which corresponds to closest intersection point.
+ t = (-b - sqrt(t)) / (2 * a);
+ pt.x = i * t + line.pt1.x;
+ pt.y = j * t + line.pt1.y;
+ pt.z = k * t + line.pt1.z;
+ return true;
+ }
+
+ return false;
+}
+
+bool GlobeGame::canSolve() {
+ return _gameState != kPlayerWon1 && _gameState != kPlayerWon2 && _gameState != kPlayerLost1;
+}
+
+void GlobeGame::doSolve() {
+ _owner->requestDelay(1, 2, kFilterNoInput, 0);
+ _upperNamesMovie.hide();
+ _lowerNamesMovie.hide();
+ _countdown.hide();
+ _monitorMovie.setSegment(kMaxDeactivatedStart * _monitorMovie.getScale(), kMaxDeactivatedStop * _monitorMovie.getScale());
+ _monitorMovie.setTime(kMaxDeactivatedStart * _monitorMovie.getScale());
+ _monitorCallBack.setCallBackFlag(kMaxDeactivatedFinished);
+ _monitorCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ _monitorMovie.start();
+ _owner->requestSpotSound(kMaximumDeactivationIn, kMaximumDeactivationOut, kFilterNoInput, kSpotSoundCompletedFlag);
+ _gameState = kPlayerWon1;
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/norad/delta/globegame.h b/engines/pegasus/neighborhood/norad/delta/globegame.h
new file mode 100644
index 0000000000..73ed48866f
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/delta/globegame.h
@@ -0,0 +1,169 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_NORAD_DELTA_GLOBEGAME_H
+#define PEGASUS_NEIGHBORHOOD_NORAD_DELTA_GLOBEGAME_H
+
+#include "pegasus/interaction.h"
+#include "pegasus/movie.h"
+#include "pegasus/notification.h"
+
+namespace Pegasus {
+
+enum GlobeTrackDirection {
+ kTrackLeft,
+ kTrackRight,
+ kTrackUp,
+ kTrackDown
+};
+
+// This class assumes that the globe movie is built at 15 frames per second with a
+// time scale of 600, yielding 40 time unit per frame.
+
+class GlobeTracker : public Tracker {
+public:
+ GlobeTracker(Movie *, Picture *, Picture *, Picture *, Picture *);
+ virtual ~GlobeTracker() {}
+
+ void setTrackParameters(const Hotspot *, GlobeTrackDirection);
+ void continueTracking(const Input &);
+ void startTracking(const Input &);
+ void stopTracking(const Input &);
+ void activateHotspots();
+ bool stopTrackingInput(const Input &);
+
+protected:
+ void trackGlobeMovie();
+ void stopGlobeMovie();
+
+ Movie *_globeMovie;
+ Picture *_leftHighlight;
+ Picture *_rightHighlight;
+ Picture *_upHighlight;
+ Picture *_downHighlight;
+ const Hotspot *_trackSpot;
+ int _trackTime;
+ GlobeTrackDirection _trackDirection;
+};
+
+class GlobeCountdown : public IdlerAnimation {
+public:
+ GlobeCountdown(const DisplayElementID);
+ virtual ~GlobeCountdown() {}
+
+ void setCountdownTime(const int);
+ void startCountdown();
+ void stopCountdown();
+
+ void setDisplayOrder(const DisplayOrder);
+ void show();
+ void hide();
+ void moveElementTo(const CoordType, const CoordType);
+
+ void draw(const Common::Rect &);
+
+protected:
+ Surface _digits;
+ int16 _digitOffset;
+};
+
+static const int16 kNumAllSilos = 40;
+static const int16 kNumTargetSilos = 10;
+static const int16 kNumLongSlices = 72;
+
+class GlobeGame : public GameInteraction, public NotificationReceiver {
+public:
+ GlobeGame(Neighborhood *);
+ virtual ~GlobeGame() {}
+
+ void handleInput(const Input &, const Hotspot *);
+ void clickInHotspot(const Input &, const Hotspot *);
+ void activateHotspots();
+
+ bool canSolve();
+ void doSolve();
+
+ struct Point3D {
+ float x, y, z;
+ };
+
+ struct Line3D {
+ Point3D pt1, pt2;
+ };
+
+protected:
+ // Latitude (-90 - 90) and longitude (-180 - 180)
+ static const int16 _siloCoords[kNumAllSilos][2];
+
+ static const int16 _targetSilo[kNumTargetSilos];
+ static const int16 _timeLimit[kNumTargetSilos];
+ static const TimeValue _siloName[kNumTargetSilos][2];
+
+ void openInteraction();
+ void initInteraction();
+ void closeInteraction();
+
+ void receiveNotification(Notification *, const NotificationFlags);
+
+ void spinGlobe(const Input &, const Hotspot *, GlobeTrackDirection);
+ void clickGlobe(const Input &);
+
+ int16 findClickedSilo(const Input &);
+
+ void globeMovieFrameToOrigin(int16, int16 &, int16 &);
+ void globePointToLatLong(const Point3D &, int16, int16, int16 &, int16 &);
+ void screenPointTo3DPoint(int16, int16, Point3D &);
+ bool lineHitsGlobe(const Line3D &, Point3D &);
+
+ Movie _monitorMovie;
+ Movie _globeMovie;
+ Movie _upperNamesMovie;
+ Movie _lowerNamesMovie;
+ Notification _globeNotification;
+ NotificationCallBack _monitorCallBack;
+ GlobeTracker _globeTracker;
+ Picture _globeCircleLeft;
+ Picture _globeCircleRight;
+ Picture _globeCircleUp;
+ Picture _globeCircleDown;
+ Picture _motionHighlightLeft;
+ Picture _motionHighlightRight;
+ Picture _motionHighlightUp;
+ Picture _motionHighlightDown;
+ Picture _targetHighlightUpperLeft;
+ Picture _targetHighlightUpperRight;
+ Picture _targetHighlightLowerLeft;
+ Picture _targetHighlightLowerRight;
+ GlobeCountdown _countdown;
+ NotificationCallBack _countdownCallBack;
+ int16 _gameState;
+ int16 _currentSiloIndex;
+ Notification *_neighborhoodNotification;
+ bool _playedInstructions;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/norad/delta/noraddelta.cpp b/engines/pegasus/neighborhood/norad/delta/noraddelta.cpp
new file mode 100644
index 0000000000..f2ea53ff89
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/delta/noraddelta.cpp
@@ -0,0 +1,869 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/energymonitor.h"
+#include "pegasus/gamestate.h"
+#include "pegasus/interface.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/biochips/opticalchip.h"
+#include "pegasus/items/biochips/retscanchip.h"
+#include "pegasus/items/inventory/airmask.h"
+#include "pegasus/neighborhood/norad/constants.h"
+#include "pegasus/neighborhood/norad/subcontrolroom.h"
+#include "pegasus/neighborhood/norad/delta/globegame.h"
+#include "pegasus/neighborhood/norad/delta/noraddelta.h"
+
+namespace Pegasus {
+
+const uint32 NoradDelta::_noradDeltaClawExtras[22] = {
+ kN60ClawFromAToB,
+ kN60ClawALoop,
+ kN60ClawAPinch,
+ kN60ClawACounterclockwise,
+ kN60ClawAClockwise,
+ kN60ClawFromBToA,
+ kN60ClawFromBToC,
+ kN60ClawFromBToD,
+ kN60ClawBLoop,
+ kN60ClawBPinch,
+ kN60ClawBCounterclockwise,
+ kN60ClawBClockwise,
+ kN60ClawFromCToB,
+ kN60ClawCLoop,
+ kN60ClawCPinch,
+ kN60ClawCCounterclockwise,
+ kN60ClawCClockwise,
+ kN60ClawFromDToB,
+ kN60ClawDLoop,
+ kN60ClawDPinch,
+ kN60ClawDCounterclockwise,
+ kN60ClawDClockwise
+};
+
+NoradDelta::NoradDelta(InputHandler *nextHandler, PegasusEngine *owner) : Norad(nextHandler, owner, "Norad Delta", kNoradDeltaID) {
+ _elevatorUpRoomID = kNorad49South;
+ _elevatorDownRoomID = kNorad48South;
+ _elevatorUpSpotID = kNorad48ElevatorUpSpotID;
+ _elevatorDownSpotID = kNorad49ElevatorDownSpotID;
+
+ // Pressure door stuff.
+
+ _subRoomEntryRoom1 = kNorad50;
+ _subRoomEntryDir1 = kEast;
+ _subRoomEntryRoom2 = kNorad59;
+ _subRoomEntryDir2 = kWest;
+ _upperPressureDoorRoom = kNorad50East;
+ _lowerPressureDoorRoom = kNorad59West;
+
+ _upperPressureDoorUpSpotID = kDeltaUpperPressureDoorUpSpotID;
+ _upperPressureDoorDownSpotID = kDeltaUpperPressureDoorDownSpotID;
+ _upperPressureDoorAbortSpotID = kNorad50DoorOutSpotID;
+
+ _lowerPressureDoorUpSpotID = kDeltaLowerPressureDoorUpSpotID;
+ _lowerPressureDoorDownSpotID = kDeltaLowerPressureDoorDownSpotID;
+ _lowerPressureDoorAbortSpotID = kNorad59WestOutSpotID;
+
+ _pressureSoundIn = kPressureDoorIntro1In;
+ _pressureSoundOut = kPressureDoorIntro1Out;
+ _equalizeSoundIn = kPressureDoorIntro2In;
+ _equalizeSoundOut = kPressureDoorIntro2Out;
+ _accessDeniedIn = kDeltaAccessDeniedIn;
+ _accessDeniedOut = kDeltaAccessDeniedOut;
+
+ GameState.setNoradSubPrepState(kSubDamaged);
+
+ _subControlRoom = kNorad60West;
+}
+
+void NoradDelta::init() {
+ Norad::init();
+
+ // Little fix for the retinal scan zoom in spot...
+ Hotspot *hotspot = _vm->getAllHotspots().findHotspotByID(kNorad68WestSpotID);
+ hotspot->setMaskedHotspotFlags(kZoomInSpotFlag, kZoomInSpotFlag | kZoomOutSpotFlag);
+
+ hotspot = _vm->getAllHotspots().findHotspotByID(kNorad79WestSpotID);
+ hotspot->setMaskedHotspotFlags(kZoomInSpotFlag, kZoomInSpotFlag | kZoomOutSpotFlag);
+
+ hotspot = _vm->getAllHotspots().findHotspotByID(kDelta59RobotShieldBiochipSpotID);
+ hotspot->setMaskedHotspotFlags(kPickUpBiochipSpotFlag, kPickUpBiochipSpotFlag);
+ HotspotInfoTable::Entry *hotspotEntry = findHotspotEntry(kDelta59RobotShieldBiochipSpotID);
+ hotspotEntry->hotspotItem = kShieldBiochip;
+
+ hotspot = _vm->getAllHotspots().findHotspotByID(kDelta59RobotOpMemBiochipSpotID);
+ hotspot->setMaskedHotspotFlags(kPickUpBiochipSpotFlag, kPickUpBiochipSpotFlag);
+ hotspotEntry = findHotspotEntry(kDelta59RobotOpMemBiochipSpotID);
+ hotspotEntry->hotspotItem = kOpticalBiochip;
+
+ hotspot = _vm->getAllHotspots().findHotspotByID(kDelta59RobotRetinalBiochipSpotID);
+ hotspot->setMaskedHotspotFlags(kPickUpBiochipSpotFlag, kPickUpBiochipSpotFlag);
+ hotspotEntry = findHotspotEntry(kDelta59RobotRetinalBiochipSpotID);
+ hotspotEntry->hotspotItem = kRetinalScanBiochip;
+
+ hotspot = _vm->getAllHotspots().findHotspotByID(kDelta60RobotShieldBiochipSpotID);
+ hotspot->setMaskedHotspotFlags(kPickUpBiochipSpotFlag, kPickUpBiochipSpotFlag);
+ hotspotEntry = findHotspotEntry(kDelta60RobotShieldBiochipSpotID);
+ hotspotEntry->hotspotItem = kShieldBiochip;
+
+ hotspot = _vm->getAllHotspots().findHotspotByID(kDelta60RobotOpMemBiochipSpotID);
+ hotspot->setMaskedHotspotFlags(kPickUpBiochipSpotFlag, kPickUpBiochipSpotFlag);
+ hotspotEntry = findHotspotEntry(kDelta60RobotOpMemBiochipSpotID);
+ hotspotEntry->hotspotItem = kOpticalBiochip;
+
+ hotspot = _vm->getAllHotspots().findHotspotByID(kDelta60RobotRetinalBiochipSpotID);
+ hotspot->setMaskedHotspotFlags(kPickUpBiochipSpotFlag, kPickUpBiochipSpotFlag);
+ hotspotEntry = findHotspotEntry(kDelta60RobotRetinalBiochipSpotID);
+ hotspotEntry->hotspotItem = kRetinalScanBiochip;
+}
+
+void NoradDelta::start() {
+ if (g_energyMonitor) {
+ g_energyMonitor->stopEnergyDraining();
+ g_energyMonitor->restoreLastEnergyValue();
+ _vm->resetEnergyDeathReason();
+ g_energyMonitor->startEnergyDraining();
+ }
+
+ Norad::start();
+}
+
+void NoradDelta::setUpAIRules() {
+ Neighborhood::setUpAIRules();
+
+ if (g_AIArea) {
+ AIPlayMessageAction *messageAction = new AIPlayMessageAction("Images/AI/Norad/XN07NE", false);
+ AILocationCondition *locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kNorad68, kWest));
+ AIRule *rule = new AIRule(locCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+ }
+}
+
+void NoradDelta::getExtraCompassMove(const ExtraTable::Entry &entry, FaderMoveSpec &compassMove) {
+ switch (entry.extra) {
+ case kArriveFromSubChase:
+ compassMove.makeTwoKnotFaderSpec(kNoradDeltaMovieScale, entry.movieStart, 20, entry.movieEnd, 90);
+ compassMove.insertFaderKnot(entry.movieStart + 25 * kNoradDeltaFrameDuration, 20);
+ compassMove.insertFaderKnot(entry.movieStart + 94 * kNoradDeltaFrameDuration, 45);
+ compassMove.insertFaderKnot(entry.movieStart + 101 * kNoradDeltaFrameDuration, 45);
+ compassMove.insertFaderKnot(entry.movieStart + 146 * kNoradDeltaFrameDuration, 90 + 15);
+ compassMove.insertFaderKnot(entry.movieStart + 189 * kNoradDeltaFrameDuration, 90 + 15);
+ compassMove.insertFaderKnot(entry.movieStart + 204 * kNoradDeltaFrameDuration, 90 + 30);
+ compassMove.insertFaderKnot(entry.movieStart + 214 * kNoradDeltaFrameDuration, 90 + 20);
+ compassMove.insertFaderKnot(entry.movieStart + 222 * kNoradDeltaFrameDuration, 90 + 20);
+ compassMove.insertFaderKnot(entry.movieStart + 228 * kNoradDeltaFrameDuration, 90 + 10);
+ compassMove.insertFaderKnot(entry.movieStart + 245 * kNoradDeltaFrameDuration, 90 + 85);
+ compassMove.insertFaderKnot(entry.movieStart + 262 * kNoradDeltaFrameDuration, 90 + 70);
+ compassMove.insertFaderKnot(entry.movieStart + 273 * kNoradDeltaFrameDuration, 90 + 80);
+ compassMove.insertFaderKnot(entry.movieStart + 287 * kNoradDeltaFrameDuration, 90);
+ break;
+ case kN60PlayerFollowsRobotToDoor:
+ compassMove.makeTwoKnotFaderSpec(kNoradDeltaMovieScale, entry.movieStart, 270 + kSubControlCompassAngle,
+ entry.movieEnd, 270 - 15);
+ compassMove.insertFaderKnot(entry.movieStart + 280, 270 + kSubControlCompassAngle);
+ compassMove.insertFaderKnot(entry.movieStart + 920, 360);
+ compassMove.insertFaderKnot(entry.movieStart + 1840, 360);
+ compassMove.insertFaderKnot(entry.movieStart + 2520, 270);
+ compassMove.insertFaderKnot(entry.movieStart + 3760, 270);
+ compassMove.insertFaderKnot(entry.movieStart + 4640, 270 + kSubControlCompassAngle);
+ break;
+ case kN59PlayerWins2:
+ compassMove.makeTwoKnotFaderSpec(kNoradDeltaMovieScale, entry.movieStart, 270, entry.movieEnd, 280);
+ compassMove.insertFaderKnot(entry.movieEnd - 1000, 270);
+ default:
+ Norad::getExtraCompassMove(entry, compassMove);
+ break;
+ }
+}
+
+GameInteraction *NoradDelta::makeInteraction(const InteractionID interactionID) {
+ if (interactionID == kNoradGlobeGameInteractionID)
+ return new GlobeGame(this);
+
+ return Norad::makeInteraction(interactionID);
+}
+
+void NoradDelta::playClawMonitorIntro() {
+ playSpotSoundSync(kLoadClawIntroIn, kLoadClawIntroOut);
+}
+
+void NoradDelta::getExitEntry(const RoomID room, const DirectionConstant direction, ExitTable::Entry &entry) {
+ Norad::getExitEntry(room, direction, entry);
+
+ if (room == kNorad61 && direction == kSouth)
+ entry.movieStart += kNoradDeltaFrameDuration;
+}
+
+void NoradDelta::getZoomEntry(const HotSpotID id, ZoomTable::Entry &zoomEntry) {
+ Norad::getZoomEntry(id, zoomEntry);
+
+ if (id == kNorad59WestSpotID && GameState.getNoradPlayedGlobeGame()) {
+ ExtraTable::Entry extraEntry;
+ getExtraEntry(kN59ZoomWithRobot, extraEntry);
+ zoomEntry.movieStart = extraEntry.movieStart;
+ zoomEntry.movieEnd = extraEntry.movieEnd;
+ }
+}
+
+void NoradDelta::loadAmbientLoops() {
+/*
+ Logic:
+
+ loop sound 1:
+ if room == kNorad79West
+ if player globe game
+ play kNoradGlobeLoop2SoundNum
+ else
+ play kNoradRedAlertLoopSoundNum
+ else if room >= kNorad78 && room <= kNorad79
+ play kNoradGlobeLoop2SoundNum
+ else if gassed,
+ if room >= kNorad41 && room <= kNorad49South
+ play kNoradNewSubLoopSoundNum, kNoradWarningVolume
+ else if room >= kNorad59 && room <= kNorad60West
+ play kNoradSubControlLoopSoundNum, kNoradWarningVolume
+ else
+ play kNoradWarningLoopSoundNum, kNoradWarningVolume
+ else
+ play nothing
+ loop sound 2:
+ if gassed and not wearing air mask
+ if room == kNorad54North
+ play breathing unmanned loop
+ else
+ play breathing
+ else
+ if room == kNorad54North
+ play unmanned loop
+ else
+ play nothing
+*/
+
+ if (GameState.getNoradArrivedFromSub()) {
+ RoomID room = GameState.getCurrentRoom();
+
+ if (room == kNorad79West) {
+ if (_privateFlags.getFlag(kNoradPrivateFinishedGlobeGameFlag))
+ loadLoopSound1("Sounds/Norad/GlobAmb2.22K.AIFF");
+ else
+ loadLoopSound1("Sounds/Norad/RedAlert.22K.AIFF");
+ } else if (room >= kNorad78 && room <= kNorad79) {
+ // clone2727 says: This looks like it should be loadLoopSound1...
+ loadLoopSound2("Sounds/Norad/RedAlert.22K.AIFF");
+ } else if (GameState.getNoradGassed()) {
+ if (room >= kNorad41 && room <= kNorad49South)
+ loadLoopSound1("Sounds/Norad/NEW SUB AMB.22K.AIFF", kNoradWarningVolume * 3);
+ else if (room >= kNorad59 && room <= kNorad60West)
+ loadLoopSound1("Sounds/Norad/SUB CONTRL LOOP.22K.AIFF", kNoradWarningVolume * 3);
+ else
+ loadLoopSound1("Sounds/Norad/WARNING LOOP.22K.AIFF", kNoradWarningVolume);
+ } else {
+ loadLoopSound1("");
+ }
+
+ if (GameState.getNoradGassed() && !g_airMask->isAirFilterOn()) {
+ if (room == kNorad54North)
+ loadLoopSound2("Sounds/Norad/Breathing Typing.22K.AIFF", 0x100 / 2);
+ else
+ loadLoopSound2("Sounds/Norad/SUCKING WIND.22K.AIFF", kNoradSuckWindVolume, 0, 0);
+ } else {
+ if (room == kNorad54North)
+ loadLoopSound2("Sounds/Norad/N54NAS.22K.AIFF", 0x100 / 2);
+ else
+ loadLoopSound2("");
+ }
+ } else {
+ // Start them off at zero...
+ if (GameState.getNoradGassed())
+ loadLoopSound1("Sounds/Norad/NEW SUB AMB.22K.AIFF", 0, 0, 0);
+ if (!g_airMask->isAirFilterOn())
+ loadLoopSound2("Sounds/Norad/SUCKING WIND.22K.AIFF", 0, 0, 0);
+ }
+}
+
+void NoradDelta::checkContinuePoint(const RoomID room, const DirectionConstant direction) {
+ switch (MakeRoomView(room, direction)) {
+ case MakeRoomView(kNorad41, kEast):
+ case MakeRoomView(kNorad49, kEast):
+ case MakeRoomView(kNorad49, kWest):
+ case MakeRoomView(kNorad61, kSouth):
+ case MakeRoomView(kNorad68, kEast):
+ case MakeRoomView(kNorad79, kWest):
+ makeContinuePoint();
+ break;
+ }
+}
+
+void NoradDelta::arriveAt(const RoomID room, const DirectionConstant direction) {
+ if (room != kNorad68)
+ GameState.setNoradRetScanGood(false);
+
+ Norad::arriveAt(room, direction);
+
+ FaderMoveSpec loop1Spec, loop2Spec;
+ ExtraTable::Entry entry;
+
+ switch (room) {
+ case kNorad41:
+ if (direction == kEast && !GameState.getNoradArrivedFromSub()) {
+ GameState.setNoradPlayedGlobeGame(false);
+
+ GameState.setNoradBeatRobotWithClaw(false);
+ GameState.setNoradBeatRobotWithDoor(false);
+ GameState.setNoradRetScanGood(false);
+
+ GameState.setScoringExitedSub(true);
+
+ getExtraEntry(kArriveFromSubChase, entry);
+
+ loop1Spec.makeTwoKnotFaderSpec(kNoradDeltaMovieScale, 0, 0, entry.movieEnd -
+ entry.movieStart, kNoradWarningVolume);
+ loop1Spec.insertFaderKnot(7320, 0);
+ loop1Spec.insertFaderKnot(7880, kNoradWarningVolume);
+
+ loop2Spec.makeTwoKnotFaderSpec(kNoradDeltaMovieScale, 0, 0, entry.movieEnd -
+ entry.movieStart, kNoradSuckWindVolume);
+ loop1Spec.insertFaderKnot(7320, 0);
+ loop1Spec.insertFaderKnot(7880, kNoradSuckWindVolume);
+
+ startExtraSequence(kArriveFromSubChase, kExtraCompletedFlag, kFilterNoInput);
+
+ startLoop1Fader(loop1Spec);
+ startLoop2Fader(loop2Spec);
+ }
+ break;
+ case kNorad54North:
+ GameState.setScoringSawRobotAt54North(true);
+ break;
+ case kNorad68:
+ if (GameState.getNoradRetScanGood())
+ openDoor();
+ break;
+ case kNorad68West:
+ arriveAtNorad68West();
+ break;
+ case kNorad79West:
+ arriveAtNorad79West();
+ break;
+ default:
+ break;
+ }
+}
+
+void NoradDelta::doorOpened() {
+ Norad::doorOpened();
+ GameState.setNoradRetScanGood(false);
+}
+
+void NoradDelta::arriveAtNorad68West() {
+ playSpotSoundSync(kHoldForRetinalIn, kHoldForRetinalOut);
+
+ BiochipItem *retScan = _vm->getCurrentBiochip();
+
+ if (retScan != 0 && retScan->getObjectID() == kRetinalScanBiochip) {
+ ((RetScanChip *)retScan)->searchForLaser();
+ succeedRetinalScan();
+ } else {
+ failRetinalScan();
+ }
+}
+
+void NoradDelta::arriveAtNorad79West() {
+ if (!GameState.getNoradPlayedGlobeGame())
+ newInteraction(kNoradGlobeGameInteractionID);
+}
+
+void NoradDelta::bumpIntoWall() {
+ requestSpotSound(kDeltaBumpIntoWallIn, kDeltaBumpIntoWallOut, kFilterNoInput, 0);
+ Neighborhood::bumpIntoWall();
+}
+
+void NoradDelta::failRetinalScan() {
+ startExtraSequence(kNoradDeltaRetinalScanBad, kExtraCompletedFlag, kFilterNoInput);
+}
+
+void NoradDelta::succeedRetinalScan() {
+ startExtraSequence(kNoradDeltaRetinalScanGood, kExtraCompletedFlag, kFilterNoInput);
+ GameState.setNoradRetScanGood(true);
+ GameState.setScoringUsedRetinalChip(true);
+}
+
+void NoradDelta::getDoorEntry(const RoomID room, const DirectionConstant direction, DoorTable::Entry &entry) {
+ Norad::getDoorEntry(room, direction, entry);
+
+ if (room == kNorad68 && direction == kWest && !GameState.getNoradRetScanGood())
+ entry.flags = kDoorPresentMask | kDoorLockedMask;
+}
+
+void NoradDelta::finishedGlobeGame() {
+ GameState.setNoradPlayedGlobeGame(true);
+ _privateFlags.setFlag(kNoradPrivateFinishedGlobeGameFlag, true);
+ GameState.setScoringFinishedGlobeGame(true);
+ loadAmbientLoops();
+ g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Norad/XN60WD1", false, kWarningInterruption);
+}
+
+bool NoradDelta::playingAgainstRobot() {
+ return GameState.getNoradPlayedGlobeGame();
+}
+
+void NoradDelta::getClawInfo(HotSpotID &outSpotID, HotSpotID &prepSpotID, HotSpotID &clawControlSpotID, HotSpotID &pinchClawSpotID,
+ HotSpotID &moveClawDownSpotID, HotSpotID &moveClawRightSpotID, HotSpotID &moveClawLeftSpotID, HotSpotID &moveClawUpSpotID,
+ HotSpotID &clawCCWSpotID, HotSpotID &clawCWSpotID, uint32 &clawPosition, const uint32 *&clawExtraIDs) {
+ outSpotID = kNorad60MonitorOutSpotID;
+ prepSpotID = kNorad60LaunchPrepSpotID;
+ clawControlSpotID = kNorad60ClawControlSpotID;
+ pinchClawSpotID = kNorad60ClawPinchSpotID;
+ moveClawDownSpotID = kNorad60ClawDownSpotID;
+ moveClawRightSpotID = kNorad60ClawRightSpotID;
+ moveClawLeftSpotID = kNorad60ClawLeftSpotID;
+ moveClawUpSpotID = kNorad60ClawUpSpotID;
+ clawCCWSpotID = kNorad60ClawCCWSpotID;
+ clawCWSpotID = kNorad60ClawCWSpotID;
+ clawPosition = kClawAtC;
+ clawExtraIDs = _noradDeltaClawExtras;
+}
+
+void NoradDelta::playerBeatRobotWithDoor() {
+ GameState.setNoradBeatRobotWithDoor(true);
+ updateViewFrame();
+ GameState.setScoringStoppedNoradRobot(true);
+ g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Norad/XN59WD", false, kWarningInterruption);
+}
+
+void NoradDelta::playerBeatRobotWithClaw() {
+ GameState.setNoradBeatRobotWithClaw(true);
+ updateViewFrame();
+ GameState.setScoringStoppedNoradRobot(true);
+ GameState.setScoringNoradGandhi(true);
+ g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/Norad/XN59WD", false, kWarningInterruption);
+}
+
+TimeValue NoradDelta::getViewTime(const RoomID room, const DirectionConstant direction) {
+ ExtraTable::Entry entry;
+
+ if (room == kNorad41 && direction == kSouth && !GameState.getNoradArrivedFromSub()) {
+ getExtraEntry(kArriveFromSubChase, entry);
+ return entry.movieStart;
+ }
+
+ if (GameState.getNoradBeatRobotWithDoor()) {
+ if (_privateFlags.getFlag(kNoradPrivateRobotHeadOpenFlag)) {
+ uint32 extraID = kN59Biochips111;
+ if (_privateFlags.getFlag(kNoradPrivateGotShieldChipFlag))
+ extraID += 1;
+ if (_privateFlags.getFlag(kNoradPrivateGotOpticalChipFlag))
+ extraID += 2;
+ if (_privateFlags.getFlag(kNoradPrivateGotRetScanChipFlag))
+ extraID += 4;
+ getExtraEntry(extraID, entry);
+ return entry.movieStart;
+ }
+
+ getExtraEntry(kN59RobotHeadOpens, entry);
+ return entry.movieStart;
+ } else if (GameState.getNoradBeatRobotWithClaw()) {
+ if (_privateFlags.getFlag(kNoradPrivateRobotHeadOpenFlag)) {
+ uint32 extraID = kN60Biochips111;
+ if (_privateFlags.getFlag(kNoradPrivateGotShieldChipFlag))
+ extraID += 1;
+ if (_privateFlags.getFlag(kNoradPrivateGotOpticalChipFlag))
+ extraID += 2;
+ if (_privateFlags.getFlag(kNoradPrivateGotRetScanChipFlag))
+ extraID += 4;
+ getExtraEntry(extraID, entry);
+ return entry.movieStart;
+ }
+
+ getExtraEntry(kN60RobotHeadOpens, entry);
+ return entry.movieStart;
+ }
+
+ return Norad::getViewTime(room, direction);
+}
+
+void NoradDelta::openDoor() {
+ if (GameState.getCurrentRoom() == kNorad59 && GameState.getCurrentDirection() == kWest && GameState.getNoradPlayedGlobeGame()) {
+ Input scratch;
+ InputHandler::_inputHandler->clickInHotspot(scratch, _vm->getAllHotspots().findHotspotByID(kNorad59WestSpotID));
+ } else {
+ Norad::openDoor();
+ }
+}
+
+void NoradDelta::activateHotspots() {
+ Norad::activateHotspots();
+
+ if (GameState.getCurrentRoom() == kNorad59West && GameState.getCurrentDirection() == kWest && GameState.getNoradBeatRobotWithDoor()) {
+ _vm->getAllHotspots().deactivateOneHotspot(kNorad59WestOutSpotID);
+
+ if (_privateFlags.getFlag(kNoradPrivateRobotHeadOpenFlag)) {
+ if (!_privateFlags.getFlag(kNoradPrivateGotShieldChipFlag))
+ _vm->getAllHotspots().activateOneHotspot(kDelta59RobotShieldBiochipSpotID);
+ else
+ _vm->getAllHotspots().deactivateOneHotspot(kDelta59RobotShieldBiochipSpotID);
+
+ if (!_privateFlags.getFlag(kNoradPrivateGotOpticalChipFlag))
+ _vm->getAllHotspots().activateOneHotspot(kDelta59RobotOpMemBiochipSpotID);
+ else
+ _vm->getAllHotspots().deactivateOneHotspot(kDelta59RobotOpMemBiochipSpotID);
+
+ if (!_privateFlags.getFlag(kNoradPrivateGotRetScanChipFlag))
+ _vm->getAllHotspots().activateOneHotspot(kDelta59RobotRetinalBiochipSpotID);
+ else
+ _vm->getAllHotspots().deactivateOneHotspot(kDelta59RobotRetinalBiochipSpotID);
+ } else
+ _vm->getAllHotspots().activateOneHotspot(kDelta59RobotHeadSpotID);
+ } else if (GameState.getCurrentRoom() == kNorad60West && GameState.getCurrentDirection() == kWest &&
+ GameState.getNoradBeatRobotWithClaw()) {
+ _vm->getAllHotspots().deactivateOneHotspot(kNorad60MonitorOutSpotID);
+
+ if (_privateFlags.getFlag(kNoradPrivateRobotHeadOpenFlag)) {
+ if (!_privateFlags.getFlag(kNoradPrivateGotShieldChipFlag))
+ _vm->getAllHotspots().activateOneHotspot(kDelta60RobotShieldBiochipSpotID);
+ else
+ _vm->getAllHotspots().deactivateOneHotspot(kDelta60RobotShieldBiochipSpotID);
+
+ if (!_privateFlags.getFlag(kNoradPrivateGotOpticalChipFlag))
+ _vm->getAllHotspots().activateOneHotspot(kDelta60RobotOpMemBiochipSpotID);
+ else
+ _vm->getAllHotspots().deactivateOneHotspot(kDelta60RobotOpMemBiochipSpotID);
+
+ if (!_privateFlags.getFlag(kNoradPrivateGotRetScanChipFlag))
+ _vm->getAllHotspots().activateOneHotspot(kDelta60RobotRetinalBiochipSpotID);
+ else
+ _vm->getAllHotspots().deactivateOneHotspot(kDelta60RobotRetinalBiochipSpotID);
+ } else {
+ _vm->getAllHotspots().activateOneHotspot(kDelta60RobotHeadSpotID);
+ }
+ } else if (GameState.getCurrentRoomAndView() == MakeRoomView(kNorad50, kEast)) {
+ if (GameState.isCurrentDoorOpen())
+ _vm->getAllHotspots().deactivateOneHotspot(kNorad50DoorSpotID);
+ } else if (GameState.getCurrentRoomAndView() == MakeRoomView(kNorad59, kWest)) {
+ if (GameState.isCurrentDoorOpen())
+ _vm->getAllHotspots().deactivateOneHotspot(kNorad59WestSpotID);
+ }
+}
+
+void NoradDelta::clickInHotspot(const Input &input, const Hotspot *clickedSpot) {
+ switch (clickedSpot->getObjectID()) {
+ case kDelta59RobotHeadSpotID:
+ startExtraSequence(kN59RobotHeadOpens, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kDelta60RobotHeadSpotID:
+ startExtraSequence(kN60RobotHeadOpens, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ default:
+ Norad::clickInHotspot(input, clickedSpot);
+ break;
+ }
+}
+
+void NoradDelta::receiveNotification(Notification *notification, const NotificationFlags flags) {
+ Norad::receiveNotification(notification, flags);
+
+ if ((flags & kExtraCompletedFlag) != 0) {
+ RetScanChip *retScan;
+ Input dummy;
+
+ switch (_lastExtra) {
+ case kArriveFromSubChase:
+ GameState.setNoradArrivedFromSub(true);
+ GameState.setCurrentRoom(kNoRoomID);
+ GameState.setCurrentDirection(kNoDirection);
+ arriveAt(kNorad41, kEast);
+ break;
+ case kN59RobotHeadOpens:
+ case kN60RobotHeadOpens:
+ _privateFlags.setFlag(kNoradPrivateRobotHeadOpenFlag, true);
+ break;
+ case kNoradDeltaRetinalScanBad:
+ retScan = (RetScanChip *)_vm->getCurrentBiochip();
+ retScan->setItemState(kNormalItem);
+ playSpotSoundSync(kRetinalScanFailedIn, kRetinalScanFailedOut);
+ downButton(dummy);
+ break;
+ case kNoradDeltaRetinalScanGood:
+ retScan = (RetScanChip *)_vm->getCurrentBiochip();
+ retScan->setItemState(kNormalItem);
+ downButton(dummy);
+ break;
+ case kN59RobotDisappears:
+ case kN60RobotDisappears:
+ recallToTSASuccess();
+ break;
+ }
+
+ _interruptionFilter = kFilterAllInput;
+ }
+
+ g_AIArea->checkMiddleArea();
+}
+
+void NoradDelta::pickedUpItem(Item *item) {
+ switch (item->getObjectID()) {
+ case kShieldBiochip:
+ if (_privateFlags.getFlag(kNoradPrivateGotShieldChipFlag) &&
+ _privateFlags.getFlag(kNoradPrivateGotRetScanChipFlag) &&
+ _privateFlags.getFlag(kNoradPrivateGotOpticalChipFlag)) {
+ GameState.setNoradFinished(true);
+
+ if (GameState.getCurrentRoom() == kNorad59West)
+ startExtraSequence(kN59RobotDisappears, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kN60RobotDisappears, kExtraCompletedFlag, kFilterNoInput);
+ }
+ break;
+ case kRetinalScanBiochip:
+ if (_privateFlags.getFlag(kNoradPrivateGotShieldChipFlag) &&
+ _privateFlags.getFlag(kNoradPrivateGotRetScanChipFlag) &&
+ _privateFlags.getFlag(kNoradPrivateGotOpticalChipFlag)) {
+ GameState.setNoradFinished(true);
+
+ if (GameState.getCurrentRoom() == kNorad59West)
+ startExtraSequence(kN59RobotDisappears, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kN60RobotDisappears, kExtraCompletedFlag, kFilterNoInput);
+ }
+ break;
+ case kOpticalBiochip:
+ g_opticalChip->addPoseidon();
+ GameState.setScoringGotNoradOpMemChip();
+
+ if (_privateFlags.getFlag(kNoradPrivateGotShieldChipFlag) &&
+ _privateFlags.getFlag(kNoradPrivateGotRetScanChipFlag) &&
+ _privateFlags.getFlag(kNoradPrivateGotOpticalChipFlag)) {
+ GameState.setNoradFinished(true);
+
+ if (GameState.getCurrentRoom() == kNorad59West)
+ startExtraSequence(kN59RobotDisappears, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kN60RobotDisappears, kExtraCompletedFlag, kFilterNoInput);
+ }
+ break;
+ }
+
+ Norad::pickedUpItem(item);
+}
+
+void NoradDelta::takeItemFromRoom(Item *item) {
+ switch (item->getObjectID()) {
+ case kShieldBiochip:
+ _privateFlags.setFlag(kNoradPrivateGotShieldChipFlag, true);
+ break;
+ case kRetinalScanBiochip:
+ _privateFlags.setFlag(kNoradPrivateGotRetScanChipFlag, true);
+ break;
+ case kOpticalBiochip:
+ _privateFlags.setFlag(kNoradPrivateGotOpticalChipFlag, true);
+ break;
+ }
+
+ Norad::takeItemFromRoom(item);
+}
+
+void NoradDelta::dropItemIntoRoom(Item *item, Hotspot *hotspot) {
+ switch (item->getObjectID()) {
+ case kShieldBiochip:
+ _privateFlags.setFlag(kNoradPrivateGotShieldChipFlag, false);
+ break;
+ case kOpticalBiochip:
+ _privateFlags.setFlag(kNoradPrivateGotOpticalChipFlag, false);
+ break;
+ case kRetinalScanBiochip:
+ _privateFlags.setFlag(kNoradPrivateGotRetScanChipFlag, false);
+ break;
+ }
+
+ Norad::dropItemIntoRoom(item, hotspot);
+}
+
+Hotspot *NoradDelta::getItemScreenSpot(Item *item, DisplayElement *element) {
+ HotSpotID id = kNoHotSpotID;
+
+ switch (item->getObjectID()) {
+ case kShieldBiochip:
+ if (GameState.getNoradBeatRobotWithDoor())
+ id = kDelta59RobotShieldBiochipSpotID;
+ else
+ id = kDelta60RobotShieldBiochipSpotID;
+ break;
+ case kOpticalBiochip:
+ if (GameState.getNoradBeatRobotWithDoor())
+ id = kDelta59RobotOpMemBiochipSpotID;
+ else
+ id = kDelta60RobotOpMemBiochipSpotID;
+ break;
+ case kRetinalScanBiochip:
+ if (GameState.getNoradBeatRobotWithDoor())
+ id = kDelta59RobotRetinalBiochipSpotID;
+ else
+ id = kDelta60RobotRetinalBiochipSpotID;
+ break;
+ }
+
+ if (id != kNoHotSpotID)
+ return _vm->getAllHotspots().findHotspotByID(id);
+
+ return Norad::getItemScreenSpot(item, element);
+}
+
+Common::String NoradDelta::getEnvScanMovie() {
+ return "Images/AI/Norad/XNE2";
+}
+
+uint NoradDelta::getNumHints() {
+ uint numHints = Neighborhood::getNumHints();
+
+ if (numHints == 0) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kNorad60, kWest):
+ if (GameState.getNoradPlayedGlobeGame())
+ numHints = 2;
+ else
+ numHints = 1;
+ break;
+ case MakeRoomView(kNorad59, kNorth):
+ case MakeRoomView(kNorad59, kSouth):
+ case MakeRoomView(kNorad59, kEast):
+ case MakeRoomView(kNorad59, kWest):
+ case MakeRoomView(kNorad60, kNorth):
+ case MakeRoomView(kNorad60, kSouth):
+ case MakeRoomView(kNorad60, kEast):
+ if (GameState.getNoradPlayedGlobeGame())
+ numHints = 2;
+ break;
+ case MakeRoomView(kNorad68, kWest):
+ if (_vm->playerHasItemID(kRetinalScanBiochip)) {
+ BiochipItem *retScan = _vm->getCurrentBiochip();
+ if (retScan == 0 || retScan->getObjectID() != kRetinalScanBiochip)
+ numHints = 2;
+ } else if (!GameState.isCurrentDoorOpen()) {
+ numHints = 2;
+ }
+ break;
+ }
+ }
+
+ return numHints;
+}
+
+Common::String NoradDelta::getHintMovie(uint hintNum) {
+ Common::String movieName = Neighborhood::getHintMovie(hintNum);
+
+ if (movieName.empty()) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kNorad60, kWest):
+ if (GameState.getNoradPlayedGlobeGame()) {
+ if (hintNum == 1)
+ return "Images/AI/Norad/XN60WD2";
+
+ return "Images/AI/Norad/XN60WD3";
+ }
+
+ return "Images/AI/Globals/XGLOB1C";
+ case MakeRoomView(kNorad59, kNorth):
+ case MakeRoomView(kNorad59, kSouth):
+ case MakeRoomView(kNorad59, kEast):
+ case MakeRoomView(kNorad59, kWest):
+ case MakeRoomView(kNorad60, kNorth):
+ case MakeRoomView(kNorad60, kSouth):
+ case MakeRoomView(kNorad60, kEast):
+ if (hintNum == 1)
+ return "Images/AI/Norad/XN60WD2";
+
+ return "Images/AI/Norad/XN60WD3";
+ case MakeRoomView(kNorad68, kWest):
+ if (_vm->playerHasItemID(kRetinalScanBiochip)) {
+ if (hintNum == 1)
+ return "Images/AI/Globals/XGLOB1A";
+
+ return "Images/AI/Globals/XGLOB1C";
+ }
+
+ if (hintNum == 1)
+ return "Images/AI/Globals/XGLOB1B";
+
+ return "Images/AI/Globals/XGLOB3B";
+ }
+ }
+
+ return movieName;
+}
+
+void NoradDelta::closeDoorOffScreen(const RoomID room, const DirectionConstant) {
+ switch (room) {
+ case kNorad47:
+ case kNorad48:
+ case kNorad41:
+ case kNorad42:
+ playSpotSoundSync(kDeltaElevatorDoorCloseIn, kDeltaElevatorDoorCloseOut);
+ break;
+ default:
+ playSpotSoundSync(kDeltaRegDoorCloseIn, kDeltaRegDoorCloseOut);
+ break;
+ }
+}
+
+bool NoradDelta::canSolve() {
+ if (Norad::canSolve())
+ return true;
+
+ if (GameState.getCurrentRoomAndView() == MakeRoomView(kNorad68, kWest)) {
+ BiochipItem *biochip = _vm->getCurrentBiochip();
+ if (biochip != 0 && biochip->getObjectID() != kRetinalScanBiochip)
+ return true;
+ }
+
+ return false;
+}
+
+void NoradDelta::doSolve() {
+ Norad::doSolve();
+
+ if (GameState.getCurrentRoomAndView() == MakeRoomView(kNorad68, kWest)) {
+ if (!_vm->playerHasItemID(kRetinalScanBiochip))
+ _vm->addItemToBiochips((BiochipItem *)_vm->getAllItems().findItemByID(kRetinalScanBiochip));
+
+ BiochipItem *biochip = _vm->getCurrentBiochip();
+ if (biochip != 0 && biochip->getObjectID() != kRetinalScanBiochip && g_interface)
+ g_interface->setCurrentBiochipID(kRetinalScanBiochip);
+
+ Hotspot *spot = _vm->getAllHotspots().findHotspotByID(kNorad68WestSpotID);
+ Input scratch;
+ InputHandler::_inputHandler->clickInHotspot(scratch, spot);
+ }
+}
+
+Common::String NoradDelta::getSoundSpotsName() {
+ return "Sounds/Norad/Norad Delta Spots";
+}
+
+Common::String NoradDelta::getNavMovieName() {
+ return "Images/Norad Delta/Norad Delta.movie";
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/norad/delta/noraddelta.h b/engines/pegasus/neighborhood/norad/delta/noraddelta.h
new file mode 100644
index 0000000000..11065f2c9d
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/delta/noraddelta.h
@@ -0,0 +1,117 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_NORAD_DELTA_NORADDELTA_H
+#define PEGASUS_NEIGHBORHOOD_NORAD_DELTA_NORADDELTA_H
+
+#include "pegasus/neighborhood/norad/norad.h"
+
+namespace Pegasus {
+
+class NoradDelta : public Norad {
+public:
+ NoradDelta(InputHandler *, PegasusEngine *);
+ virtual ~NoradDelta() {}
+
+ void init();
+
+ void start();
+
+ void getExtraCompassMove(const ExtraTable::Entry &, FaderMoveSpec &);
+
+ void finishedGlobeGame();
+
+ virtual GameInteraction *makeInteraction(const InteractionID);
+
+ void playClawMonitorIntro();
+
+ virtual void getClawInfo(HotSpotID &outSpotID, HotSpotID &prepSpotID, HotSpotID &clawControlSpotID,
+ HotSpotID &pinchClawSpotID, HotSpotID &moveClawDownSpotID, HotSpotID &moveClawRightSpotID,
+ HotSpotID &moveClawLeftSpotID, HotSpotID &moveClawUpSpotID, HotSpotID &clawCCWSpotID,
+ HotSpotID &clawCWSpotID, uint32 &, const uint32 *&);
+
+ void playerBeatRobotWithClaw();
+ void playerBeatRobotWithDoor();
+
+ void loadAmbientLoops();
+
+ void setUpAIRules();
+ Common::String getEnvScanMovie();
+ uint getNumHints();
+ Common::String getHintMovie(uint);
+ void closeDoorOffScreen(const RoomID, const DirectionConstant);
+
+ void checkContinuePoint(const RoomID, const DirectionConstant);
+
+ bool canSolve();
+ void doSolve();
+
+ void doorOpened();
+
+protected:
+ enum {
+ kNoradPrivateArrivedFromSubFlag,
+ kNoradPrivateFinishedGlobeGameFlag,
+ kNoradPrivateRobotHeadOpenFlag,
+ kNoradPrivateGotShieldChipFlag,
+ kNoradPrivateGotOpticalChipFlag,
+ kNoradPrivateGotRetScanChipFlag,
+ kNumNoradPrivateFlags
+ };
+
+ static const uint32 _noradDeltaClawExtras[22];
+
+ void getExitEntry(const RoomID, const DirectionConstant, ExitTable::Entry &);
+ void getZoomEntry(const HotSpotID, ZoomTable::Entry &);
+ virtual void arriveAt(const RoomID, const DirectionConstant);
+ void arriveAtNorad68West();
+ void arriveAtNorad79West();
+ TimeValue getViewTime(const RoomID, const DirectionConstant);
+ void openDoor();
+ void activateHotspots();
+ void clickInHotspot(const Input &, const Hotspot *);
+ void receiveNotification(Notification *, const NotificationFlags);
+ void pickedUpItem(Item *item);
+ void takeItemFromRoom(Item *item);
+ void dropItemIntoRoom(Item *item, Hotspot *);
+ Hotspot *getItemScreenSpot(Item *, DisplayElement *);
+
+ virtual bool playingAgainstRobot();
+
+ void failRetinalScan();
+ void succeedRetinalScan();
+ void getDoorEntry(const RoomID, const DirectionConstant, DoorTable::Entry &);
+
+ void bumpIntoWall();
+
+ FlagsArray<byte, kNumNoradPrivateFlags> _privateFlags;
+
+ Common::String getSoundSpotsName();
+ Common::String getNavMovieName();
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/norad/norad.cpp b/engines/pegasus/neighborhood/norad/norad.cpp
new file mode 100644
index 0000000000..578f062dea
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/norad.cpp
@@ -0,0 +1,285 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/energymonitor.h"
+#include "pegasus/gamestate.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/inventory/airmask.h"
+#include "pegasus/neighborhood/norad/constants.h"
+#include "pegasus/neighborhood/norad/norad.h"
+#include "pegasus/neighborhood/norad/noradelevator.h"
+#include "pegasus/neighborhood/norad/pressuredoor.h"
+#include "pegasus/neighborhood/norad/subcontrolroom.h"
+#include "pegasus/neighborhood/norad/subplatform.h"
+
+namespace Pegasus {
+
+const NotificationFlags kDoneWithPressureDoorNotification = 1;
+
+const NotificationFlags kNoradNotificationFlags = kDoneWithPressureDoorNotification;
+
+// This class handles everything that Norad Alpha and Delta have in common, such as
+// oxygen mask usage, the elevator and the pressure doors.
+
+Norad::Norad(InputHandler *nextHandler, PegasusEngine *vm, const Common::String &resName, NeighborhoodID id) :
+ Neighborhood(nextHandler, vm, resName, id), _noradNotification(kNoradNotificationID, vm) {
+ _elevatorUpSpotID = kNoHotSpotID;
+ _elevatorDownSpotID = kNoHotSpotID;
+ _elevatorUpRoomID = kNoHotSpotID;
+ _elevatorDownRoomID = kNoHotSpotID;
+
+ _subRoomEntryRoom1 = kNoRoomID;
+ _subRoomEntryDir1 = kNoDirection;
+ _subRoomEntryRoom2 = kNoRoomID;
+ _subRoomEntryDir2 = kNoDirection;
+ _upperPressureDoorRoom = kNoRoomID;
+ _lowerPressureDoorRoom = kNoRoomID;
+
+ _upperPressureDoorUpSpotID = kNoHotSpotID;
+ _upperPressureDoorDownSpotID = kNoHotSpotID;
+ _upperPressureDoorAbortSpotID = kNoHotSpotID;
+
+ _lowerPressureDoorUpSpotID = kNoHotSpotID;
+ _lowerPressureDoorDownSpotID = kNoHotSpotID;
+ _lowerPressureDoorAbortSpotID = kNoHotSpotID;
+
+ _pressureSoundIn = 0xffffffff;
+ _pressureSoundOut = 0xffffffff;
+ _equalizeSoundIn = 0xffffffff;
+ _equalizeSoundOut = 0xffffffff;
+ _accessDeniedIn = 0xffffffff;
+ _accessDeniedOut = 0xffffffff;
+
+ _platformRoom = kNoRoomID;
+ _subControlRoom = kNoRoomID;
+
+ _doneWithPressureDoor = false;
+
+ _noradNotification.notifyMe(this, kNoradNotificationFlags, kNoradNotificationFlags);
+}
+
+GameInteraction *Norad::makeInteraction(const InteractionID interactionID) {
+ PressureDoor *pressureDoor;
+ SubControlRoom *subControl;
+
+ switch (interactionID) {
+ case kNoradElevatorInteractionID:
+ return new NoradElevator(this, _elevatorUpRoomID, _elevatorDownRoomID, _elevatorUpSpotID, _elevatorDownSpotID);
+ case kNoradPressureDoorInteractionID:
+ if (GameState.getCurrentRoom() == _upperPressureDoorRoom)
+ pressureDoor = new PressureDoor(this, true, _upperPressureDoorUpSpotID, _upperPressureDoorDownSpotID,
+ _upperPressureDoorAbortSpotID, _pressureSoundIn, _pressureSoundOut, _equalizeSoundIn, _equalizeSoundOut);
+ else
+ pressureDoor = new PressureDoor(this, false, _lowerPressureDoorUpSpotID, _lowerPressureDoorDownSpotID,
+ _lowerPressureDoorAbortSpotID, _pressureSoundIn, _pressureSoundOut, _equalizeSoundIn, _equalizeSoundOut);
+
+ if (GameState.getCurrentRoom() == kNorad59West && playingAgainstRobot())
+ pressureDoor->playAgainstRobot();
+
+ return pressureDoor;
+ case kNoradSubControlRoomInteractionID:
+ subControl = new SubControlRoom(this);
+
+ if (GameState.getCurrentRoom() == kNorad60West && playingAgainstRobot())
+ subControl->playAgainstRobot();
+
+ return subControl;
+ case kNoradSubPlatformInteractionID:
+ return new SubPlatform(this);
+ default:
+ return 0;
+ }
+}
+
+void Norad::flushGameState() {
+ g_energyMonitor->saveCurrentEnergyValue();
+}
+
+void Norad::start() {
+ setUpAirMask();
+ Neighborhood::start();
+}
+
+void Norad::activateHotspots() {
+ Neighborhood::activateHotspots();
+
+ RoomID room = GameState.getCurrentRoom();
+ if (room == _elevatorUpRoomID)
+ _neighborhoodHotspots.activateOneHotspot(_elevatorDownSpotID);
+ else if (room == _elevatorDownRoomID)
+ _neighborhoodHotspots.activateOneHotspot(_elevatorUpSpotID);
+}
+
+void Norad::arriveAt(const RoomID room, const DirectionConstant direction) {
+ Neighborhood::arriveAt(room, direction);
+
+ if (GameState.getCurrentRoom() == _elevatorUpRoomID || GameState.getCurrentRoom() == _elevatorDownRoomID)
+ arriveAtNoradElevator();
+ else if (GameState.getCurrentRoom() == _upperPressureDoorRoom)
+ arriveAtUpperPressureDoorRoom();
+ else if (GameState.getCurrentRoom() == _lowerPressureDoorRoom)
+ arriveAtLowerPressureDoorRoom();
+ else if (GameState.getCurrentRoom() == _platformRoom)
+ arriveAtSubPlatformRoom();
+ else if (GameState.getCurrentRoom() == _subControlRoom)
+ arriveAtSubControlRoom();
+
+ if (_doneWithPressureDoor) {
+ _doneWithPressureDoor = false;
+ openDoor();
+ }
+}
+
+void Norad::arriveAtNoradElevator() {
+ if (_currentInteraction)
+ _currentInteraction->startOverInteraction();
+ else
+ newInteraction(kNoradElevatorInteractionID);
+}
+
+void Norad::arriveAtUpperPressureDoorRoom() {
+ newInteraction(kNoradPressureDoorInteractionID);
+}
+
+void Norad::arriveAtLowerPressureDoorRoom() {
+ newInteraction(kNoradPressureDoorInteractionID);
+}
+
+void Norad::arriveAtSubPlatformRoom() {
+ newInteraction(kNoradSubPlatformInteractionID);
+}
+
+void Norad::arriveAtSubControlRoom() {
+ newInteraction(kNoradSubControlRoomInteractionID);
+}
+
+int16 Norad::getStaticCompassAngle(const RoomID room, const DirectionConstant dir) {
+ int16 result = Neighborhood::getStaticCompassAngle(room, dir);
+
+ if (room == _elevatorUpRoomID || room == _elevatorDownRoomID)
+ result += kElevatorCompassAngle;
+ else if (room == _platformRoom)
+ result += kSubPlatformCompassAngle;
+ else if (room == _subControlRoom)
+ result += kSubControlCompassAngle;
+
+ return result;
+}
+
+CanOpenDoorReason Norad::canOpenDoor(DoorTable::Entry &entry) {
+ if (((GameState.getCurrentRoom() == _subRoomEntryRoom1 && GameState.getCurrentDirection() == _subRoomEntryDir1) ||
+ (GameState.getCurrentRoom() == _subRoomEntryRoom2 && GameState.getCurrentDirection() == _subRoomEntryDir2)) &&
+ GameState.getNoradSubRoomPressure() != kNormalSubRoomPressure)
+ return kCantOpenBadPressure;
+
+ return Neighborhood::canOpenDoor(entry);
+}
+
+void Norad::cantOpenDoor(CanOpenDoorReason reason) {
+ if (reason == kCantOpenBadPressure)
+ playSpotSoundSync(_pressureSoundIn, _pressureSoundOut);
+ else
+ playSpotSoundSync(_accessDeniedIn, _accessDeniedOut);
+}
+
+void Norad::startExitMovie(const ExitTable::Entry &exitEntry) {
+ if (GameState.getCurrentRoom() == _elevatorUpRoomID) {
+ if (exitEntry.exitRoom != _elevatorDownRoomID)
+ newInteraction(kNoInteractionID);
+ } else if (GameState.getCurrentRoom() == _elevatorDownRoomID) {
+ if (exitEntry.exitRoom != _elevatorUpRoomID)
+ newInteraction(kNoInteractionID);
+ } else {
+ newInteraction(kNoInteractionID);
+ }
+
+ Neighborhood::startExitMovie(exitEntry);
+}
+
+void Norad::startZoomMovie(const ZoomTable::Entry &zoomEntry) {
+ newInteraction(kNoInteractionID);
+ Neighborhood::startZoomMovie(zoomEntry);
+}
+
+void Norad::upButton(const Input &input) {
+ if (GameState.getCurrentRoom() != _elevatorUpRoomID && GameState.getCurrentRoom() != _elevatorDownRoomID)
+ Neighborhood::upButton(input);
+}
+
+void Norad::setUpAirMask() {
+ _airMaskCallBack.setNotification(&_neighborhoodNotification);
+ _airMaskCallBack.initCallBack(&_airMaskTimer, kCallBackAtExtremes);
+ _airMaskCallBack.setCallBackFlag(kAirTimerExpiredFlag);
+ _neighborhoodNotification.notifyMe(this, kAirTimerExpiredFlag, kAirTimerExpiredFlag);
+ _airMaskCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ _airMaskTimer.setScale(1);
+ _airMaskTimer.setSegment(0, kNoradAirMaskTimeLimit);
+ checkAirMask();
+}
+
+void Norad::checkAirMask() {
+ if (g_airMask && g_airMask->isAirFilterOn()) {
+ _airMaskTimer.stop();
+ } else if (GameState.getNoradGassed() && !_airMaskTimer.isRunning()) {
+ _airMaskTimer.setTime(0);
+ _airMaskTimer.start();
+ }
+
+ loadAmbientLoops();
+}
+
+void Norad::receiveNotification(Notification *notification, const NotificationFlags flags) {
+ if (notification == &_neighborhoodNotification && (flags & kAirTimerExpiredFlag) != 0)
+ ((PegasusEngine *)g_engine)->die(kDeathGassedInNorad);
+
+ Neighborhood::receiveNotification(notification, flags);
+
+ if (notification == &_noradNotification) {
+ // Must be kDoneWithPressureDoorNotification...
+ Input scratch;
+ _doneWithPressureDoor = true;
+ downButton(scratch);
+ }
+}
+
+uint16 Norad::getDateResID() const {
+ return kDate2112ID;
+}
+
+Common::String Norad::getBriefingMovie() {
+ return "Images/AI/Norad/XNO";
+}
+
+void Norad::pickedUpItem(Item *item) {
+ Neighborhood::pickedUpItem(item);
+ g_AIArea->checkMiddleArea();
+}
+
+void Norad::doneWithPressureDoor() {
+ _noradNotification.setNotificationFlags(kDoneWithPressureDoorNotification, kDoneWithPressureDoorNotification);
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/norad/norad.h b/engines/pegasus/neighborhood/norad/norad.h
new file mode 100644
index 0000000000..3cd77cc54b
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/norad.h
@@ -0,0 +1,121 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_NORAD_NORAD_H
+#define PEGASUS_NEIGHBORHOOD_NORAD_NORAD_H
+
+#include "pegasus/neighborhood/neighborhood.h"
+
+namespace Pegasus {
+
+// This is the code common to both Norad Alpha and Norad Delta
+
+class Norad : public Neighborhood {
+public:
+ Norad(InputHandler *, PegasusEngine *owner, const Common::String &resName, const NeighborhoodID);
+ virtual ~Norad() {}
+
+ void flushGameState();
+
+ virtual void start();
+
+ virtual void getClawInfo(HotSpotID &outSpotID, HotSpotID &prepSpotID,
+ HotSpotID &clawControlSpotID, HotSpotID &pinchClawSpotID,
+ HotSpotID &moveClawDownSpotID, HotSpotID &moveClawRightSpotID,
+ HotSpotID &moveClawLeftSpotID,HotSpotID &moveClawUpSpotID,
+ HotSpotID &clawCCWSpotID, HotSpotID &clawCWSpotID, uint32 &, const uint32 *&) = 0;
+ void checkAirMask();
+
+ virtual uint16 getDateResID() const;
+
+ virtual GameInteraction *makeInteraction(const InteractionID);
+
+ Common::String getBriefingMovie();
+
+ void pickedUpItem(Item *);
+
+ virtual void playClawMonitorIntro() {}
+
+ void doneWithPressureDoor();
+
+protected:
+ CanOpenDoorReason canOpenDoor(DoorTable::Entry &);
+ void cantOpenDoor(CanOpenDoorReason);
+ int16 getStaticCompassAngle(const RoomID, const DirectionConstant);
+ virtual void startExitMovie(const ExitTable::Entry &);
+ void startZoomMovie(const ZoomTable::Entry &);
+ virtual void upButton(const Input &);
+ virtual void activateHotspots();
+
+ virtual void arriveAt(const RoomID, const DirectionConstant);
+ virtual void arriveAtNoradElevator();
+ virtual void arriveAtUpperPressureDoorRoom();
+ virtual void arriveAtLowerPressureDoorRoom();
+ virtual void arriveAtSubPlatformRoom();
+ virtual void arriveAtSubControlRoom();
+ void setUpAirMask();
+ virtual void receiveNotification(Notification *, const NotificationFlags);
+ virtual bool playingAgainstRobot() { return false; }
+
+ Notification _noradNotification;
+ bool _doneWithPressureDoor;
+
+ RoomID _elevatorUpRoomID;
+ RoomID _elevatorDownRoomID;
+ HotSpotID _elevatorUpSpotID;
+ HotSpotID _elevatorDownSpotID;
+
+ TimeBase _airMaskTimer;
+ NotificationCallBack _airMaskCallBack;
+
+ RoomID _subRoomEntryRoom1;
+ DirectionConstant _subRoomEntryDir1;
+ RoomID _subRoomEntryRoom2;
+ DirectionConstant _subRoomEntryDir2;
+ RoomID _upperPressureDoorRoom;
+ RoomID _lowerPressureDoorRoom;
+
+ HotSpotID _upperPressureDoorUpSpotID;
+ HotSpotID _upperPressureDoorDownSpotID;
+ HotSpotID _upperPressureDoorAbortSpotID;
+
+ HotSpotID _lowerPressureDoorUpSpotID;
+ HotSpotID _lowerPressureDoorDownSpotID;
+ HotSpotID _lowerPressureDoorAbortSpotID;
+
+ TimeValue _pressureSoundIn;
+ TimeValue _pressureSoundOut;
+ TimeValue _equalizeSoundIn;
+ TimeValue _equalizeSoundOut;
+ TimeValue _accessDeniedIn;
+ TimeValue _accessDeniedOut;
+
+ RoomID _platformRoom;
+ RoomID _subControlRoom;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/norad/noradelevator.cpp b/engines/pegasus/neighborhood/norad/noradelevator.cpp
new file mode 100644
index 0000000000..1751f4dcb6
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/noradelevator.cpp
@@ -0,0 +1,130 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/gamestate.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/neighborhood/norad/constants.h"
+#include "pegasus/neighborhood/norad/norad.h"
+#include "pegasus/neighborhood/norad/noradelevator.h"
+
+namespace Pegasus {
+
+// Norad elevator PICTs:
+static const ResIDType kElevatorLabelID = 200;
+static const ResIDType kElevatorButtonsID = 201;
+static const ResIDType kElevatorDownOnID = 202;
+static const ResIDType kElevatorUpOnID = 203;
+
+NoradElevator::NoradElevator(Neighborhood *handler, const RoomID upRoom, const RoomID downRoom,
+ const HotSpotID upHotspot, const HotSpotID downHotspot) : GameInteraction(kNoradElevatorInteractionID, handler),
+ _elevatorControls(kNoradElevatorControlsID), _elevatorNotification(kNoradElevatorNotificationID, ((PegasusEngine *)g_engine)) {
+ _timerExpired = false;
+ _upRoom = upRoom;
+ _downRoom = downRoom;
+ _upHotspot = upHotspot;
+ _downHotspot = downHotspot;
+}
+
+void NoradElevator::openInteraction() {
+ SpriteFrame *frame = new SpriteFrame();
+ frame->initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kElevatorLabelID, true);
+ _elevatorControls.addFrame(frame, 0, 0);
+
+ frame = new SpriteFrame();
+ frame->initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kElevatorButtonsID, true);
+ _elevatorControls.addFrame(frame, 0, 0);
+
+ frame = new SpriteFrame();
+ frame->initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kElevatorDownOnID, true);
+ _elevatorControls.addFrame(frame, 0, 0);
+
+ frame = new SpriteFrame();
+ frame->initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kElevatorUpOnID, true);
+ _elevatorControls.addFrame(frame, 0, 0);
+
+ _elevatorControls.setCurrentFrameIndex(0);
+ _elevatorControls.setDisplayOrder(kElevatorControlsOrder);
+
+ Common::Rect r;
+ frame->getSurfaceBounds(r);
+ r.moveTo(kNoradAlphaElevatorControlsLeft, kNoradAlphaElevatorControlsTop);
+
+ _elevatorControls.setBounds(r);
+ _elevatorControls.startDisplaying();
+ _elevatorControls.show();
+}
+
+void NoradElevator::initInteraction() {
+ _elevatorTimer.setScale(2);
+ _elevatorTimer.setSegment(0, 1);
+ _elevatorCallBack.initCallBack(&_elevatorTimer, kCallBackAtExtremes);
+ _elevatorCallBack.setCallBackFlag(1);
+ _elevatorCallBack.setNotification(&_elevatorNotification);
+ _elevatorNotification.notifyMe(this, 1, 1);
+ _elevatorCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ _elevatorTimer.start();
+}
+
+void NoradElevator::closeInteraction() {
+ _elevatorControls.stopDisplaying();
+ _elevatorControls.discardFrames();
+ _elevatorCallBack.releaseCallBack();
+}
+
+void NoradElevator::resetInteraction() {
+ _elevatorControls.setCurrentFrameIndex(1);
+}
+
+void NoradElevator::activateHotspots() {
+ GameInteraction::activateHotspots();
+
+ if (_timerExpired) {
+ if (GameState.getCurrentRoom() == _upRoom)
+ g_allHotspots.activateOneHotspot(_downHotspot);
+ else if (GameState.getCurrentRoom() == _downRoom)
+ g_allHotspots.activateOneHotspot(_upHotspot);
+ }
+}
+
+void NoradElevator::clickInHotspot(const Input &input, const Hotspot *spot) {
+ HotSpotID id = spot->getObjectID();
+
+ if (id == _upHotspot || id == _downHotspot) {
+ g_neighborhood->moveForward();
+ if (id == _downHotspot)
+ _elevatorControls.setCurrentFrameIndex(2);
+ else
+ _elevatorControls.setCurrentFrameIndex(3);
+ } else {
+ GameInteraction::clickInHotspot(input, spot);
+ }
+}
+
+void NoradElevator::receiveNotification(Notification *, const NotificationFlags) {
+ _elevatorControls.setCurrentFrameIndex(1);
+ _timerExpired = true;
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/norad/noradelevator.h b/engines/pegasus/neighborhood/norad/noradelevator.h
new file mode 100644
index 0000000000..24aa488534
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/noradelevator.h
@@ -0,0 +1,67 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_NORAD_NORADELEVATOR_H
+#define PEGASUS_NEIGHBORHOOD_NORAD_NORADELEVATOR_H
+
+#include "pegasus/interaction.h"
+#include "pegasus/notification.h"
+#include "pegasus/surface.h"
+#include "pegasus/timers.h"
+
+namespace Pegasus {
+
+class Neighborhood;
+
+class NoradElevator : public GameInteraction, private NotificationReceiver {
+public:
+ NoradElevator(Neighborhood *, const RoomID, const RoomID, const HotSpotID, const HotSpotID);
+ virtual ~NoradElevator() {}
+
+protected:
+ virtual void openInteraction();
+ virtual void initInteraction();
+ virtual void closeInteraction();
+ virtual void resetInteraction();
+
+ virtual void activateHotspots();
+ virtual void clickInHotspot(const Input &, const Hotspot *);
+
+ virtual void receiveNotification(Notification *, const NotificationFlags);
+
+ RoomID _upRoom;
+ RoomID _downRoom;
+ HotSpotID _upHotspot;
+ HotSpotID _downHotspot;
+ Sprite _elevatorControls;
+ TimeBase _elevatorTimer;
+ NotificationCallBack _elevatorCallBack;
+ Notification _elevatorNotification;
+ bool _timerExpired;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/norad/pressuredoor.cpp b/engines/pegasus/neighborhood/norad/pressuredoor.cpp
new file mode 100644
index 0000000000..d1378567d3
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/pressuredoor.cpp
@@ -0,0 +1,554 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/gamestate.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/neighborhood/norad/constants.h"
+#include "pegasus/neighborhood/norad/norad.h"
+#include "pegasus/neighborhood/norad/pressuredoor.h"
+#include "pegasus/neighborhood/norad/delta/noraddelta.h"
+
+namespace Pegasus {
+
+static const TimeValue kLevelsSplashStart = 0;
+static const TimeValue kLevelsSplashStop = 1;
+static const TimeValue kPressureBase = 1;
+
+static const TimeValue kDoorSealedTime = 0;
+static const TimeValue kEqualizeTime = 1;
+static const TimeValue kMaxPressureLoopStart = 2;
+static const TimeValue kMaxPressureLoopStop = 3;
+static const TimeValue kOpeningDoorLoopStart = 3;
+static const TimeValue kOpeningDoorLoopStop = 4;
+static const TimeValue kIncreasingPressureTime = 4;
+static const TimeValue kDecreasingPressureTime = 5;
+static const TimeValue kCautionLoopStart = 6;
+static const TimeValue kCautionLoopStop = 7;
+
+static const NotificationFlags kSplashFinished = 1;
+static const NotificationFlags kPressureDroppingFlag = kSplashFinished << 1;
+
+static const NotificationFlags kPressureNotificationFlags = kSplashFinished |
+ kPressureDroppingFlag;
+
+static const NotificationFlags kDoorJumpsUpFlag = 1;
+static const NotificationFlags kDoorJumpsBackFlag = kDoorJumpsUpFlag << 1;
+static const NotificationFlags kDoorCrushedFlag = kDoorJumpsBackFlag << 1;
+
+static const NotificationFlags kUtilityNotificationFlags = kDoorJumpsUpFlag |
+ kDoorJumpsBackFlag |
+ kDoorCrushedFlag;
+
+enum {
+ kPlayingRobotApproaching,
+ kRobotPunching,
+ kRobotComingThrough,
+ kRobotDying,
+ kRobotDead
+};
+
+const short kMaxPunches = 5;
+
+enum {
+ kPlayingSplash,
+ kPlayingPressureMessage,
+ kPlayingEqualizeMessage,
+ kWaitingForPlayer,
+ kPlayingDoneMessage,
+ kGameOver
+};
+
+// Pressure values range from 0 to 11.
+static const short kMinPressure = 0;
+static const short kMaxPressure = 11;
+
+static const TimeScale kNavTimeScale = 600;
+static const TimeValue kNavFrameRate = 15;
+static const TimeValue kNavTimePerFrame = kNavTimeScale / kNavFrameRate;
+
+static const TimeValue kApproachPunchInTime = 122 * kNavTimePerFrame;
+static const TimeValue kLoopPunchInTime = 38 * kNavTimePerFrame;
+static const TimeValue kPunchThroughTime = 38 * kNavTimePerFrame;
+
+// Pressure door PICTs:
+static const ResIDType kUpperPressureUpOffPICTID = 400;
+static const ResIDType kUpperPressureUpOnPICTID = 401;
+static const ResIDType kUpperPressureDownOffPICTID = 402;
+static const ResIDType kUpperPressureDownOnPICTID = 403;
+
+static const ResIDType kLowerPressureUpOffPICTID = 404;
+static const ResIDType kLowerPressureUpOnPICTID = 405;
+static const ResIDType kLowerPressureDownOffPICTID = 406;
+static const ResIDType kLowerPressureDownOnPICTID = 407;
+
+PressureDoor::PressureDoor(Neighborhood *handler, bool isUpperDoor, const HotSpotID upSpotID, const HotSpotID downSpotID,
+ const HotSpotID outSpotID, TimeValue pressureSoundIn, TimeValue pressureSoundOut, TimeValue equalizeSoundIn,
+ TimeValue equalizeSoundOut) : GameInteraction(kNoradPressureDoorInteractionID, handler),
+ _levelsMovie(kPressureDoorLevelsID), _typeMovie(kPressureDoorTypeID), _upButton(kPressureDoorUpButtonID),
+ _downButton(kPressureDoorDownButtonID), _pressureNotification(kNoradPressureNotificationID, ((PegasusEngine *)g_engine)),
+ _doorTracker(this), _utilityNotification(kNoradUtilityNotificationID, ((PegasusEngine *)g_engine)) {
+ _neighborhoodNotification = handler->getNeighborhoodNotification();
+ _upHotspotID = upSpotID;
+ _downHotspotID = downSpotID;
+ _outHotspotID = outSpotID;
+ _pressureSoundIn = pressureSoundIn;
+ _pressureSoundOut = pressureSoundOut;
+ _equalizeSoundIn = equalizeSoundIn;
+ _equalizeSoundOut = equalizeSoundOut;
+ _playingAgainstRobot = false;
+ _isUpperDoor = isUpperDoor;
+}
+
+void PressureDoor::openInteraction() {
+ if (_isUpperDoor) {
+ _levelsMovie.initFromMovieFile("Images/Norad Alpha/Upper Levels Movie");
+ _levelsMovie.moveElementTo(kNoradUpperLevelsLeft, kNoradUpperLevelsTop);
+ } else {
+ _levelsMovie.initFromMovieFile("Images/Norad Alpha/Lower Levels Movie");
+ _levelsMovie.moveElementTo(kNoradLowerLevelsLeft, kNoradLowerLevelsTop);
+ }
+
+ _levelsScale = _levelsMovie.getScale();
+ _levelsMovie.setDisplayOrder(kPressureLevelsOrder);
+ _levelsMovie.startDisplaying();
+ _levelsMovie.setSegment(kLevelsSplashStart * _levelsScale, kLevelsSplashStop * _levelsScale);
+ _levelsMovie.setTime(kLevelsSplashStart * _levelsScale);
+ _levelsMovie.redrawMovieWorld();
+ _levelsMovie.show();
+
+ _pressureCallBack.setNotification(&_pressureNotification);
+ _pressureCallBack.initCallBack(&_levelsMovie, kCallBackAtExtremes);
+ _pressureCallBack.setCallBackFlag(kSplashFinished);
+ _pressureCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+
+ _pressureNotification.notifyMe(this, kPressureNotificationFlags, kPressureNotificationFlags);
+
+ if (_isUpperDoor) {
+ _typeMovie.initFromMovieFile("Images/Norad Alpha/Upper Type Movie");
+ _typeMovie.moveElementTo(kNoradUpperTypeLeft, kNoradUpperTypeTop);
+ } else {
+ _typeMovie.initFromMovieFile("Images/Norad Alpha/Lower Type Movie");
+ _typeMovie.moveElementTo(kNoradLowerTypeLeft, kNoradLowerTypeTop);
+ }
+
+ _typeScale = _typeMovie.getScale();
+ _typeMovie.setDisplayOrder(kPressureTypeOrder);
+ _typeMovie.startDisplaying();
+ _typeMovie.setTime(kDoorSealedTime * _typeScale);
+ _typeMovie.redrawMovieWorld();
+
+ SpriteFrame *frame = new SpriteFrame();
+ if (_isUpperDoor)
+ frame->initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kLowerPressureUpOffPICTID);
+ else
+ frame->initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kUpperPressureUpOffPICTID);
+ _upButton.addFrame(frame, 0, 0);
+
+ frame = new SpriteFrame();
+ if (_isUpperDoor)
+ frame->initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kLowerPressureUpOnPICTID);
+ else
+ frame->initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kUpperPressureUpOnPICTID);
+ _upButton.addFrame(frame, 0, 0);
+
+ _upButton.setCurrentFrameIndex(0);
+ _upButton.setDisplayOrder(kPressureUpOrder);
+
+ Common::Rect r;
+ frame->getSurfaceBounds(r);
+ if (_isUpperDoor)
+ r.moveTo(kNoradUpperUpLeft, kNoradUpperUpTop);
+ else
+ r.moveTo(kNoradLowerUpLeft, kNoradLowerUpTop);
+
+ _upButton.setBounds(r);
+ _upButton.startDisplaying();
+ _upButton.show();
+
+ frame = new SpriteFrame();
+ if (_isUpperDoor)
+ frame->initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kLowerPressureDownOffPICTID);
+ else
+ frame->initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kUpperPressureDownOffPICTID);
+ _downButton.addFrame(frame, 0, 0);
+
+ frame = new SpriteFrame();
+ if (_isUpperDoor)
+ frame->initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kLowerPressureDownOnPICTID);
+ else
+ frame->initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kUpperPressureDownOnPICTID);
+ _downButton.addFrame(frame, 0, 0);
+
+ _downButton.setCurrentFrameIndex(0);
+ _downButton.setDisplayOrder(kPressureDownOrder);
+
+ frame->getSurfaceBounds(r);
+ if (_isUpperDoor)
+ r.moveTo(kNoradUpperDownLeft, kNoradUpperDownTop);
+ else
+ r.moveTo(kNoradLowerDownLeft, kNoradLowerDownTop);
+
+ _downButton.setBounds(r);
+ _downButton.startDisplaying();
+ _downButton.show();
+
+ _utilityCallBack.setNotification(&_utilityNotification);
+ _utilityCallBack.initCallBack(&_utilityTimer, kCallBackAtTime);
+ _utilityNotification.notifyMe(this, kUtilityNotificationFlags, kUtilityNotificationFlags);
+ _utilityTimer.setMasterTimeBase(getOwner()->getNavMovie());
+
+ if (_playingAgainstRobot)
+ _neighborhoodNotification->notifyMe(this, kExtraCompletedFlag | kDelayCompletedFlag |
+ kSpotSoundCompletedFlag, kExtraCompletedFlag | kDelayCompletedFlag | kSpotSoundCompletedFlag);
+ else
+ _neighborhoodNotification->notifyMe(this, kDelayCompletedFlag | kSpotSoundCompletedFlag,
+ kDelayCompletedFlag | kSpotSoundCompletedFlag);
+
+ _gameState = kPlayingSplash;
+}
+
+void PressureDoor::initInteraction() {
+ _levelsMovie.start();
+
+ if (_playingAgainstRobot) {
+ ExtraTable::Entry entry;
+ _owner->getExtraEntry(kN59RobotApproaches, entry);
+ _utilityTimer.setSegment(entry.movieStart, entry.movieEnd);
+ _utilityCallBack.setCallBackFlag(kDoorJumpsUpFlag);
+ _punchInTime = kApproachPunchInTime + entry.movieStart;
+ _utilityCallBack.scheduleCallBack(kTriggerTimeFwd, _punchInTime, kNavTimeScale);
+ _utilityTimer.setTime(entry.movieStart);
+ _owner->startExtraSequence(kN59RobotApproaches, kExtraCompletedFlag, kFilterAllInput);
+ _utilityTimer.start();
+ _robotState = kPlayingRobotApproaching;
+ }
+
+ _levelsMovie.redrawMovieWorld();
+}
+
+void PressureDoor::closeInteraction() {
+ _pressureNotification.cancelNotification(this);
+ _pressureCallBack.releaseCallBack();
+ _utilityNotification.cancelNotification(this);
+ _utilityCallBack.releaseCallBack();
+ _neighborhoodNotification->cancelNotification(this);
+}
+
+void PressureDoor::playAgainstRobot() {
+ _playingAgainstRobot = true;
+}
+
+void PressureDoor::receiveNotification(Notification *notification, const NotificationFlags flags) {
+ Neighborhood *owner = getOwner();
+
+ if (notification == _neighborhoodNotification) {
+ if (_playingAgainstRobot && (flags & kExtraCompletedFlag) != 0) {
+ ExtraTable::Entry entry;
+
+ switch (_robotState) {
+ case kPlayingRobotApproaching:
+ _utilityTimer.stop();
+ if (GameState.getNoradSubRoomPressure() == kMaxPressure) {
+ owner->getExtraEntry(kN59PlayerWins1, entry);
+ _utilityTimer.setSegment(entry.movieStart, entry.movieEnd);
+ _utilityTimer.setTime(entry.movieStart);
+ _utilityCallBack.setCallBackFlag(kDoorJumpsUpFlag);
+ _punchInTime = kLoopPunchInTime + entry.movieStart;
+ _utilityCallBack.scheduleCallBack(kTriggerTimeFwd, _punchInTime, kNavTimeScale);
+ owner->startExtraSequence(kN59PlayerWins1, kExtraCompletedFlag, kFilterNoInput);
+ _utilityTimer.start();
+ _robotState = kRobotDying;
+ } else {
+ owner->getExtraEntry(kN59RobotPunchLoop, entry);
+ _utilityTimer.setSegment(entry.movieStart, entry.movieEnd);
+ _utilityTimer.setTime(entry.movieStart);
+ _utilityCallBack.setCallBackFlag(kDoorJumpsUpFlag);
+ _punchInTime = kLoopPunchInTime + entry.movieStart;
+ _utilityCallBack.scheduleCallBack(kTriggerTimeFwd, _punchInTime, kNavTimeScale);
+ owner->startSpotLoop(entry.movieStart, entry.movieEnd, kExtraCompletedFlag);
+ _utilityTimer.start();
+ _robotState = kRobotPunching;
+ _punchCount = 1;
+ }
+ break;
+ case kRobotPunching:
+ if (GameState.getNoradSubRoomPressure() == kMaxPressure) {
+ owner->startExtraSequence(kN59PlayerWins1, kExtraCompletedFlag, kFilterNoInput);
+ _robotState = kRobotDying;
+ } else if (++_punchCount >= kMaxPunches) {
+ _robotState = kRobotComingThrough;
+ owner->getExtraEntry(kN59RobotWins, entry);
+ _utilityTimer.stop();
+ _utilityTimer.setSegment(entry.movieStart, entry.movieEnd);
+ _utilityTimer.setTime(entry.movieStart);
+ _utilityCallBack.cancelCallBack();
+ _utilityCallBack.setCallBackFlag(kDoorCrushedFlag);
+ _utilityCallBack.scheduleCallBack(kTriggerTimeFwd, kPunchThroughTime + entry.movieStart, kNavTimeScale);
+ owner->startExtraSequence(kN59RobotWins, kExtraCompletedFlag, kFilterNoInput);
+ _utilityTimer.start();
+ } else {
+ _utilityCallBack.setCallBackFlag(kDoorJumpsUpFlag);
+ _utilityCallBack.scheduleCallBack(kTriggerTimeFwd, _punchInTime, kNavTimeScale);
+ owner->scheduleNavCallBack(kExtraCompletedFlag);
+ }
+ break;
+ case kRobotComingThrough:
+ g_system->delayMillis(2 * 1000);
+ ((PegasusEngine *)g_engine)->die(kDeathRobotThroughNoradDoor);
+ break;
+ case kRobotDying:
+ _robotState = kRobotDead;
+ _levelsMovie.stop();
+ _levelsMovie.setSegment((kNormalSubRoomPressure + kPressureBase) * _levelsScale,
+ (GameState.getNoradSubRoomPressure() + kPressureBase) * _levelsScale);
+ _pressureCallBack.setCallBackFlag(kPressureDroppingFlag);
+ _pressureCallBack.scheduleCallBack(kTriggerAtStart, 0, 0);
+ _typeMovie.stop();
+ _typeMovie.setSegment(0, _typeMovie.getDuration());
+ _typeMovie.setTime(kDecreasingPressureTime * _typeScale);
+ _typeMovie.redrawMovieWorld();
+ _typeMovie.show();
+ _downButton.show();
+ _downButton.setCurrentFrameIndex(1);
+ _gameState = kGameOver;
+ allowInput(false);
+ _levelsMovie.setRate(Common::Rational(0x5555, 0x10000) - 1); // Should match door tracker.
+ break;
+ case kRobotDead:
+ allowInput(true);
+ ((NoradDelta *)owner)->playerBeatRobotWithDoor();
+ owner->requestDeleteCurrentInteraction();
+ break;
+ }
+ }
+
+ if ((flags & (kDelayCompletedFlag | kSpotSoundCompletedFlag)) != 0) {
+ switch (_gameState) {
+ case kPlayingPressureMessage:
+ _typeMovie.setTime(kEqualizeTime * _typeScale);
+ _typeMovie.redrawMovieWorld();
+ owner->requestDelay(1, 5, kFilterNoInput, 0);
+ owner->requestSpotSound(_equalizeSoundIn, _equalizeSoundOut, kFilterNoInput, 0);
+ owner->requestDelay(1, 5, kFilterNoInput, kDelayCompletedFlag);
+ _gameState = kPlayingEqualizeMessage;
+ break;
+ case kPlayingEqualizeMessage:
+ _gameState = kWaitingForPlayer;
+ stopChangingPressure();
+ break;
+ case kPlayingDoneMessage:
+ _gameState = kWaitingForPlayer;
+ _typeMovie.stop();
+ _typeMovie.setFlags(0);
+ _typeMovie.hide();
+ if (!_playingAgainstRobot)
+ ((Norad *)_owner)->doneWithPressureDoor();
+ break;
+ }
+ }
+ } else if (notification == &_pressureNotification) {
+ switch (flags) {
+ case kSplashFinished:
+ _levelsMovie.stop();
+ _levelsMovie.setSegment(0, _levelsMovie.getDuration());
+ _levelsMovie.setTime((GameState.getNoradSubRoomPressure() + kPressureBase) * _levelsScale);
+ _levelsMovie.redrawMovieWorld();
+
+ if (GameState.getNoradSubRoomPressure() != kNormalSubRoomPressure) {
+ _typeMovie.show();
+ owner->requestDelay(1, 5, kFilterNoInput, 0);
+ owner->requestSpotSound(_pressureSoundIn, _pressureSoundOut, kFilterNoInput, 0);
+ owner->requestDelay(1, 5, kFilterNoInput, kDelayCompletedFlag);
+ _gameState = kPlayingPressureMessage;
+ } else {
+ _gameState = kWaitingForPlayer;
+ }
+ break;
+ case kPressureDroppingFlag:
+ _levelsMovie.stop();
+ _levelsMovie.hide();
+ _typeMovie.stop();
+ _typeMovie.hide();
+ _upButton.hide();
+ _downButton.hide();
+ owner->startExtraSequence(kN59PlayerWins2, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ }
+ } else if (notification == &_utilityNotification) {
+ switch (flags) {
+ case kDoorJumpsUpFlag:
+ _utilityCallBack.setCallBackFlag(kDoorJumpsBackFlag);
+ _utilityCallBack.scheduleCallBack(kTriggerTimeFwd, _punchInTime + kNavTimePerFrame, kNavTimeScale);
+ _levelsMovie.hide();
+ _typePunched = _typeMovie.isVisible();
+ if (_typePunched == true)
+ _typeMovie.hide();
+ _upButton.hide();
+ _downButton.hide();
+ break;
+ case kDoorJumpsBackFlag:
+ _levelsMovie.show();
+ _upButton.show();
+ _downButton.show();
+ if (_typePunched)
+ _typeMovie.show();
+ break;
+ case kDoorCrushedFlag:
+ _levelsMovie.hide();
+ _typeMovie.hide();
+ _upButton.hide();
+ _downButton.hide();
+ break;
+ }
+ }
+}
+
+void PressureDoor::activateHotspots() {
+ GameInteraction::activateHotspots();
+
+ switch (_gameState) {
+ case kWaitingForPlayer:
+ g_allHotspots.activateOneHotspot(_upHotspotID);
+ g_allHotspots.activateOneHotspot(_downHotspotID);
+ if (!_playingAgainstRobot)
+ g_allHotspots.activateOneHotspot(_outHotspotID);
+ break;
+ default:
+ break;
+ }
+}
+
+void PressureDoor::clickInHotspot(const Input &input, const Hotspot *spot) {
+ HotSpotID id = spot->getObjectID();
+
+ if (id == _upHotspotID || id == _downHotspotID) {
+ if (id == _upHotspotID)
+ _doorTracker.setTrackParameters(spot, &_upButton);
+ else
+ _doorTracker.setTrackParameters(spot, &_downButton);
+
+ _doorTracker.startTracking(input);
+ } else {
+ GameInteraction::clickInHotspot(input, spot);
+ }
+}
+
+void PressureDoor::incrementPressure(const HotSpotID id) {
+ _typeMovie.stop();
+ _typeMovie.setSegment(0, _typeMovie.getDuration());
+ _typeMovie.setFlags(0);
+
+ if (id == _upHotspotID) {
+ if (GameState.getNoradSubRoomPressure() < kMaxPressure) {
+ GameState.setNoradSubRoomPressure(GameState.getNoradSubRoomPressure() + 1);
+ _levelsMovie.setTime((GameState.getNoradSubRoomPressure() + kPressureBase) * _levelsScale);
+ _levelsMovie.redrawMovieWorld();
+ _typeMovie.setTime(kIncreasingPressureTime * _typeScale);
+ _typeMovie.redrawMovieWorld();
+ _typeMovie.show();
+ g_AIArea->checkMiddleArea();
+ } else {
+ _typeMovie.hide();
+ }
+ } else if (id == _downHotspotID) {
+ if (GameState.getNoradSubRoomPressure() > kMinPressure) {
+ GameState.setNoradSubRoomPressure(GameState.getNoradSubRoomPressure() - 1);
+ _levelsMovie.setTime((GameState.getNoradSubRoomPressure() + kPressureBase) * _levelsScale);
+ _levelsMovie.redrawMovieWorld();
+ _typeMovie.setTime(kDecreasingPressureTime * _typeScale);
+ _typeMovie.redrawMovieWorld();
+ _typeMovie.show();
+ g_AIArea->checkMiddleArea();
+ } else {
+ _typeMovie.hide();
+ }
+ }
+}
+
+void PressureDoor::stopChangingPressure() {
+ Neighborhood *owner;
+
+ switch (GameState.getNoradSubRoomPressure()) {
+ case 11:
+ _typeMovie.setSegment(kMaxPressureLoopStart * _typeScale, kMaxPressureLoopStop * _typeScale);
+ _typeMovie.setFlags(kLoopTimeBase);
+ _typeMovie.show();
+ _typeMovie.start();
+ break;
+ case 10:
+ _typeMovie.setSegment(kCautionLoopStart * _typeScale, kCautionLoopStop * _typeScale);
+ _typeMovie.setFlags(kLoopTimeBase);
+ _typeMovie.show();
+ _typeMovie.start();
+ break;
+ case kNormalSubRoomPressure:
+ owner = getOwner();
+ _typeMovie.setSegment(kOpeningDoorLoopStart * _typeScale, kOpeningDoorLoopStop * _typeScale);
+ _typeMovie.setFlags(kLoopTimeBase);
+ _typeMovie.show();
+ _gameState = kPlayingDoneMessage;
+ owner->requestDelay(2, 1, kFilterNoInput, kDelayCompletedFlag);
+ _typeMovie.start();
+ break;
+ default:
+ _typeMovie.hide();
+ break;
+ }
+}
+
+bool PressureDoor::canSolve() {
+ if (_playingAgainstRobot)
+ return GameState.getNoradSubRoomPressure() < 11;
+
+ return GameState.getNoradSubRoomPressure() != kNormalSubRoomPressure;
+}
+
+void PressureDoor::doSolve() {
+ if (_playingAgainstRobot) {
+ GameState.setNoradSubRoomPressure(11);
+ _levelsMovie.setTime((11 + kPressureBase) * _levelsScale);
+ _levelsMovie.redrawMovieWorld();
+ _typeMovie.setSegment(kMaxPressureLoopStart * _typeScale, kMaxPressureLoopStop * _typeScale);
+ _typeMovie.setFlags(kLoopTimeBase);
+ _typeMovie.show();
+ _typeMovie.start();
+ g_AIArea->checkMiddleArea();
+ } else {
+ GameState.setNoradSubRoomPressure(kNormalSubRoomPressure);
+ _levelsMovie.setTime((kNormalSubRoomPressure + kPressureBase) * _levelsScale);
+ _levelsMovie.redrawMovieWorld();
+ _typeMovie.setSegment(kOpeningDoorLoopStart * _typeScale, kOpeningDoorLoopStop * _typeScale);
+ _typeMovie.setFlags(kLoopTimeBase);
+ _typeMovie.show();
+ Neighborhood *owner = getOwner();
+ owner->requestDelay(2, 1, kFilterNoInput, kDelayCompletedFlag);
+ _gameState = kPlayingDoneMessage;
+ _typeMovie.start();
+ g_AIArea->checkMiddleArea();
+ }
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/norad/pressuredoor.h b/engines/pegasus/neighborhood/norad/pressuredoor.h
new file mode 100644
index 0000000000..b2018bfcf7
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/pressuredoor.h
@@ -0,0 +1,93 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_NORAD_PRESSUREDOOR_H
+#define PEGASUS_NEIGHBORHOOD_NORAD_PRESSUREDOOR_H
+
+#include "pegasus/interaction.h"
+#include "pegasus/movie.h"
+#include "pegasus/notification.h"
+#include "pegasus/neighborhood/norad/pressuretracker.h"
+
+namespace Pegasus {
+
+static const short kNormalSubRoomPressure = 2;
+
+class PressureDoor : public GameInteraction, public NotificationReceiver {
+public:
+ PressureDoor(Neighborhood *, bool isUpperDoor, const HotSpotID, const HotSpotID,
+ const HotSpotID, TimeValue pressureSoundIn, TimeValue pressureSoundOut,
+ TimeValue equalizeSoundIn, TimeValue equalizeSoundOut);
+ virtual ~PressureDoor() {}
+
+ void incrementPressure(const HotSpotID);
+ void stopChangingPressure();
+
+ void playAgainstRobot();
+
+ bool canSolve();
+ void doSolve();
+
+protected:
+ virtual void openInteraction();
+ virtual void initInteraction();
+ virtual void closeInteraction();
+
+ virtual void activateHotspots();
+ virtual void clickInHotspot(const Input &, const Hotspot *);
+
+ virtual void receiveNotification(Notification *, const NotificationFlags);
+
+ Movie _levelsMovie;
+ TimeScale _levelsScale;
+ Movie _typeMovie;
+ TimeScale _typeScale;
+ Sprite _upButton;
+ Sprite _downButton;
+ Notification _pressureNotification;
+ NotificationCallBack _pressureCallBack;
+ Notification *_neighborhoodNotification;
+ int _gameState;
+ HotSpotID _upHotspotID;
+ HotSpotID _downHotspotID;
+ HotSpotID _outHotspotID;
+ PressureTracker _doorTracker;
+ TimeValue _pressureSoundIn;
+ TimeValue _pressureSoundOut;
+ TimeValue _equalizeSoundIn;
+ TimeValue _equalizeSoundOut;
+ bool _isUpperDoor;
+
+ bool _playingAgainstRobot, _typePunched;
+ int _robotState, _punchCount;
+ TimeBase _utilityTimer;
+ Notification _utilityNotification;
+ NotificationCallBack _utilityCallBack;
+ TimeValue _punchInTime;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/norad/pressuretracker.cpp b/engines/pegasus/neighborhood/norad/pressuretracker.cpp
new file mode 100644
index 0000000000..5aac19dcbe
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/pressuretracker.cpp
@@ -0,0 +1,87 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/hotspot.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/neighborhood/norad/pressuredoor.h"
+#include "pegasus/neighborhood/norad/pressuretracker.h"
+
+namespace Pegasus {
+
+PressureTracker::PressureTracker(PressureDoor *pressureDoor) {
+ _pressureDoor = pressureDoor;
+ _trackSpot = 0;
+ _trackTime = 0;
+}
+
+void PressureTracker::setTrackParameters(const Hotspot *trackSpot, Sprite *trackButton) {
+ _trackSpot = trackSpot;
+ _trackButton = trackButton;
+ _trackTime = 0;
+}
+
+void PressureTracker::activateHotspots() {
+ Tracker::activateHotspots();
+
+ if (_trackSpot)
+ g_allHotspots.activateOneHotspot(_trackSpot->getObjectID());
+}
+
+// For click-hold dragging.
+bool PressureTracker::stopTrackingInput(const Input &input) {
+ return !JMPPPInput::isPressingInput(input);
+}
+
+void PressureTracker::continueTracking(const Input &input) {
+ Common::Point where;
+ input.getInputLocation(where);
+
+ if (g_allHotspots.findHotspot(where) == _trackSpot) {
+ trackPressure();
+ _trackButton->setCurrentFrameIndex(1);
+ } else {
+ _trackButton->setCurrentFrameIndex(0);
+ }
+}
+
+void PressureTracker::startTracking(const Input &input) {
+ Tracker::startTracking(input);
+ trackPressure();
+}
+
+void PressureTracker::stopTracking(const Input &input) {
+ _trackButton->setCurrentFrameIndex(0);
+ _pressureDoor->stopChangingPressure();
+ Tracker::stopTracking(input);
+}
+
+void PressureTracker::trackPressure() {
+ if (g_system->getMillis() - _trackTime > kPressureDoorTrackInterval * 1000 / 60) {
+ _pressureDoor->incrementPressure(_trackSpot->getObjectID());
+ _trackTime = g_system->getMillis();
+ }
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/norad/pressuretracker.h b/engines/pegasus/neighborhood/norad/pressuretracker.h
new file mode 100644
index 0000000000..6ca7252e22
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/pressuretracker.h
@@ -0,0 +1,69 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_NORAD_PRESSURETRACKER_H
+#define PEGASUS_NEIGHBORHOOD_NORAD_PRESSURETRACKER_H
+
+#include "pegasus/input.h"
+
+namespace Pegasus {
+
+// This class assumes that the globe movie is built at 15 frames per second with a
+// time scale of 600, yielding 40 time unit per frame.
+
+enum PressureTrackDirection {
+ kTrackPressureUp,
+ kTrackPressureDown
+};
+
+static const int kPressureDoorTrackInterval = 45;
+
+class PressureDoor;
+class Sprite;
+
+class PressureTracker : public Tracker {
+public:
+ PressureTracker(PressureDoor *);
+ virtual ~PressureTracker() {}
+
+ void setTrackParameters(const Hotspot *, Sprite *);
+ void continueTracking(const Input &);
+ void startTracking(const Input &);
+ void stopTracking(const Input &);
+ void activateHotspots();
+ bool stopTrackingInput(const Input &);
+
+protected:
+ void trackPressure();
+
+ PressureDoor *_pressureDoor;
+ const Hotspot *_trackSpot;
+ Sprite *_trackButton;
+ long _trackTime;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/norad/subcontrolroom.cpp b/engines/pegasus/neighborhood/norad/subcontrolroom.cpp
new file mode 100644
index 0000000000..d48481e925
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/subcontrolroom.cpp
@@ -0,0 +1,1178 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/gamestate.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/neighborhood/norad/constants.h"
+#include "pegasus/neighborhood/norad/norad.h"
+#include "pegasus/neighborhood/norad/subcontrolroom.h"
+#include "pegasus/neighborhood/norad/delta/noraddelta.h"
+
+namespace Pegasus {
+
+// Right Monitor times
+
+static const TimeValue kAlphaClawSplashStart = 0;
+static const TimeValue kAlphaClawSplashStop = 4000;
+
+static const TimeValue kDeltaClawSplashStart = 4000;
+static const TimeValue kDeltaClawSplashStop = 8000;
+
+static const TimeValue kClawAtATime = 8000;
+static const TimeValue kClawAtAPinchedTime = 8600;
+static const TimeValue kClawAtATurnedTime = 9200;
+static const TimeValue kClawAtAWithRobotPinchedTime = 9800;
+
+static const TimeValue kClawAtBTime = 10400;
+static const TimeValue kClawAtBPinchedTime = 11000;
+static const TimeValue kClawAtBTurnedTime = 11600;
+static const TimeValue kClawAtBWithRobotTime = 12200;
+static const TimeValue kClawAtBWithRobotPinchedTime = 12800;
+
+static const TimeValue kClawAtCTime = 13400;
+static const TimeValue kClawAtCPinchedTime = 14000;
+static const TimeValue kClawAtCTurnedTime = 14600;
+
+static const TimeValue kClawAtDTime = 15200;
+static const TimeValue kClawAtDPinchedTime = 15800;
+static const TimeValue kClawAtDTurnedTime = 16400;
+
+static const TimeValue kAToBStart = 17000;
+static const TimeValue kAToBStop = 18680;
+static const TimeValue kAPinchStart = 18680;
+static const TimeValue kAPinchStop = 20200;
+static const TimeValue kACCWStart = 20200;
+static const TimeValue kACCWStop = 21600;
+static const TimeValue kACWStart = 21600;
+static const TimeValue kACWStop = 23000;
+
+static const TimeValue kBToAStart = 23000;
+static const TimeValue kBToAStop = 24680;
+static const TimeValue kBToCStart = 24680;
+static const TimeValue kBToCStop = 26520;
+static const TimeValue kBToDStart = 26520;
+static const TimeValue kBToDStop = 28320;
+static const TimeValue kBPinchStart = 28320;
+static const TimeValue kBPinchStop = 29680;
+static const TimeValue kBCCWStart = 29680;
+static const TimeValue kBCCWStop = 31200;
+static const TimeValue kBCWStart = 31200;
+static const TimeValue kBCWStop = 32720;
+
+static const TimeValue kCToBStart = 32720;
+static const TimeValue kCToBStop = 34560;
+static const TimeValue kCPinchStart = 34560;
+static const TimeValue kCPinchStop = 36400;
+static const TimeValue kCCCWStart = 36400;
+static const TimeValue kCCCWStop = 37840;
+static const TimeValue kCCWStart = 37840;
+static const TimeValue kCCWStop = 39280;
+
+static const TimeValue kDToBStart = 39280;
+static const TimeValue kDToBStop = 41080;
+static const TimeValue kDPinchStart = 41080;
+static const TimeValue kDPinchStop = 42600;
+static const TimeValue kDCCWStart = 42600;
+static const TimeValue kDCCWStop = 44000;
+static const TimeValue kDCWStart = 44000;
+static const TimeValue kDCWStop = 45400;
+
+static const TimeValue kRobotApproachStart = 45400;
+static const TimeValue kRobotApproachStop = 56800;
+
+static const TimeValue kCToBWithRobotStart = 56800;
+static const TimeValue kCToBWithRobotStop = 58600;
+
+static const TimeValue kBPinchWithRobotStart = 58600;
+static const TimeValue kBPinchWithRobotStop = 60400;
+static const TimeValue kBToAWithRobotStart = 60400;
+static const TimeValue kBToAWithRobotStop = 62240;
+
+// As usual, times here are in seconds.
+
+// Left monitor times.
+
+static const TimeValue kAlphaSplashStart = 0;
+static const TimeValue kAlphaSplashStop = 2;
+
+static const TimeValue kMainMenuTime = 2;
+static const TimeValue kLaunchPrepRolloverTime = 3;
+static const TimeValue kLaunchPrepHighlightStart = 4;
+static const TimeValue kLaunchPrepHighlightStop = 5;
+static const TimeValue kClawControlRolloverTime = 5;
+static const TimeValue kClawControlHighlightStart = 6;
+static const TimeValue kClawControlHighlightStop = 7;
+
+static const TimeValue kAlphaLaunchPrepStart = 7;
+static const TimeValue kAlphaLaunchPrepStop = 17;
+
+static const TimeValue kClawMenuStart = 17;
+static const TimeValue kClawMenuStop = 18;
+
+static const TimeValue kClawMenuTime = 18;
+
+static const TimeValue kDeltaSplashStart = 19;
+static const TimeValue kDeltaSplashStop = 21;
+
+static const TimeValue kDeltaLaunchPrepStart = 21;
+static const TimeValue kDeltaLaunchPrepStop = 30;
+
+// Right monitor times.
+
+static const NotificationFlags kAlphaSplashFinished = 1;
+static const NotificationFlags kAlphaPrepFinished = kAlphaSplashFinished << 1;
+static const NotificationFlags kPrepHighlightFinished = kAlphaPrepFinished << 1;
+static const NotificationFlags kClawHighlightFinished = kPrepHighlightFinished << 1;
+static const NotificationFlags kClawMenuFinished = kClawHighlightFinished << 1;
+static const NotificationFlags kDeltaSplashFinished = kClawMenuFinished << 1;
+static const NotificationFlags kDeltaPrepFinished = kDeltaSplashFinished << 1;
+
+static const NotificationFlags kSubControlNotificationFlags = kAlphaSplashFinished |
+ kAlphaPrepFinished |
+ kPrepHighlightFinished |
+ kClawHighlightFinished |
+ kClawMenuFinished |
+ kDeltaSplashFinished |
+ kDeltaPrepFinished;
+
+static const NotificationFlags kOneSecondOfMoveFinished = 1;
+
+static const NotificationFlags kGreenBallNotificationFlags = kOneSecondOfMoveFinished;
+
+enum {
+ kButtonDimFrame,
+ kButtonActiveFrame,
+ kButtonHighlightedFrame
+};
+
+enum {
+ kAlphaSplash,
+ kAlphaMainMenu,
+ kDeltaSplash,
+ kDeltaMainMenu,
+ kClawMenu,
+ kPlayingHighlight,
+ kPuttingClawAway
+};
+
+// The owning neighborhood must provide an array of longs which hold the various
+// extra IDs for moving the claw around. In addition, the owner must tell the sub
+// control room interaction what position the claw starts out in (which is also the
+// position the claw must be in before leaving).
+
+// Standard array indices:
+enum {
+ kClawFromAToBIndex,
+ kClawALoopIndex,
+ kClawAPinchIndex,
+ kClawACounterclockwiseIndex,
+ kClawAClockwiseIndex,
+ kClawFromBToAIndex,
+ kClawFromBToCIndex,
+ kClawFromBToDIndex,
+ kClawBLoopIndex,
+ kClawBPinchIndex,
+ kClawBCounterclockwiseIndex,
+ kClawBClockwiseIndex,
+ kClawFromCToBIndex,
+ kClawCLoopIndex,
+ kClawCPinchIndex,
+ kClawCCounterclockwiseIndex,
+ kClawCClockwiseIndex,
+ kClawFromDToBIndex,
+ kClawDLoopIndex,
+ kClawDPinchIndex,
+ kClawDCounterclockwiseIndex,
+ kClawDClockwiseIndex
+};
+
+// Action indices for s_clawStateTable:
+// Can also be used as indices into _buttons (except for kNoActionIndex and kLoopActionIndex).
+enum {
+ kNoActionIndex = -1,
+ kPinchActionIndex = 0,
+ kMoveDownActionIndex,
+ kMoveRightActionIndex,
+ kMoveLeftActionIndex,
+ kMoveUpActionIndex,
+ kCCWActionIndex,
+ kCWActionIndex,
+ kLoopActionIndex
+};
+
+/*
+ _currentAction and _nextAction:
+
+ At any time, _currentAction contains an action index (defined above). The current
+ action index is what the claw is doing right now. If the player presses a button
+ before the current action completes, _nextAction saves the new action and input
+ is disabled. This has the effect of implementing a queue of commands for the claw
+ that can save at most one extra command.
+
+ The general strategy for using _currentAction and _nextAction are:
+ -- If the player presses a claw button and _currentAction is kNoActionIndex,
+ do the command immediately and set _currentAction accordingly.
+ -- If the player presses a claw button and _currentAction is not kNoActionIndex,
+ save the appropriate action index in _nextAction.
+ -- When a command animation completes, set _nextAction to kNoActionIndex, then
+ check if _nextAction has a command waiting in it. If so, play the appriate
+ animation, copy _nextAction into _currentAction and set _nextAction to
+ kNoActionIndex.
+ -- If the player tries to get up, disable input (including all claw buttons) until
+ the player rises. Then, if the claw is in its original position, play the
+ animation of the player rising.
+ -- If the claw needs to be put back, play the first move required to put the
+ claw back by setting _currentAction and playing the appropriate animation.
+ Leave _nextAction alone. When the animation, completes, check to see if the
+ claw is in its original position or not. If so, complete the player rising
+ sequence by playing the rising animation. If not, repeat this whole step.
+
+ Using this general strategy allows the use of a single function,
+ DispatchClawAction, which can both cause the claw to perform a command and saving
+ the next command in _nextAction.
+*/
+
+// Array indexed by [claw position] [action]
+// array yields an index into the neighborhood's extra id table for claw animation or -1.
+static const int s_clawStateTable[4][8] = {
+ {
+ kClawAPinchIndex,
+ kNoActionIndex,
+ kNoActionIndex,
+ kClawFromAToBIndex,
+ kNoActionIndex,
+ kClawACounterclockwiseIndex,
+ kClawAClockwiseIndex,
+ kClawALoopIndex
+ },
+ {
+ kClawBPinchIndex,
+ kNoActionIndex,
+ kClawFromBToAIndex,
+ kClawFromBToDIndex,
+ kClawFromBToCIndex,
+ kClawBCounterclockwiseIndex,
+ kClawBClockwiseIndex,
+ kClawBLoopIndex
+ },
+ {
+ kClawCPinchIndex,
+ kClawFromCToBIndex,
+ kNoActionIndex,
+ kNoActionIndex,
+ kNoActionIndex,
+ kClawCCounterclockwiseIndex,
+ kClawCClockwiseIndex,
+ kClawCLoopIndex
+ },
+ {
+ kClawDPinchIndex,
+ kNoActionIndex,
+ kClawFromDToBIndex,
+ kNoActionIndex,
+ kNoActionIndex,
+ kClawDCounterclockwiseIndex,
+ kClawDClockwiseIndex,
+ kClawDLoopIndex
+ }
+};
+
+// Move directions for s_clawMovieTable:
+enum {
+ kMoveClawDown,
+ kMoveClawRight,
+ kMoveClawLeft,
+ kMoveClawUp
+};
+
+static const int kClawNowhere = -1;
+
+// Array indexed by [claw position] [move direction]
+// array yields new claw position or -1.
+static const int s_clawMovieTable[4][4] = {
+ {
+ kClawNowhere,
+ kClawNowhere,
+ kClawAtB,
+ kClawNowhere
+ },
+ {
+ kClawNowhere,
+ kClawAtA,
+ kClawAtD,
+ kClawAtC
+ },
+ {
+ kClawAtB,
+ kClawNowhere,
+ kClawNowhere,
+ kClawNowhere
+ },
+ {
+ kClawNowhere,
+ kClawAtB,
+ kClawNowhere,
+ kClawNowhere
+ }
+};
+
+// Indexed by claw action index, claw position, plus 0 for start, 1 for stop.
+// (Never indexed with kLoopActionIndex.)
+static const TimeValue s_clawMonitorTable[7][4][2] = {
+ {
+ { kAPinchStart, kAPinchStop },
+ { kBPinchStart, kBPinchStop },
+ { kCPinchStart, kCPinchStop },
+ { kDPinchStart, kDPinchStop }
+ },
+ {
+ { 0xffffffff, 0xffffffff },
+ { 0xffffffff, 0xffffffff },
+ { kCToBStart, kCToBStop },
+ { 0xffffffff, 0xffffffff }
+ },
+ {
+ { 0xffffffff, 0xffffffff },
+ { kBToAStart, kBToAStop },
+ { 0xffffffff, 0xffffffff },
+ { kDToBStart, kDToBStop }
+ },
+ {
+ { kAToBStart, kAToBStop },
+ { kBToDStart, kBToDStop },
+ { 0xffffffff, 0xffffffff },
+ { 0xffffffff, 0xffffffff }
+ },
+ {
+ { 0xffffffff, 0xffffffff },
+ { kBToCStart, kBToCStop },
+ { 0xffffffff, 0xffffffff },
+ { 0xffffffff, 0xffffffff }
+ },
+ {
+ { kACCWStart, kACCWStop },
+ { kBCCWStart, kBCCWStop },
+ { kCCCWStart, kCCCWStop },
+ { kDCCWStart, kDCCWStop }
+ },
+ {
+ { kACWStart, kACWStop },
+ { kBCWStart, kBCWStop },
+ { kCCWStart, kCCWStop },
+ { kDCWStart, kDCWStop }
+ }
+};
+
+// Frame indices for the green ball sprite.
+enum {
+ kGreenBallAtA,
+ kGreenBallAtAWithClaw,
+ kGreenBallAtAWithClawAndRobot,
+ kGreenBallAtB,
+ kGreenBallAtBWithClaw,
+ kGreenBallAtBWithClawAndRobot,
+ kGreenBallAtCArmAtA,
+ kGreenBallAtCArmAtB,
+ kGreenBallAtCArmAtD,
+ kGreenBallAtCWithClaw,
+ kGreenBallAtD,
+ kGreenBallAtDWithClaw,
+ kNumClawGreenBalls
+};
+
+// State constants for _robotState.
+enum {
+ kNoRobot,
+ kRobotApproaching,
+ kPunchingOnce,
+ kPunchingTwice,
+ kPunchingThrice,
+ kCarriedToDoor,
+ kPlayerWon,
+ kRobotWon
+};
+
+// Sub Control Room button PICTs:
+static const ResIDType kSubControlButtonBaseID = 500;
+static const ResIDType kClawMonitorGreenBallBaseID = 600;
+
+// Constructor
+SubControlRoom::SubControlRoom(Neighborhood *handler) : GameInteraction(kNoradSubControlRoomInteractionID, handler),
+ _subControlMovie(kSubControlMonitorID), _subControlNotification(kSubControlNotificationID, (PegasusEngine *)g_engine),
+ _clawMonitorMovie(kClawMonitorID), _pinchButton(kSubControlPinchID), _downButton(kSubControlDownID),
+ _rightButton(kSubControlRightID), _leftButton(kSubControlLeftID), _upButton(kSubControlUpID),
+ _ccwButton(kSubControlCCWID), _cwButton(kSubControlCWID), _greenBall(kClawMonitorGreenBallID),
+ _greenBallNotification(kNoradGreenBallNotificationID, (PegasusEngine *)g_engine) {
+ _neighborhoodNotification = handler->getNeighborhoodNotification();
+ _playingAgainstRobot = false;
+ _robotState = kNoRobot;
+}
+
+void SubControlRoom::playAgainstRobot() {
+ _playingAgainstRobot = true;
+}
+
+void SubControlRoom::openInteraction() {
+ _currentAction = kNoActionIndex;
+ _nextAction = kNoActionIndex;
+
+ Norad *owner = (Norad *)getOwner();
+ owner->getClawInfo(_outSpotID, _prepSpotID, _clawControlSpotID, _clawButtonSpotIDs[0],
+ _clawButtonSpotIDs[1], _clawButtonSpotIDs[2], _clawButtonSpotIDs[3],
+ _clawButtonSpotIDs[4], _clawButtonSpotIDs[5], _clawButtonSpotIDs[6],
+ _clawStartPosition, _clawExtraIDs);
+
+ _clawPosition = _clawStartPosition;
+ _clawNextPosition = _clawPosition;
+ _subControlMovie.initFromMovieFile("Images/Norad Alpha/N22 Left Monitor Movie");
+ _subControlMovie.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
+ _subControlMovie.moveElementTo(kNoradSubControlLeft, kNoradSubControlTop);
+ _subControlScale = _subControlMovie.getScale();
+ _subControlMovie.setDisplayOrder(kSubControlOrder);
+ _subControlMovie.startDisplaying();
+ _subControlCallBack.setNotification(&_subControlNotification);
+ _subControlCallBack.initCallBack(&_subControlMovie, kCallBackAtExtremes);
+
+ _clawMonitorMovie.initFromMovieFile("Images/Norad Alpha/N22:N60 Right Monitor");
+ _clawMonitorMovie.moveElementTo(kNoradClawMonitorLeft, kNoradClawMonitorTop);
+ _clawMonitorMovie.setDisplayOrder(kClawMonitorOrder);
+ _clawMonitorMovie.startDisplaying();
+ _clawMonitorCallBack.setNotification(&_subControlNotification);
+ _clawMonitorCallBack.initCallBack(&_clawMonitorMovie, kCallBackAtExtremes);
+
+ _subControlNotification.notifyMe(this, kSubControlNotificationFlags, kSubControlNotificationFlags);
+
+ _neighborhoodNotification->notifyMe(this, kExtraCompletedFlag, kExtraCompletedFlag);
+
+ _buttons[0] = &_pinchButton;
+ _buttons[1] = &_downButton;
+ _buttons[2] = &_rightButton;
+ _buttons[3] = &_leftButton;
+ _buttons[4] = &_upButton;
+ _buttons[5] = &_ccwButton;
+ _buttons[6] = &_cwButton;
+
+ _pinchButton.setDisplayOrder(kSubControlPinchOrder);
+ _downButton.setDisplayOrder(kSubControlDownOrder);
+ _rightButton.setDisplayOrder(kSubControlRightOrder);
+ _leftButton.setDisplayOrder(kSubControlLeftOrder);
+ _upButton.setDisplayOrder(kSubControlUpOrder);
+ _ccwButton.setDisplayOrder(kSubControlCCWOrder);
+ _cwButton.setDisplayOrder(kSubControlCWOrder);
+
+ for (int i = 0; i < kNumClawButtons; i++) {
+ SpriteFrame *frame = new SpriteFrame();
+ frame->initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kSubControlButtonBaseID + i * 3, true);
+ _buttons[i]->addFrame(frame, 0, 0);
+
+ frame = new SpriteFrame();
+ frame->initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kSubControlButtonBaseID + i * 3 + 1, true);
+ _buttons[i]->addFrame(frame, 0, 0);
+
+ frame = new SpriteFrame();
+ frame->initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kSubControlButtonBaseID + i * 3 + 2, true);
+ _buttons[i]->addFrame(frame, 0, 0);
+
+ _buttons[i]->setCurrentFrameIndex(0);
+ _buttons[i]->startDisplaying();
+ }
+
+ _pinchButton.moveElementTo(kNoradSubControlPinchLeft, kNoradSubControlPinchTop);
+ _downButton.moveElementTo(kNoradSubControlDownLeft, kNoradSubControlDownTop);
+ _rightButton.moveElementTo(kNoradSubControlRightLeft, kNoradSubControlRightTop);
+ _leftButton.moveElementTo(kNoradSubControlLeftLeft, kNoradSubControlLeftTop);
+ _upButton.moveElementTo(kNoradSubControlUpLeft, kNoradSubControlUpTop);
+ _ccwButton.moveElementTo(kNoradSubControlCCWLeft, kNoradSubControlCCWTop);
+ _cwButton.moveElementTo(kNoradSubControlCWLeft, kNoradSubControlCWTop);
+
+ _greenBall.setDisplayOrder(kClawMonitorGreenBallOrder);
+
+ for (int i = 0; i < kNumClawGreenBalls; i++) {
+ SpriteFrame *frame = new SpriteFrame();
+ frame->initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kClawMonitorGreenBallBaseID + i);
+ _greenBall.addFrame(frame, 0, 0);
+ }
+
+ _greenBall.setCurrentFrameIndex(0);
+ _greenBall.startDisplaying();
+
+ _greenBallTimer.setScale(owner->getNavMovie()->getScale());
+ _greenBallCallBack.setNotification(&_greenBallNotification);
+ _greenBallCallBack.initCallBack(&_greenBallTimer, kCallBackAtExtremes);
+ _greenBallCallBack.setCallBackFlag(kOneSecondOfMoveFinished);
+ _greenBallNotification.notifyMe(this, kGreenBallNotificationFlags, kGreenBallNotificationFlags);
+
+ _subControlMovie.show();
+ _clawMonitorMovie.show();
+}
+
+void SubControlRoom::initInteraction() {
+ if (GameState.getNoradSubPrepState() == kSubDamaged) {
+ playControlMonitorSection(kDeltaSplashStart * _subControlScale, kDeltaSplashStop * _subControlScale,
+ 0, kDeltaSplash, false);
+ playClawMonitorSection(kDeltaClawSplashStart, kDeltaClawSplashStop, kDeltaSplashFinished, _gameState, false);
+ } else {
+ playControlMonitorSection(kAlphaSplashStart * _subControlScale, kAlphaSplashStop * _subControlScale,
+ 0, kAlphaSplash, false);
+ playClawMonitorSection(kAlphaClawSplashStart, kAlphaClawSplashStop, kAlphaSplashFinished, _gameState, false);
+ }
+
+ _subControlMovie.redrawMovieWorld();
+ _clawMonitorMovie.redrawMovieWorld();
+}
+
+void SubControlRoom::closeInteraction() {
+ _subControlNotification.cancelNotification(this);
+ _subControlCallBack.releaseCallBack();
+ _greenBallNotification.cancelNotification(this);
+ _greenBallCallBack.releaseCallBack();
+ _neighborhoodNotification->cancelNotification(this);
+}
+
+void SubControlRoom::setSoundFXLevel(const uint16 fxLevel) {
+ _subControlMovie.setVolume(fxLevel);
+}
+
+void SubControlRoom::receiveNotification(Notification *notification, const NotificationFlags flags) {
+ Norad *owner = (Norad *)getOwner();
+
+ if (notification == &_subControlNotification) {
+ switch (flags) {
+ case kAlphaSplashFinished:
+ setControlMonitorToTime(kMainMenuTime * _subControlScale, kAlphaMainMenu, true);
+ break;
+ case kPrepHighlightFinished:
+ if (GameState.getNoradSubPrepState() == kSubDamaged)
+ playControlMonitorSection(kDeltaLaunchPrepStart * _subControlScale,
+ kDeltaLaunchPrepStop * _subControlScale, kDeltaPrepFinished, _gameState, false);
+ else
+ playControlMonitorSection(kAlphaLaunchPrepStart * _subControlScale,
+ kAlphaLaunchPrepStop * _subControlScale, kAlphaPrepFinished, _gameState, false);
+ break;
+ case kAlphaPrepFinished:
+ GameState.setNoradSubPrepState(kSubPrepped);
+ GameState.setScoringPreppedSub(true);
+ setControlMonitorToTime(kMainMenuTime * _subControlScale, kAlphaMainMenu, true);
+ break;
+ case kClawHighlightFinished:
+ playControlMonitorSection(kClawMenuStart * _subControlScale, kClawMenuStop * _subControlScale,
+ kClawMenuFinished, _gameState, false);
+ break;
+ case kClawMenuFinished:
+ owner->playClawMonitorIntro();
+ showButtons();
+ setControlMonitorToTime(kClawMenuTime * _subControlScale, kClawMenu, true);
+
+ if (!_playingAgainstRobot) {
+ updateClawMonitor();
+ owner->loopExtraSequence(_clawExtraIDs[s_clawStateTable[_clawPosition][kLoopActionIndex]]);
+ }
+ break;
+ case kDeltaSplashFinished:
+ setControlMonitorToTime(kMainMenuTime * _subControlScale, kDeltaMainMenu, true);
+
+ if (_playingAgainstRobot) {
+ _robotState = kRobotApproaching;
+ playClawMonitorSection(kRobotApproachStart, kRobotApproachStop, 0, _gameState, true);
+ owner->startExtraSequence(kN60RobotApproaches, kExtraCompletedFlag, kFilterAllInput);
+ }
+ break;
+ case kDeltaPrepFinished:
+ setControlMonitorToTime(kMainMenuTime * _subControlScale, kDeltaMainMenu, true);
+ break;
+ }
+ } else if (notification == &_greenBallNotification) {
+ if (_robotState == kRobotWon) {
+ // We are using the green ball notification to hide stuff when the robot comes through
+ // the glass.
+ hideEverything();
+ } else {
+ // We are now midway through a move, time to update the claw's position and the green
+ // ball.
+ _clawPosition = _clawNextPosition;
+ updateClawMonitor();
+ updateGreenBall();
+ }
+ } else if (notification == _neighborhoodNotification) {
+ _currentAction = kNoActionIndex;
+ if (_playingAgainstRobot) {
+ switch (_robotState) {
+ case kRobotApproaching:
+ if (_gameState == kClawMenu) {
+ _robotState = kPunchingOnce;
+ dispatchClawAction(kNoActionIndex);
+ } else {
+ robotKillsPlayer(kN60FirstMistake, owner);
+ }
+ break;
+ case kPunchingOnce:
+ if (_nextAction == kMoveDownActionIndex) {
+ _robotState = kPunchingTwice;
+ performActionImmediately(_nextAction, _clawExtraIDs[s_clawStateTable[_clawPosition][_nextAction]], owner);
+ } else {
+ robotKillsPlayer(kN60SecondMistake, owner);
+ }
+ break;
+ case kPunchingTwice:
+ if (_nextAction == kPinchActionIndex) {
+ _robotState = kPunchingThrice;
+ performActionImmediately(_nextAction, _clawExtraIDs[s_clawStateTable[_clawPosition][_nextAction]], owner);
+ } else {
+ robotKillsPlayer(kN60ThirdMistake, owner);
+ }
+ break;
+ case kPunchingThrice:
+ if (_nextAction == kMoveRightActionIndex) {
+ _robotState = kCarriedToDoor;
+ performActionImmediately(_nextAction, _clawExtraIDs[s_clawStateTable[_clawPosition][_nextAction]], owner);
+ } else {
+ robotKillsPlayer(kN60FourthMistake, owner);
+ }
+ break;
+ case kCarriedToDoor:
+ hideEverything();
+ _robotState = kPlayerWon;
+ owner->startExtraSequence(kN60PlayerFollowsRobotToDoor, kExtraCompletedFlag, kFilterAllInput);
+ break;
+ case kPlayerWon:
+ ((NoradDelta *)owner)->playerBeatRobotWithClaw();
+ owner->requestDeleteCurrentInteraction();
+ break;
+ case kRobotWon:
+ g_system->delayMillis(2 * 1000); // 120 ticks
+ ((PegasusEngine *)g_engine)->die(kDeathRobotSubControlRoom);
+ break;
+ }
+ } else {
+ if (_gameState == kPuttingClawAway && _nextAction == kNoActionIndex) {
+ if (_clawPosition == _clawStartPosition) {
+ Input scratch;
+ GameInteraction::clickInHotspot(scratch, g_allHotspots.findHotspotByID(_outSpotID));
+ } else {
+ switch (_clawPosition) {
+ case kClawAtA:
+ dispatchClawAction(kMoveLeftActionIndex);
+ break;
+ case kClawAtB:
+ if (_clawStartPosition == kClawAtD) // Norad Alpha
+ dispatchClawAction(kMoveLeftActionIndex);
+ else if (_clawStartPosition == kClawAtC) // Norad Delta
+ dispatchClawAction(kMoveUpActionIndex);
+ break;
+ case kClawAtC:
+ dispatchClawAction(kMoveDownActionIndex);
+ break;
+ case kClawAtD:
+ dispatchClawAction(kMoveRightActionIndex);
+ break;
+ }
+ }
+ } else {
+ dispatchClawAction(_nextAction);
+ }
+ }
+ }
+}
+
+void SubControlRoom::hideEverything() {
+ hideButtons();
+ _subControlMovie.hide();
+ _clawMonitorMovie.hide();
+ _greenBall.hide();
+}
+
+void SubControlRoom::robotKillsPlayer(const uint32 extraID, Neighborhood *owner) {
+ _robotState = kRobotWon;
+ owner->startExtraSequence(extraID, kExtraCompletedFlag, kFilterAllInput);
+ _greenBallTimer.stop();
+ _greenBallTimer.setSegment(0, 32 * _greenBallTimer.getScale() / 15);
+ _greenBallTimer.setTime(0);
+ _greenBallCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ _greenBallTimer.start();
+}
+
+void SubControlRoom::activateHotspots() {
+ if (_robotState == kRobotWon || _robotState == kPlayerWon)
+ return;
+
+ GameInteraction::activateHotspots();
+
+ switch (_gameState) {
+ case kAlphaMainMenu:
+ case kDeltaMainMenu:
+ g_allHotspots.activateOneHotspot(_prepSpotID);
+ g_allHotspots.activateOneHotspot(_clawControlSpotID);
+ break;
+ case kClawMenu:
+ // This could be called during a move, so use _clawNextPosition.
+ if (_playingAgainstRobot) {
+ g_allHotspots.deactivateOneHotspot(_outSpotID);
+ if (_robotState != kRobotApproaching && _nextAction == kNoActionIndex)
+ for (int i = 0; i < kNumClawButtons; i++)
+ if (s_clawStateTable[_clawNextPosition][i] != kNoActionIndex)
+ g_allHotspots.activateOneHotspot(_clawButtonSpotIDs[i]);
+ } else if (_nextAction == kNoActionIndex) {
+ for (int i = 0; i < kNumClawButtons; i++)
+ if (s_clawStateTable[_clawNextPosition][i] != kNoActionIndex)
+ g_allHotspots.activateOneHotspot(_clawButtonSpotIDs[i]);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void SubControlRoom::showButtons() {
+ if (_playingAgainstRobot && _robotState == kRobotApproaching) {
+ for (int i = 0; i < kNumClawButtons; i++) {
+ _buttons[i]->show();
+ _buttons[i]->setCurrentFrameIndex(kButtonDimFrame);
+ }
+ } else if (_nextAction != kNoActionIndex) {
+ for (int i = 0; i < kNumClawButtons; i++) {
+ _buttons[i]->show();
+ if (i == _currentAction || i == _nextAction)
+ _buttons[i]->setCurrentFrameIndex(kButtonHighlightedFrame);
+ else
+ _buttons[i]->setCurrentFrameIndex(kButtonDimFrame);
+ }
+ } else {
+ for (int i = 0; i < kNumClawButtons; i++) {
+ _buttons[i]->show();
+ if (i == _currentAction)
+ _buttons[i]->setCurrentFrameIndex(kButtonHighlightedFrame);
+ else if (s_clawStateTable[_clawNextPosition][i] != kNoActionIndex &&
+ _gameState != kPuttingClawAway) // this could be called during a move, so check _clawNextPosition
+ _buttons[i]->setCurrentFrameIndex(kButtonActiveFrame);
+ else
+ _buttons[i]->setCurrentFrameIndex(kButtonDimFrame);
+ }
+ }
+}
+
+void SubControlRoom::hideButtons() {
+ for (int i = 0; i < kNumClawButtons; i++)
+ _buttons[i]->hide();
+}
+
+int SubControlRoom::findActionIndex(HotSpotID id) {
+ for (int i = 0; i < kNumClawButtons; i++)
+ if (id == _clawButtonSpotIDs[i])
+ return i;
+
+ return kNoActionIndex;
+}
+
+void SubControlRoom::clickInHotspot(const Input &input, const Hotspot *spot) {
+ HotSpotID clickedID = spot->getObjectID();
+ int actionIndex = findActionIndex(clickedID);
+
+ if (actionIndex != kNoActionIndex) {
+ dispatchClawAction(actionIndex);
+ } else if (clickedID == _prepSpotID) {
+ playControlMonitorSection(kLaunchPrepHighlightStart * _subControlScale,
+ kLaunchPrepHighlightStop * _subControlScale,
+ kPrepHighlightFinished, kPlayingHighlight, false);
+ } else if (clickedID == _clawControlSpotID) {
+ playControlMonitorSection(kClawControlHighlightStart * _subControlScale,
+ kClawControlHighlightStop * _subControlScale,
+ kClawHighlightFinished, kPlayingHighlight, false);
+ } else if (clickedID == _outSpotID) {
+ _gameState = kPuttingClawAway;
+
+ if (_currentAction == kNoActionIndex) {
+ if (_clawPosition == _clawStartPosition) {
+ GameInteraction::clickInHotspot(input, spot);
+ } else {
+ switch (_clawPosition) {
+ case kClawAtA:
+ dispatchClawAction(kMoveLeftActionIndex);
+ break;
+ case kClawAtB:
+ if (_clawStartPosition == kClawAtD) // Norad Alpha
+ dispatchClawAction(kMoveLeftActionIndex);
+ else if (_clawStartPosition == kClawAtC) // Norad Delta
+ dispatchClawAction(kMoveUpActionIndex);
+ break;
+ case kClawAtC:
+ dispatchClawAction(kMoveDownActionIndex);
+ break;
+ case kClawAtD:
+ dispatchClawAction(kMoveRightActionIndex);
+ break;
+ }
+ }
+ }
+ } else {
+ GameInteraction::clickInHotspot(input, spot);
+ }
+}
+
+void SubControlRoom::dispatchClawAction(const int newAction) {
+ GameState.setScoringPlayedWithClaw(true);
+
+ Neighborhood *owner = getOwner();
+
+ if (newAction == kNoActionIndex) {
+ _currentAction = kNoActionIndex;
+ _nextAction = kNoActionIndex;
+ showButtons();
+ updateGreenBall();
+
+ if (_playingAgainstRobot)
+ owner->startExtraSequence(kN60ArmActivated, kExtraCompletedFlag, kFilterAllInput);
+ else
+ owner->loopExtraSequence(_clawExtraIDs[s_clawStateTable[_clawPosition][kLoopActionIndex]]);
+ } else {
+ if (_currentAction == kNoActionIndex) {
+ if (_playingAgainstRobot) {
+ _nextAction = newAction;
+ showButtons();
+ updateGreenBall();
+ } else {
+ performActionImmediately(newAction, _clawExtraIDs[s_clawStateTable[_clawPosition][newAction]], owner);
+ }
+ } else if (_nextAction == kNoActionIndex) {
+ _nextAction = newAction;
+ showButtons();
+ updateGreenBall();
+ }
+ }
+}
+
+void SubControlRoom::performActionImmediately(const int action, const uint32 extraID, Neighborhood *owner) {
+ _currentAction = action;
+ _nextAction = kNoActionIndex;
+ ExtraTable::Entry entry;
+
+ switch (action) {
+ case kMoveDownActionIndex:
+ case kMoveRightActionIndex:
+ case kMoveLeftActionIndex:
+ case kMoveUpActionIndex:
+ // Set up green ball callback.
+ owner->getExtraEntry(extraID, entry);
+ _greenBallTimer.stop();
+ _greenBallTimer.setSegment(entry.movieStart, entry.movieStart + owner->getNavMovie()->getScale());
+ _greenBallTimer.setTime(entry.movieStart);
+ _greenBallCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ // Start move.
+ _greenBallTimer.start();
+ break;
+ }
+
+ if (_playingAgainstRobot) {
+ switch (_robotState) {
+ case kPunchingTwice:
+ owner->startExtraSequence(kN60ArmToPositionB, kExtraCompletedFlag, kFilterAllInput);
+ break;
+ case kPunchingThrice:
+ owner->startExtraSequence(kN60ArmGrabsRobot, kExtraCompletedFlag, kFilterAllInput);
+ break;
+ case kCarriedToDoor:
+ owner->startExtraSequence(kN60ArmCarriesRobotToPositionA, kExtraCompletedFlag, kFilterAllInput);
+ break;
+ }
+ } else {
+ owner->startExtraSequence(extraID, kExtraCompletedFlag, kFilterAllInput);
+ }
+
+ switch (action) {
+ case kMoveDownActionIndex:
+ _clawNextPosition = s_clawMovieTable[_clawPosition][kMoveClawDown];
+ break;
+ case kMoveRightActionIndex:
+ _clawNextPosition = s_clawMovieTable[_clawPosition][kMoveClawRight];
+ break;
+ case kMoveLeftActionIndex:
+ _clawNextPosition = s_clawMovieTable[_clawPosition][kMoveClawLeft];
+ break;
+ case kMoveUpActionIndex:
+ _clawNextPosition = s_clawMovieTable[_clawPosition][kMoveClawUp];
+ break;
+ case kLoopActionIndex:
+ // Do nothing.
+ break;
+ default:
+ playClawMonitorSection(s_clawMonitorTable[action][_clawPosition][0],
+ s_clawMonitorTable[action][_clawPosition][1], 0, _gameState, true);
+ break;
+ }
+
+ showButtons();
+ updateGreenBall();
+}
+
+void SubControlRoom::setControlMonitorToTime(const TimeValue newTime, const int newState, const bool shouldAllowInput) {
+ _subControlMovie.stop();
+ _subControlMovie.setSegment(0, _subControlMovie.getDuration());
+ _subControlMovie.setTime(newTime);
+ _subControlMovie.redrawMovieWorld();
+ _gameState = newState;
+ allowInput(shouldAllowInput);
+}
+
+void SubControlRoom::playControlMonitorSection(const TimeValue in, const TimeValue out, const NotificationFlags flags,
+ const int newState, const bool shouldAllowInput) {
+ _subControlMovie.stop();
+ _subControlMovie.setSegment(in, out);
+ _subControlMovie.setTime(in);
+
+ if (flags != 0) {
+ _subControlCallBack.setCallBackFlag(flags);
+ _subControlCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ }
+
+ _gameState = newState;
+ allowInput(shouldAllowInput);
+ _subControlMovie.start();
+}
+
+void SubControlRoom::updateClawMonitor() {
+ switch (_clawPosition) {
+ case kClawAtA:
+ setClawMonitorToTime(kClawAtATime);
+ break;
+ case kClawAtB:
+ setClawMonitorToTime(kClawAtBTime);
+ break;
+ case kClawAtC:
+ setClawMonitorToTime(kClawAtCTime);
+ break;
+ case kClawAtD:
+ setClawMonitorToTime(kClawAtDTime);
+ break;
+ }
+}
+
+void SubControlRoom::setClawMonitorToTime(const TimeValue newTime) {
+ _clawMonitorMovie.stop();
+ _clawMonitorMovie.setSegment(0, _clawMonitorMovie.getDuration());
+ _clawMonitorMovie.setTime(newTime);
+ _clawMonitorMovie.redrawMovieWorld();
+}
+
+void SubControlRoom::playClawMonitorSection(const TimeValue in, const TimeValue out, const NotificationFlags flags,
+ const int newState, const bool shouldAllowInput) {
+ _clawMonitorMovie.stop();
+ _clawMonitorMovie.setSegment(in, out);
+ _clawMonitorMovie.setTime(in);
+
+ if (flags != 0) {
+ _clawMonitorCallBack.setCallBackFlag(flags);
+ _clawMonitorCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ }
+
+ _gameState = newState;
+ allowInput(shouldAllowInput);
+ _clawMonitorMovie.start();
+}
+
+void SubControlRoom::updateGreenBall() {
+ switch (_currentAction) {
+ case kMoveDownActionIndex:
+ switch (_nextAction) {
+ case kMoveRightActionIndex:
+ moveGreenBallToA();
+ break;
+ case kMoveLeftActionIndex:
+ moveGreenBallToD();
+ break;
+ case kMoveUpActionIndex:
+ moveGreenBallToC();
+ break;
+ default:
+ moveGreenBallToB();
+ break;
+ }
+ break;
+ case kMoveRightActionIndex:
+ if (_clawNextPosition == kClawAtA) {
+ switch (_nextAction) {
+ case kMoveLeftActionIndex:
+ moveGreenBallToB();
+ break;
+ default:
+ moveGreenBallToA();
+ break;
+ }
+ } else {
+ switch (_nextAction) {
+ case kMoveRightActionIndex:
+ moveGreenBallToA();
+ break;
+ case kMoveLeftActionIndex:
+ moveGreenBallToD();
+ break;
+ case kMoveUpActionIndex:
+ moveGreenBallToC();
+ break;
+ default:
+ moveGreenBallToB();
+ break;
+ }
+ }
+ break;
+ case kMoveLeftActionIndex:
+ if (_clawNextPosition == kClawAtB) {
+ switch (_nextAction) {
+ case kMoveRightActionIndex:
+ moveGreenBallToA();
+ break;
+ case kMoveLeftActionIndex:
+ moveGreenBallToD();
+ break;
+ case kMoveUpActionIndex:
+ moveGreenBallToC();
+ break;
+ default:
+ moveGreenBallToB();
+ break;
+ }
+ } else {
+ switch (_nextAction) {
+ case kMoveRightActionIndex:
+ moveGreenBallToB();
+ break;
+ default:
+ moveGreenBallToD();
+ break;
+ }
+ }
+ break;
+ case kMoveUpActionIndex:
+ switch (_nextAction) {
+ case kMoveDownActionIndex:
+ moveGreenBallToB();
+ break;
+ default:
+ moveGreenBallToC();
+ break;
+ }
+ break;
+ default:
+ switch (_nextAction) {
+ case kMoveDownActionIndex:
+ moveGreenBallToB();
+ break;
+ case kMoveRightActionIndex:
+ if (_clawPosition == kClawAtB)
+ moveGreenBallToA();
+ else
+ moveGreenBallToB();
+ break;
+ case kMoveLeftActionIndex:
+ if (_clawPosition == kClawAtB)
+ moveGreenBallToD();
+ else
+ moveGreenBallToB();
+ break;
+ case kMoveUpActionIndex:
+ moveGreenBallToC();
+ break;
+ default:
+ _greenBall.hide();
+ break;
+ }
+ break;
+ }
+}
+
+void SubControlRoom::moveGreenBallToA() {
+ if (_clawPosition == kClawAtA) {
+ if (_playingAgainstRobot)
+ _greenBall.setCurrentFrameIndex(kGreenBallAtAWithClawAndRobot);
+ else
+ _greenBall.setCurrentFrameIndex(kGreenBallAtAWithClaw);
+ } else {
+ _greenBall.setCurrentFrameIndex(kGreenBallAtA);
+ }
+
+ _greenBall.moveElementTo(kNoradGreenBallAtALeft, kNoradGreenBallAtATop);
+ _greenBall.show();
+}
+
+void SubControlRoom::moveGreenBallToB() {
+ if (_clawPosition == kClawAtB) {
+ if (_playingAgainstRobot)
+ _greenBall.setCurrentFrameIndex(kGreenBallAtBWithClawAndRobot);
+ else
+ _greenBall.setCurrentFrameIndex(kGreenBallAtBWithClaw);
+ } else {
+ _greenBall.setCurrentFrameIndex(kGreenBallAtB);
+ }
+
+ _greenBall.moveElementTo(kNoradGreenBallAtBLeft, kNoradGreenBallAtBTop);
+ _greenBall.show();
+}
+
+void SubControlRoom::moveGreenBallToC() {
+ switch (_clawPosition) {
+ case kClawAtA:
+ _greenBall.setCurrentFrameIndex(kGreenBallAtCArmAtA);
+ break;
+ case kClawAtB:
+ _greenBall.setCurrentFrameIndex(kGreenBallAtCArmAtB);
+ break;
+ case kClawAtC:
+ _greenBall.setCurrentFrameIndex(kGreenBallAtCWithClaw);
+ break;
+ case kClawAtD:
+ _greenBall.setCurrentFrameIndex(kGreenBallAtCArmAtD);
+ break;
+ }
+
+ _greenBall.moveElementTo(kNoradGreenBallAtCLeft, kNoradGreenBallAtCTop);
+ _greenBall.show();
+}
+
+void SubControlRoom::moveGreenBallToD() {
+ if (_clawPosition == kClawAtD)
+ _greenBall.setCurrentFrameIndex(kGreenBallAtDWithClaw);
+ else
+ _greenBall.setCurrentFrameIndex(kGreenBallAtD);
+
+ _greenBall.moveElementTo(kNoradGreenBallAtDLeft, kNoradGreenBallAtDTop);
+ _greenBall.show();
+}
+
+bool SubControlRoom::canSolve() {
+ return _playingAgainstRobot && _robotState < kCarriedToDoor;
+}
+
+void SubControlRoom::doSolve() {
+ _robotState = kCarriedToDoor;
+ hideEverything();
+ getOwner()->startExtraSequence(kN60ArmGrabsRobot, kExtraCompletedFlag, kFilterAllInput);
+}
+
+InputBits SubControlRoom::getInputFilter() {
+ if (_playingAgainstRobot)
+ return GameInteraction::getInputFilter() & ~kFilterDownButtonAny;
+
+ return GameInteraction::getInputFilter();
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/norad/subcontrolroom.h b/engines/pegasus/neighborhood/norad/subcontrolroom.h
new file mode 100644
index 0000000000..6ce599db42
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/subcontrolroom.h
@@ -0,0 +1,133 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_NORAD_SUBCONTROLROOM_H
+#define PEGASUS_NEIGHBORHOOD_NORAD_SUBCONTROLROOM_H
+
+#include "pegasus/interaction.h"
+#include "pegasus/notification.h"
+
+namespace Pegasus {
+
+static const uint32 kClawAtA = 0;
+static const uint32 kClawAtB = 1;
+static const uint32 kClawAtC = 2;
+static const uint32 kClawAtD = 3;
+
+static const int kNumClawButtons = 7;
+
+class Norad;
+
+class SubControlRoom : public GameInteraction, public NotificationReceiver {
+public:
+ SubControlRoom(Neighborhood *);
+ virtual ~SubControlRoom() {}
+
+ void playAgainstRobot();
+
+ virtual void setSoundFXLevel(const uint16);
+
+ bool canSolve();
+ void doSolve();
+
+protected:
+ virtual void openInteraction();
+ virtual void initInteraction();
+ virtual void closeInteraction();
+
+ virtual void activateHotspots();
+ virtual void clickInHotspot(const Input &, const Hotspot *);
+
+ virtual void receiveNotification(Notification *, const NotificationFlags);
+
+ void robotKillsPlayer(const uint32, Neighborhood *);
+ InputBits getInputFilter();
+
+ int findActionIndex(HotSpotID);
+ void dispatchClawAction(const int);
+ void performActionImmediately(const int, const uint32, Neighborhood *);
+
+ void hideEverything();
+ void showButtons();
+ void hideButtons();
+
+ void updateGreenBall();
+ void moveGreenBallToA();
+ void moveGreenBallToB();
+ void moveGreenBallToC();
+ void moveGreenBallToD();
+
+ void setControlMonitorToTime(const TimeValue, const int, const bool);
+ void playControlMonitorSection(const TimeValue, const TimeValue, const NotificationFlags,
+ const int, const bool);
+
+ void updateClawMonitor();
+ void setClawMonitorToTime(const TimeValue);
+ void playClawMonitorSection(const TimeValue, const TimeValue, const NotificationFlags,
+ const int, const bool);
+
+ Movie _subControlMovie;
+ TimeScale _subControlScale;
+ Notification _subControlNotification;
+ NotificationCallBack _subControlCallBack;
+ Movie _clawMonitorMovie;
+ NotificationCallBack _clawMonitorCallBack;
+ int _gameState;
+ uint32 _clawStartPosition;
+ uint32 _clawPosition;
+ uint32 _clawNextPosition;
+ const uint32 *_clawExtraIDs;
+
+ int _currentAction;
+ int _nextAction;
+
+ Sprite *_buttons[kNumClawButtons];
+ Sprite _pinchButton;
+ Sprite _downButton;
+ Sprite _rightButton;
+ Sprite _leftButton;
+ Sprite _upButton;
+ Sprite _ccwButton;
+ Sprite _cwButton;
+
+ Sprite _greenBall;
+ TimeBase _greenBallTimer;
+ Notification _greenBallNotification;
+ NotificationCallBack _greenBallCallBack;
+
+ HotSpotID _outSpotID;
+ HotSpotID _prepSpotID;
+ HotSpotID _clawControlSpotID;
+ HotSpotID _clawButtonSpotIDs[kNumClawButtons];
+
+ Notification *_neighborhoodNotification;
+
+ bool _playingAgainstRobot;
+ int _robotState;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/norad/subplatform.cpp b/engines/pegasus/neighborhood/norad/subplatform.cpp
new file mode 100644
index 0000000000..97079a9f53
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/subplatform.cpp
@@ -0,0 +1,205 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/gamestate.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/neighborhood/norad/constants.h"
+#include "pegasus/neighborhood/norad/norad.h"
+#include "pegasus/neighborhood/norad/subplatform.h"
+#include "pegasus/neighborhood/norad/alpha/noradalpha.h"
+
+namespace Pegasus {
+
+// As usual, times here are in seconds.
+
+static const TimeValue kNormalSplashStart = 0;
+static const TimeValue kNormalSplashStop = 5;
+
+static const TimeValue kPrepSubStart = 5;
+static const TimeValue kPrepSubStop = 15;
+
+static const TimeValue kPrepIncompleteStart = 15;
+static const TimeValue kPrepIncompleteStop = 19;
+
+static const TimeValue kDamagedStart = 19;
+static const TimeValue kDamagedStop = 28;
+
+static const NotificationFlags kNormalSplashFinished = 1;
+static const NotificationFlags kPrepSubFinished = kNormalSplashFinished << 1;
+static const NotificationFlags kPrepIncompleteFinished = kPrepSubFinished << 1;
+static const NotificationFlags kDamagedFinished = kPrepIncompleteFinished << 1;
+
+static const NotificationFlags kPlatformNotificationFlags = kNormalSplashFinished |
+ kPrepSubFinished |
+ kPrepIncompleteFinished |
+ kDamagedFinished;
+
+static const uint16 kSubPreppedBit = (1 << 0);
+static const uint16 kWaitingForPlayerBit = (1 << 1);
+
+SubPlatform::SubPlatform(Neighborhood *handler) : GameInteraction(kNoradSubPlatformInteractionID, handler),
+ _platformMovie(kPlatformMonitorID), _platformNotification(kNoradSubPlatformNotificationID, (PegasusEngine *)g_engine) {
+ _neighborhoodNotification = handler->getNeighborhoodNotification();
+}
+
+void SubPlatform::openInteraction() {
+ _stateBits = 0;
+
+ // TODO: These next two lines seem unused?
+ if (GameState.getNoradSubPrepState() == kSubPrepped)
+ _stateBits |= kSubPreppedBit;
+
+ _stateBits |= kWaitingForPlayerBit;
+ _platformMovie.initFromMovieFile("Images/Norad Alpha/Platform Monitor Movie");
+ _platformMovie.setVolume(((PegasusEngine *)g_engine)->getSoundFXLevel());
+ _platformMovie.moveElementTo(kNoradPlatformLeft, kNoradPlatformTop);
+ _platformScale = _platformMovie.getScale();
+ _platformMovie.setDisplayOrder(kPlatformOrder);
+ _platformMovie.startDisplaying();
+ _platformCallBack.setNotification(&_platformNotification);
+ _platformCallBack.initCallBack(&_platformMovie, kCallBackAtExtremes);
+
+ _platformNotification.notifyMe(this, kPlatformNotificationFlags, kPlatformNotificationFlags);
+}
+
+void SubPlatform::initInteraction() {
+ _neighborhoodNotification->notifyMe(this, kExtraCompletedFlag, kExtraCompletedFlag);
+}
+
+void SubPlatform::closeInteraction() {
+ _platformNotification.cancelNotification(this);
+ _platformCallBack.releaseCallBack();
+ _neighborhoodNotification->cancelNotification(this);
+}
+
+void SubPlatform::setSoundFXLevel(const uint16 fxLevel) {
+ _platformMovie.setVolume(fxLevel);
+}
+
+void SubPlatform::receiveNotification(Notification *notification, const NotificationFlags flags) {
+ FaderMoveSpec loop1Spec, loop2Spec;
+ ExtraTable::Entry entry;
+
+ Norad *owner = (Norad *)getOwner();
+
+ if (notification == &_platformNotification) {
+ switch (flags) {
+ case kNormalSplashFinished:
+ _platformMovie.stop();
+ switch (GameState.getNoradSubPrepState()) {
+ case kSubNotPrepped:
+ _platformMovie.setSegment(kPrepIncompleteStart * _platformScale, kPrepIncompleteStop * _platformScale);
+ _platformMovie.setTime(kPrepIncompleteStart * _platformScale);
+ _platformCallBack.setCallBackFlag(kPrepIncompleteFinished);
+ _platformCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ _platformMovie.start();
+ break;
+ case kSubPrepped:
+ _platformMovie.setSegment(kPrepSubStart * _platformScale, kPrepSubStop * _platformScale);
+ _platformMovie.setTime(kPrepSubStart * _platformScale);
+ _platformCallBack.setCallBackFlag(kPrepSubFinished);
+ _platformCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ owner->startExtraSequence(kNorad19PrepSub, 0, kFilterNoInput);
+ _platformMovie.start();
+ break;
+ case kSubDamaged:
+ // Shouldn't happen.
+ break;
+ }
+ break;
+ case kPrepSubFinished:
+ _platformMovie.stop();
+ _platformMovie.stopDisplaying();
+
+ owner->getExtraEntry(kNorad19ExitToSub, entry);
+
+ loop1Spec.makeTwoKnotFaderSpec(kNoradAlphaMovieScale, 0, kNoradWarningVolume,
+ entry.movieEnd - entry.movieStart, 0);
+ loop1Spec.insertFaderKnot(4560, kNoradWarningVolume);
+ loop1Spec.insertFaderKnot(5080, 0);
+
+ loop2Spec.makeTwoKnotFaderSpec(kNoradAlphaMovieScale, 0, kNoradSuckWindVolume,
+ entry.movieEnd - entry.movieStart, 0);
+ loop1Spec.insertFaderKnot(4560, kNoradSuckWindVolume);
+ loop1Spec.insertFaderKnot(5080, 0);
+
+ owner->startExtraSequence(kNorad19ExitToSub, kExtraCompletedFlag, kFilterNoInput);
+
+ owner->startLoop1Fader(loop1Spec);
+ owner->startLoop2Fader(loop2Spec);
+ break;
+ case kPrepIncompleteFinished:
+ ((NoradAlpha *)owner)->setSubPrepFailed(true);
+ g_AIArea->checkMiddleArea();
+ // Fall through...
+ case kDamagedFinished:
+ _platformMovie.stop();
+ _platformMovie.hide();
+ _stateBits |= kWaitingForPlayerBit;
+ allowInput(true);
+ break;
+ }
+ } else if (notification == _neighborhoodNotification) {
+ allowInput(true);
+ ((PegasusEngine *)g_engine)->jumpToNewEnvironment(kNoradSubChaseID, kNoRoomID, kNoDirection);
+ GameState.setScoringEnteredSub(true);
+ }
+}
+
+void SubPlatform::activateHotspots() {
+ if (_stateBits & kWaitingForPlayerBit)
+ g_allHotspots.activateOneHotspot(kNorad19ActivateMonitorSpotID);
+
+ GameInteraction::activateHotspots();
+}
+
+void SubPlatform::clickInHotspot(const Input &input, const Hotspot *spot) {
+ if (spot->getObjectID() == kNorad19ActivateMonitorSpotID) {
+ if (GameState.getNoradSubPrepState() == kSubDamaged) {
+ _platformMovie.setSegment(kDamagedStart * _platformScale, kDamagedStop * _platformScale);
+ _platformMovie.setTime(kDamagedStart * _platformScale);
+ _platformCallBack.setCallBackFlag(kDamagedFinished);
+ } else {
+ _platformMovie.setSegment(kNormalSplashStart * _platformScale, kNormalSplashStop * _platformScale);
+ _platformMovie.setTime(kNormalSplashStart * _platformScale);
+ _platformCallBack.setCallBackFlag(kNormalSplashFinished);
+ }
+
+ _platformCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+
+ _platformMovie.show();
+ _platformMovie.start();
+ _platformMovie.redrawMovieWorld();
+
+ _stateBits &= ~kWaitingForPlayerBit;
+
+ allowInput(false);
+ } else {
+ GameInteraction::clickInHotspot(input, spot);
+ }
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/norad/subplatform.h b/engines/pegasus/neighborhood/norad/subplatform.h
new file mode 100644
index 0000000000..82e86ecae2
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/subplatform.h
@@ -0,0 +1,63 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_NORAD_SUBPLATFORM_H
+#define PEGASUS_NEIGHBORHOOD_NORAD_SUBPLATFORM_H
+
+#include "pegasus/interaction.h"
+#include "pegasus/movie.h"
+#include "pegasus/notification.h"
+#include "pegasus/timers.h"
+
+namespace Pegasus {
+
+class SubPlatform : public GameInteraction, public NotificationReceiver {
+public:
+ SubPlatform(Neighborhood *);
+ virtual ~SubPlatform() {}
+
+ virtual void setSoundFXLevel(const uint16);
+
+protected:
+ virtual void openInteraction();
+ virtual void initInteraction();
+ virtual void closeInteraction();
+
+ virtual void activateHotspots();
+ virtual void clickInHotspot(const Input &, const Hotspot *);
+
+ virtual void receiveNotification(Notification *, const NotificationFlags);
+
+ Movie _platformMovie;
+ TimeScale _platformScale;
+ Notification _platformNotification;
+ NotificationCallBack _platformCallBack;
+ Notification *_neighborhoodNotification;
+ uint16 _stateBits;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/prehistoric/prehistoric.cpp b/engines/pegasus/neighborhood/prehistoric/prehistoric.cpp
new file mode 100644
index 0000000000..814d7717de
--- /dev/null
+++ b/engines/pegasus/neighborhood/prehistoric/prehistoric.cpp
@@ -0,0 +1,689 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/compass.h"
+#include "pegasus/energymonitor.h"
+#include "pegasus/gamestate.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/ai/ai_action.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/ai/ai_condition.h"
+#include "pegasus/ai/ai_rule.h"
+#include "pegasus/neighborhood/prehistoric/prehistoric.h"
+
+namespace Pegasus {
+
+static const int16 s_prehistoricCompass[kPrehistoric25 + 1][4] = {
+ { 0, 170, 90, 270 }, // kPrehistoric01
+ { 0, 180, 90, 270 }, // kPrehistoric02
+ { 10, 180, 90, 270 }, // kPrehistoric03
+ { 10, 190, 90, 270 }, // kPrehistoric04
+ { 10, 195, 90, 270 }, // kPrehistoric05
+ { 20, 210, 90, 270 }, // kPrehistoric06
+ { 20, 200, 130, 276 }, // kPrehistoric07
+ { 20, 176, 110, 260 }, // kPrehistoric08
+ { 20, 200, 100, 270 }, // kPrehistoric09
+ { 14, 186, 100, 280 }, // kPrehistoric10
+ { 26, 206, 116, 296 }, // kPrehistoric11
+ { 60, 226, 140, 320 }, // kPrehistoric12
+ { 0, 180, 80, 270 }, // kPrehistoric13
+ { 14, 200, 106, 286 }, // kPrehistoric14
+ { -10, 174, 80, 260 }, // kPrehistoric15
+ { 54, 236, 140, 210 }, // kPrehistoric16
+ { -24, 160, 70, 250 }, // kPrehistoric17
+ { 26, 206, 140, 296 }, // kPrehistoric18
+ { -16, 160, 70, 250 }, // kPrehistoric19
+ { -16, 160, 70, 250 }, // kPrehistoric20
+ { -10, 160, 90, 250 }, // kPrehistoric21
+ { -20, 160, 70, 244 }, // kPrehistoric22
+ { -20, 160, 70, 244 }, // kPrehistoric22North
+ { 60, 234, 150, 330 }, // kPrehistoric23
+ { 50, 230, 140, 320 }, // kPrehistoric24
+ { 60, 240, 140, 330 } // kPrehistoric25
+};
+
+static const TimeValue kPrehistoricFlashlightClickIn = 0;
+static const TimeValue kPrehistoricFlashlightClickOut = 138;
+
+static const TimeValue kPrehistoricBumpIntoWallIn = 138;
+static const TimeValue kPrehistoricBumpIntoWallOut = 291;
+
+static const TimeValue kBridgeRetractIn = 291;
+static const TimeValue kBridgeRetractOut = 1499;
+
+static const TimeValue kPrehistoricWarningTimeLimit = kTenMinutes;
+
+Prehistoric::Prehistoric(InputHandler *nextHandler, PegasusEngine *owner) : Neighborhood(nextHandler, owner, "Prehistoric", kPrehistoricID) {
+ setIsItemTaken(kHistoricalLog);
+}
+
+uint16 Prehistoric::getDateResID() const {
+ return kDatePrehistoricID;
+}
+
+void Prehistoric::init() {
+ Neighborhood::init();
+
+ // Forces a stop so the flashlight can turn off...
+ forceStridingStop(kPrehistoric12, kSouth, kNoAlternateID);
+}
+
+void Prehistoric::start() {
+ if (g_energyMonitor) {
+ g_energyMonitor->stopEnergyDraining();
+ g_energyMonitor->restoreLastEnergyValue();
+ _vm->resetEnergyDeathReason();
+ g_energyMonitor->startEnergyDraining();
+ }
+
+ Neighborhood::start();
+}
+
+class FinishPrehistoricAction : public AIPlayMessageAction {
+public:
+ FinishPrehistoricAction() : AIPlayMessageAction("Images/AI/Prehistoric/XP25W", false) {}
+ ~FinishPrehistoricAction() {}
+
+ void performAIAction(AIRule *);
+
+};
+
+void FinishPrehistoricAction::performAIAction(AIRule *rule) {
+ AIPlayMessageAction::performAIAction(rule);
+ ((PegasusEngine *)g_engine)->die(kPlayerWonGame);
+}
+
+void Prehistoric::setUpAIRules() {
+ Neighborhood::setUpAIRules();
+
+ if (g_AIArea) {
+ if (_vm->isDemo()) {
+ FinishPrehistoricAction *doneAction = new FinishPrehistoricAction();
+ AIHasItemCondition *hasLogCondition = new AIHasItemCondition(kHistoricalLog);
+ AIRule *rule = new AIRule(hasLogCondition, doneAction);
+ g_AIArea->addAIRule(rule);
+ } else {
+ AIPlayMessageAction *messageAction = new AIPlayMessageAction("Images/AI/Prehistoric/XP1NB", false);
+ AILocationCondition *locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kPrehistoric16, kNorth));
+ AIRule *rule = new AIRule(locCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Prehistoric/XP2SB", false);
+ locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kPrehistoric01, kSouth));
+ rule = new AIRule(locCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Prehistoric/XP2SB", false);
+ locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kPrehistoric08, kEast));
+ rule = new AIRule(locCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Prehistoric/XP2SB", false);
+ locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kPrehistoric25, kWest));
+ rule = new AIRule(locCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Prehistoric/XP16NB", false);
+ locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kPrehistoric23, kNorth));
+ rule = new AIRule(locCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Prehistoric/XP18NB", false);
+ AITimerCondition *timerCondition = new AITimerCondition(kPrehistoricWarningTimeLimit, 1, true);
+ rule = new AIRule(timerCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Prehistoric/XP25W", false);
+ AIHasItemCondition *hasLogCondition = new AIHasItemCondition(kHistoricalLog);
+ rule = new AIRule(hasLogCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+ }
+ }
+}
+
+TimeValue Prehistoric::getViewTime(const RoomID room, const DirectionConstant direction) {
+ ExtraTable::Entry extra;
+ uint32 extraID = 0xffffffff;
+
+ switch (MakeRoomView(room, direction)) {
+ case MakeRoomView(kPrehistoric02, kSouth):
+ if (!GameState.getPrehistoricSeenTimeStream()) {
+ getExtraEntry(kPreArrivalFromTSA, extra);
+ return extra.movieStart;
+ }
+ break;
+ case MakeRoomView(kPrehistoric25, kEast):
+ if (_privateFlags.getFlag(kPrehistoricPrivateVaultOpenFlag)) {
+ if (_vm->itemInLocation(kHistoricalLog, kPrehistoricID, kPrehistoric25, kEast))
+ extraID = kPre25EastViewWithLog;
+ else
+ extraID = kPre25EastViewNoLog;
+ }
+ break;
+ }
+
+ if (extraID == 0xffffffff)
+ return Neighborhood::getViewTime(room, direction);
+
+ getExtraEntry(extraID, extra);
+ return extra.movieEnd - 1;
+}
+
+
+void Prehistoric::findSpotEntry(const RoomID room, const DirectionConstant direction, SpotFlags flags, SpotTable::Entry &entry) {
+ Neighborhood::findSpotEntry(room, direction, flags, entry);
+
+ switch (MakeRoomView(room, direction)) {
+ case MakeRoomView(kPrehistoric01, kSouth):
+ case MakeRoomView(kPrehistoric25, kSouth):
+ entry.clear();
+ break;
+ case MakeRoomView(kPrehistoric01, kEast):
+ if (GameState.getPrehistoricSeenFlyer1())
+ entry.clear();
+ else
+ GameState.setPrehistoricSeenFlyer1(true);
+ break;
+ case MakeRoomView(kPrehistoric08, kEast):
+ if (GameState.getPrehistoricSeenFlyer2())
+ entry.clear();
+ else
+ GameState.setPrehistoricSeenFlyer2(true);
+ break;
+ }
+}
+
+int16 Prehistoric::getStaticCompassAngle(const RoomID room, const DirectionConstant dir) {
+ if (room == kPrehistoricDeath)
+ return g_compass->getFaderValue();
+
+ return s_prehistoricCompass[room][dir];
+}
+
+void Prehistoric::getExitCompassMove(const ExitTable::Entry &exitEntry, FaderMoveSpec &compassMove) {
+ uint32 angle;
+ Neighborhood::getExitCompassMove(exitEntry, compassMove);
+
+ switch (MakeRoomView(exitEntry.room, exitEntry.direction)) {
+ case MakeRoomView(kPrehistoric01, kNorth):
+ compassMove.insertFaderKnot(exitEntry.movieStart + (exitEntry.movieEnd - exitEntry.movieStart) / 2, -10);
+ break;
+ case MakeRoomView(kPrehistoric06, kEast):
+ compassMove.insertFaderKnot(exitEntry.movieStart + (exitEntry.movieEnd - exitEntry.movieStart) / 4, 95);
+ compassMove.insertFaderKnot(exitEntry.movieStart + (exitEntry.movieEnd - exitEntry.movieStart) / 4 * 1, 100);
+ break;
+ case MakeRoomView(kPrehistoric18, kEast):
+ if (getCurrentAlternate() == kAltPrehistoricBridgeSet) {
+ compassMove.insertFaderKnot(exitEntry.movieStart + kPrehistoricFrameDuration * 11, 145);
+ compassMove.insertFaderKnot(exitEntry.movieStart + kPrehistoricFrameDuration * 26, 145);
+ compassMove.insertFaderKnot(exitEntry.movieStart + kPrehistoricFrameDuration * 39, 148);
+ compassMove.insertFaderKnot(exitEntry.movieStart + kPrehistoricFrameDuration * 114, 140);
+ } else {
+ compassMove.insertFaderKnot(exitEntry.movieStart + kPrehistoricFrameDuration * 10, 140);
+ compassMove.insertFaderKnot(exitEntry.movieStart + kPrehistoricFrameDuration * 16, 145);
+ compassMove.insertFaderKnot(exitEntry.movieEnd, 145);
+ }
+ break;
+ case MakeRoomView(kPrehistoric23, kWest):
+ angle = compassMove.getNthKnotValue(0);
+ compassMove.insertFaderKnot(exitEntry.movieStart + kPrehistoricFrameDuration * 17, angle);
+ compassMove.insertFaderKnot(exitEntry.movieStart + kPrehistoricFrameDuration * 32, angle - 90);
+ compassMove.insertFaderKnot(exitEntry.movieEnd, angle - 90);
+ break;
+ }
+}
+
+void Prehistoric::turnTo(const DirectionConstant newDirection) {
+ setCurrentAlternate(kAltPrehistoricNormal);
+ _privateFlags.setFlag(kPrehistoricPrivateVaultOpenFlag, false);
+ Neighborhood::turnTo(newDirection);
+
+ Item *keyCard;
+
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kPrehistoric18, kEast):
+ zoomToVault();
+ break;
+ case MakeRoomView(kPrehistoric18, kNorth):
+ case MakeRoomView(kPrehistoric18, kSouth):
+ if (_privateFlags.getFlag(kPrehistoricPrivateExtendedBridgeFlag)) {
+ playSpotSoundSync(kBridgeRetractIn, kBridgeRetractOut);
+ _privateFlags.setFlag(kPrehistoricPrivateExtendedBridgeFlag, false);
+ loadAmbientLoops();
+ }
+ // fall through
+ case MakeRoomView(kPrehistoric25, kEast):
+ setCurrentActivation(kActivationVaultClosed);
+ break;
+ case MakeRoomView(kPrehistoric16, kNorth):
+ case MakeRoomView(kPrehistoric21, kWest):
+ keyCard = _vm->getAllItems().findItemByID(kKeyCard);
+ if (keyCard->getItemState() == kFlashlightOff) {
+ keyCard->setItemState(kFlashlightOn);
+ playSpotSoundSync(kPrehistoricFlashlightClickIn, kPrehistoricFlashlightClickOut);
+ }
+ break;
+ case MakeRoomView(kPrehistoric16, kEast):
+ case MakeRoomView(kPrehistoric16, kWest):
+ case MakeRoomView(kPrehistoric21, kNorth):
+ case MakeRoomView(kPrehistoric21, kSouth):
+ keyCard = _vm->getAllItems().findItemByID(kKeyCard);
+ if (keyCard->getItemState() == kFlashlightOn) {
+ keyCard->setItemState(kFlashlightOff);
+ playSpotSoundSync(kPrehistoricFlashlightClickIn, kPrehistoricFlashlightClickOut);
+ }
+ break;
+ }
+}
+
+void Prehistoric::zoomToVault() {
+ if (!GameState.getPrehistoricSeenBridgeZoom())
+ startExtraSequence(kPre18EastZoom, kExtraCompletedFlag, kFilterNoInput);
+}
+
+void Prehistoric::checkContinuePoint(const RoomID room, const DirectionConstant direction) {
+ switch (MakeRoomView(room, direction)) {
+ case MakeRoomView(kPrehistoric08, kEast):
+ case MakeRoomView(kPrehistoric18, kSouth):
+ case MakeRoomView(kPrehistoric16, kNorth):
+ case MakeRoomView(kPrehistoric21, kNorth):
+ case MakeRoomView(kPrehistoric25, kNorth):
+ makeContinuePoint();
+ break;
+ }
+}
+
+void Prehistoric::arriveAt(const RoomID room, const DirectionConstant direction) {
+ Item *keyCard;
+
+ if (MakeRoomView(room, direction) == MakeRoomView(kPrehistoric25, kEast) &&
+ _privateFlags.getFlag(kPrehistoricPrivateExtendedBridgeFlag)) {
+ _navMovie.stop();
+ playSpotSoundSync(kBridgeRetractIn, kBridgeRetractOut);
+ _privateFlags.setFlag(kPrehistoricPrivateExtendedBridgeFlag, false);
+ }
+
+ Neighborhood::arriveAt(room, direction);
+
+ switch (MakeRoomView(room, direction)) {
+ case MakeRoomView(kPrehistoricDeath, kNorth):
+ case MakeRoomView(kPrehistoricDeath, kSouth):
+ case MakeRoomView(kPrehistoricDeath, kEast):
+ case MakeRoomView(kPrehistoricDeath, kWest):
+ if (GameState.getLastRoom() == kPrehistoric23)
+ die(kDeathEatenByDinosaur);
+ else
+ die(kDeathFallOffCliff);
+ break;
+ case MakeRoomView(kPrehistoric02, kSouth):
+ if (!GameState.getPrehistoricSeenTimeStream()) {
+ GameState.setPrehistoricTriedToExtendBridge(false);
+ GameState.setPrehistoricSeenFlyer1(false);
+ GameState.setPrehistoricSeenFlyer2(false);
+ GameState.setPrehistoricSeenBridgeZoom(false);
+ GameState.setPrehistoricBreakerThrown(false);
+ startExtraSequence(kPreArrivalFromTSA, kExtraCompletedFlag, kFilterNoInput);
+ }
+ break;
+ case MakeRoomView(kPrehistoric18, kEast):
+ zoomToVault();
+ break;
+ case MakeRoomView(kPrehistoric16, kNorth):
+ keyCard = _vm->getAllItems().findItemByID(kKeyCard);
+
+ if (keyCard->getItemState() == kFlashlightOff) {
+ keyCard->setItemState(kFlashlightOn);
+ playSpotSoundSync(kPrehistoricFlashlightClickIn, kPrehistoricFlashlightClickOut);
+ }
+
+ if (g_AIArea)
+ g_AIArea->checkRules();
+ break;
+ case MakeRoomView(kPrehistoric01, kSouth):
+ case MakeRoomView(kPrehistoric23, kNorth):
+ if (g_AIArea)
+ g_AIArea->checkRules();
+ break;
+ case MakeRoomView(kPrehistoric08, kSouth):
+ case MakeRoomView(kPrehistoric10, kSouth):
+ case MakeRoomView(kPrehistoric12, kSouth):
+ case MakeRoomView(kPrehistoric13, kNorth):
+ case MakeRoomView(kPrehistoric14, kSouth):
+ case MakeRoomView(kPrehistoric15, kNorth):
+ case MakeRoomView(kPrehistoric16, kSouth):
+ case MakeRoomView(kPrehistoric17, kNorth):
+ case MakeRoomView(kPrehistoric18, kSouth):
+ case MakeRoomView(kPrehistoric19, kNorth):
+ case MakeRoomView(kPrehistoric20, kNorth):
+ case MakeRoomView(kPrehistoric21, kEast):
+ keyCard = _vm->getAllItems().findItemByID(kKeyCard);
+
+ if (keyCard->getItemState() == kFlashlightOn) {
+ keyCard->setItemState(kFlashlightOff);
+ playSpotSoundSync(kPrehistoricFlashlightClickIn, kPrehistoricFlashlightClickOut);
+ }
+ break;
+ case MakeRoomView(kPrehistoric25, kEast):
+ setCurrentActivation(kActivationVaultClosed);
+ break;
+ }
+}
+
+void Prehistoric::loadAmbientLoops() {
+ RoomID room = GameState.getCurrentRoom();
+
+ switch (room) {
+ case kPrehistoric02:
+ // 1/4 volume.
+ if (GameState.getPrehistoricSeenTimeStream())
+ loadLoopSound1("Sounds/Prehistoric/P02SAL00.22k.AIFF", 64);
+ break;
+ case kPrehistoric01:
+ case kPrehistoric03:
+ case kPrehistoric04:
+ case kPrehistoric05:
+ case kPrehistoric06:
+ case kPrehistoric07:
+ case kPrehistoric09:
+ case kPrehistoric11:
+ case kPrehistoric13:
+ case kPrehistoric15:
+ case kPrehistoric17:
+ case kPrehistoric19:
+ case kPrehistoric20:
+ // 1/4 volume.
+ loadLoopSound1("Sounds/Prehistoric/P02SAL00.22k.AIFF", 64);
+ break;
+ case kPrehistoric08:
+ case kPrehistoric10:
+ case kPrehistoric12:
+ case kPrehistoric14:
+ case kPrehistoric16:
+ case kPrehistoric18:
+ case kPrehistoric21:
+ // 3/16 volume.
+ loadLoopSound1("Sounds/Prehistoric/P02SAL00.22k.AIFF", 48);
+ break;
+ case kPrehistoric25:
+ // 1/8 volume.
+ loadLoopSound1("Sounds/Prehistoric/P02SAL00.22k.AIFF", 32);
+ break;
+ case kPrehistoric22:
+ case kPrehistoric22North:
+ case kPrehistoric23:
+ case kPrehistoric24:
+ case kPrehistoricDeath:
+ // 0 volume.
+ loadLoopSound1("");
+ break;
+ }
+
+ switch (room) {
+ case kPrehistoric02:
+ case kPrehistoric03:
+ case kPrehistoric04:
+ case kPrehistoric05:
+ case kPrehistoric06:
+ case kPrehistoric07:
+ case kPrehistoric08:
+ case kPrehistoric09:
+ case kPrehistoric10:
+ case kPrehistoric11:
+ case kPrehistoric12:
+ case kPrehistoric13:
+ case kPrehistoric14:
+ case kPrehistoric15:
+ case kPrehistoric16:
+ case kPrehistoric17:
+ case kPrehistoric19:
+ case kPrehistoric20:
+ case kPrehistoric21:
+ case kPrehistoricDeath:
+ loadLoopSound2("");
+ break;
+ case kPrehistoric01:
+ case kPrehistoric25:
+ loadLoopSound2("Sounds/Prehistoric/VolcLoop.22K.AIFF", 64);
+ break;
+ case kPrehistoric18:
+ if (_privateFlags.getFlag(kPrehistoricPrivateExtendedBridgeFlag))
+ loadLoopSound2("Sounds/Prehistoric/P18EAL00.22k.AIFF", 0x100, 0, 0);
+ else
+ loadLoopSound2("");
+ break;
+ case kPrehistoric23:
+ case kPrehistoric24:
+ case kPrehistoric22:
+ case kPrehistoric22North:
+ loadLoopSound2("Sounds/Prehistoric/P24NAL00.22k.AIFF", 64);
+ break;
+ }
+}
+
+void Prehistoric::activateHotspots() {
+ Neighborhood::activateHotspots();
+
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kPrehistoric18, kEast):
+ if (!_privateFlags.getFlag(kPrehistoricPrivateExtendedBridgeFlag))
+ _vm->getAllHotspots().activateOneHotspot(kPre18EastSpotID);
+ break;
+ case MakeRoomView(kPrehistoric22North, kNorth):
+ _vm->getAllHotspots().activateOneHotspot(kPre22NorthBreakerSpotID);
+ break;
+ }
+}
+
+void Prehistoric::clickInHotspot(const Input &input, const Hotspot *spot) {
+ switch (spot->getObjectID()) {
+ case kPre18EastSpotID:
+ if (GameState.getPrehistoricBreakerThrown())
+ startExtraSequence(kPre18EastBridgeOn, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kPre18EastBridgeOut, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kPre22NorthBreakerSpotID:
+ startExtraSequence(kPre22ThrowBreaker, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ default:
+ Neighborhood::clickInHotspot(input, spot);
+ break;
+ }
+}
+
+void Prehistoric::receiveNotification(Notification *notification, const NotificationFlags flags) {
+ Neighborhood::receiveNotification(notification, flags);
+
+ if ((flags & kExtraCompletedFlag) != 0) {
+ _interruptionFilter = kFilterAllInput;
+
+ switch (_lastExtra) {
+ case kPreArrivalFromTSA:
+ GameState.setPrehistoricSeenTimeStream(true);
+ loadAmbientLoops();
+ makeContinuePoint();
+ break;
+ case kPre18EastZoom:
+ startExtraSequence(kPre18EastZoomOut, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kPre18EastZoomOut:
+ GameState.setPrehistoricSeenBridgeZoom(true);
+ break;
+ case kPre18EastBridgeOn:
+ _privateFlags.setFlag(kPrehistoricPrivateExtendedBridgeFlag, true);
+ setCurrentAlternate(kAltPrehistoricBridgeSet);
+ GameState.setPrehistoricTriedToExtendBridge(false);
+ loadAmbientLoops();
+ GameState.setScoringExtendedBridge(true);
+ break;
+ case kPre18EastBridgeOut:
+ GameState.setPrehistoricTriedToExtendBridge(true);
+ if (g_AIArea)
+ g_AIArea->checkMiddleArea();
+ break;
+ case kPre22ThrowBreaker:
+ GameState.setPrehistoricBreakerThrown(true);
+ GameState.setScoringThrewBreaker(true);
+ break;
+ case kPre25EastUnlockingVaultNoLog:
+ case kPre25EastUnlockingVaultWithLog:
+ _vm->addItemToInventory((InventoryItem *)_vm->getAllItems().findItemByID(kJourneymanKey));
+ break;
+ }
+ }
+
+ g_AIArea->checkMiddleArea();
+}
+
+Common::String Prehistoric::getBriefingMovie() {
+ Common::String movieName = Neighborhood::getBriefingMovie();
+
+ if (movieName.empty())
+ movieName = "Images/AI/Prehistoric/XPE";
+
+ return movieName;
+}
+
+Common::String Prehistoric::getEnvScanMovie() {
+ Common::String movieName = Neighborhood::getEnvScanMovie();
+
+ if (movieName.empty()) {
+ if (!_vm->isDemo()) {
+ switch (GameState.getCurrentRoom()) {
+ case kPrehistoric16:
+ case kPrehistoric23:
+ case kPrehistoric24:
+ return "Images/AI/Prehistoric/XP7WB";
+ }
+ }
+
+ return "Images/AI/Prehistoric/XP17NB";
+ }
+
+ return movieName;
+}
+
+uint Prehistoric::getNumHints() {
+ uint numHints = Neighborhood::getNumHints();
+
+ if (numHints == 0) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kPrehistoric18, kEast):
+ if (!GameState.getPrehistoricBreakerThrown() && GameState.getPrehistoricTriedToExtendBridge() &&
+ !_privateFlags.getFlag(kPrehistoricPrivateExtendedBridgeFlag))
+ numHints = 1;
+ break;
+ case MakeRoomView(kPrehistoric25, kEast):
+ if (!_privateFlags.getFlag(kPrehistoricPrivateVaultOpenFlag))
+ numHints = 1;
+ break;
+ }
+ }
+
+ return numHints;
+}
+
+Common::String Prehistoric::getHintMovie(uint hintNum) {
+ Common::String movieName = Neighborhood::getHintMovie(hintNum);
+
+ if (movieName.empty()) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kPrehistoric18, kEast):
+ return "Images/AI/Prehistoric/XP18WD";
+ case MakeRoomView(kPrehistoric25, kEast):
+ return "Images/AI/Globals/XGLOB1A";
+ }
+ }
+
+ return movieName;
+}
+
+bool Prehistoric::canSolve() {
+ return GameState.getCurrentRoomAndView() == MakeRoomView(kPrehistoric18, kEast) &&
+ !GameState.getPrehistoricBreakerThrown() &&
+ GameState.getPrehistoricTriedToExtendBridge() &&
+ !_privateFlags.getFlag(kPrehistoricPrivateExtendedBridgeFlag);
+}
+
+void Prehistoric::doSolve() {
+ GameState.setPrehistoricBreakerThrown(true);
+ startExtraSequence(kPre18EastBridgeOn, kExtraCompletedFlag, kFilterNoInput);
+}
+
+Hotspot *Prehistoric::getItemScreenSpot(Item *item, DisplayElement *element) {
+ if (item->getObjectID() == kHistoricalLog)
+ return _vm->getAllHotspots().findHotspotByID(kPrehistoricHistoricalLogSpotID);
+
+ return Neighborhood::getItemScreenSpot(item, element);
+}
+
+void Prehistoric::pickedUpItem(Item *item) {
+ switch (item->getObjectID()) {
+ case kHistoricalLog:
+ GameState.setScoringGotHistoricalLog(true);
+ break;
+ }
+
+ Neighborhood::pickedUpItem(item);
+}
+
+void Prehistoric::dropItemIntoRoom(Item *item, Hotspot *dropSpot) {
+ switch (item->getObjectID()) {
+ case kJourneymanKey:
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+
+ if (GameState.isTakenItemID(kHistoricalLog))
+ startExtraLongSequence(kPre25EastUnlockingVaultNoLog, kPre25EastVaultOpenNoLog, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraLongSequence(kPre25EastUnlockingVaultWithLog, kPre25EastVaultOpenWithLog, kExtraCompletedFlag, kFilterNoInput);
+
+ _privateFlags.setFlag(kPrehistoricPrivateVaultOpenFlag, true);
+ setCurrentActivation(kActivationVaultOpen);
+ break;
+ default:
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ break;
+ }
+}
+
+void Prehistoric::bumpIntoWall() {
+ requestSpotSound(kPrehistoricBumpIntoWallIn, kPrehistoricBumpIntoWallOut, kFilterAllInput, 0);
+ Neighborhood::bumpIntoWall();
+}
+
+Common::String Prehistoric::getNavMovieName() {
+ return "Images/Prehistoric/Prehistoric.movie";
+}
+
+Common::String Prehistoric::getSoundSpotsName() {
+ return "Sounds/Prehistoric/Prehistoric Spots";
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/prehistoric/prehistoric.h b/engines/pegasus/neighborhood/prehistoric/prehistoric.h
new file mode 100644
index 0000000000..17f9993014
--- /dev/null
+++ b/engines/pegasus/neighborhood/prehistoric/prehistoric.h
@@ -0,0 +1,158 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_PREHISTORIC_H
+#define PEGASUS_NEIGHBORHOOD_PREHISTORIC_H
+
+#include "pegasus/neighborhood/neighborhood.h"
+
+namespace Pegasus {
+
+static const TimeScale kPrehistoricMovieScale = 600;
+static const TimeScale kPrehistoricFramesPerSecond = 15;
+static const TimeScale kPrehistoricFrameDuration = 40;
+
+// Alternate IDs.
+
+static const AlternateID kAltPrehistoricNormal = 0;
+static const AlternateID kAltPrehistoricBridgeSet = 1;
+
+// Room IDs.
+
+static const RoomID kPrehistoric01 = 0;
+static const RoomID kPrehistoric02 = 1;
+static const RoomID kPrehistoric03 = 2;
+static const RoomID kPrehistoric04 = 3;
+static const RoomID kPrehistoric05 = 4;
+static const RoomID kPrehistoric06 = 5;
+static const RoomID kPrehistoric07 = 6;
+static const RoomID kPrehistoric08 = 7;
+static const RoomID kPrehistoric09 = 8;
+static const RoomID kPrehistoric10 = 9;
+static const RoomID kPrehistoric11 = 10;
+static const RoomID kPrehistoric12 = 11;
+static const RoomID kPrehistoric13 = 12;
+static const RoomID kPrehistoric14 = 13;
+static const RoomID kPrehistoric15 = 14;
+static const RoomID kPrehistoric16 = 15;
+static const RoomID kPrehistoric17 = 16;
+static const RoomID kPrehistoric18 = 17;
+static const RoomID kPrehistoric19 = 18;
+static const RoomID kPrehistoric20 = 19;
+static const RoomID kPrehistoric21 = 20;
+static const RoomID kPrehistoric22 = 21;
+static const RoomID kPrehistoric22North = 22;
+static const RoomID kPrehistoric23 = 23;
+static const RoomID kPrehistoric24 = 24;
+static const RoomID kPrehistoric25 = 25;
+static const RoomID kPrehistoricDeath = 26;
+
+// Hot Spot Activation IDs.
+
+static const HotSpotActivationID kActivationVaultClosed = 1;
+static const HotSpotActivationID kActivationVaultOpen = 2;
+
+// Hot Spot IDs.
+
+static const HotSpotID kPre18EastSpotID = 5000;
+static const HotSpotID kPre22NorthSpotID = 5001;
+static const HotSpotID kPre22NorthOutSpotID = 5002;
+static const HotSpotID kPre22NorthBreakerSpotID = 5003;
+static const HotSpotID kPrehistoricKeyDropSpotID = 5004;
+static const HotSpotID kPrehistoricHistoricalLogSpotID = 5005;
+
+// Extra sequence IDs.
+
+static const ExtraID kPreArrivalFromTSA = 0;
+static const ExtraID kPre18EastBridgeOut = 1;
+static const ExtraID kPre18EastBridgeOn = 2;
+static const ExtraID kPre18EastZoom = 3;
+static const ExtraID kPre18EastZoomOut = 4;
+static const ExtraID kPre22ThrowBreaker = 5;
+static const ExtraID kPre25EastUnlockingVaultWithLog = 6;
+static const ExtraID kPre25EastVaultOpenWithLog = 7;
+static const ExtraID kPre25EastViewWithLog = 8;
+static const ExtraID kPre25EastUnlockingVaultNoLog = 9;
+static const ExtraID kPre25EastVaultOpenNoLog = 10;
+static const ExtraID kPre25EastViewNoLog = 11;
+
+class PegasusEngine;
+
+class Prehistoric : public Neighborhood {
+public:
+ Prehistoric(InputHandler *, PegasusEngine *);
+ virtual ~Prehistoric() {}
+
+ virtual uint16 getDateResID() const;
+ virtual void init();
+
+ virtual void arriveAt(const RoomID, const DirectionConstant);
+ virtual void activateHotspots();
+ virtual void clickInHotspot(const Input &, const Hotspot *);
+ Common::String getBriefingMovie();
+ Common::String getEnvScanMovie();
+ uint getNumHints();
+ Common::String getHintMovie(uint);
+
+ Hotspot *getItemScreenSpot(Item *, DisplayElement *);
+ void dropItemIntoRoom(Item *, Hotspot *);
+ void pickedUpItem(Item *);
+
+ void start();
+
+ void bumpIntoWall();
+
+ void checkContinuePoint(const RoomID, const DirectionConstant);
+
+ bool canSolve();
+ void doSolve();
+
+protected:
+ enum {
+ kPrehistoricPrivateVaultOpenFlag,
+ kPrehistoricPrivateExtendedBridgeFlag,
+ kNumPrehistoricPrivateFlags
+ };
+
+ void setUpAIRules();
+ int16 getStaticCompassAngle(const RoomID, const DirectionConstant);
+ void getExitCompassMove(const ExitTable::Entry &, FaderMoveSpec &);
+ virtual void receiveNotification(Notification *, const NotificationFlags);
+ void turnTo(const DirectionConstant);
+ void zoomToVault();
+ TimeValue getViewTime(const RoomID, const DirectionConstant);
+ void findSpotEntry(const RoomID, const DirectionConstant, SpotFlags, SpotTable::Entry &);
+
+ void loadAmbientLoops();
+
+ FlagsArray<byte, kNumPrehistoricPrivateFlags> _privateFlags;
+
+ Common::String getNavMovieName();
+ Common::String getSoundSpotsName();
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/spot.cpp b/engines/pegasus/neighborhood/spot.cpp
new file mode 100644
index 0000000000..f285bf9bc2
--- /dev/null
+++ b/engines/pegasus/neighborhood/spot.cpp
@@ -0,0 +1,70 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/debug.h"
+#include "common/stream.h"
+#include "common/textconsole.h"
+
+#include "pegasus/neighborhood/spot.h"
+
+namespace Pegasus {
+
+void SpotTable::loadFromStream(Common::SeekableReadStream *stream) {
+ uint32 count = stream->readUint32BE();
+ _entries.resize(count);
+
+ for (uint32 i = 0; i < count; i++) {
+ _entries[i].room = stream->readUint16BE();
+ _entries[i].direction = stream->readByte();
+ _entries[i].srcFlags = stream->readByte();
+ _entries[i].altCode = stream->readByte();
+ stream->readByte(); // alignment
+ _entries[i].movieStart = stream->readUint32BE();
+ _entries[i].movieEnd = stream->readUint32BE();
+ _entries[i].dstFlags = stream->readByte();
+ stream->readByte(); // alignment
+ debug(0, "Spot[%d]: %d %d %d %d %d %d %d", i, _entries[i].room, _entries[i].direction,
+ _entries[i].srcFlags, _entries[i].altCode, _entries[i].movieStart,
+ _entries[i].movieEnd, _entries[i].dstFlags);
+ }
+}
+
+void SpotTable::clear() {
+ _entries.clear();
+}
+
+// Two SpotTable::Entries are equal if
+// In addition to having their rooms, directions and alt codes identical...
+// They are both either loops or once only animations AND
+// They overlap in at least one of the on arrival, on turn and on door open bits.
+SpotTable::Entry SpotTable::findEntry(RoomID room, DirectionConstant direction, SpotFlags srcFlags, AlternateID altCode) {
+ for (uint32 i = 0; i < _entries.size(); i++)
+ if (_entries[i].room == room && _entries[i].direction == direction && _entries[i].altCode == altCode && (_entries[i].srcFlags & kSpotLoopsMask) == (srcFlags & kSpotLoopsMask) && ((_entries[i].srcFlags & srcFlags) & kSpotTriggers) != 0)
+ return _entries[i];
+
+ return Entry();
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/spot.h b/engines/pegasus/neighborhood/spot.h
new file mode 100644
index 0000000000..a985420b7c
--- /dev/null
+++ b/engines/pegasus/neighborhood/spot.h
@@ -0,0 +1,97 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_SPOT_H
+#define PEGASUS_NEIGHBORHOOD_SPOT_H
+
+#include "common/array.h"
+#include "common/endian.h"
+
+#include "pegasus/constants.h"
+
+namespace Common {
+ class SeekableReadStream;
+}
+
+namespace Pegasus {
+
+typedef byte SpotFlags;
+
+enum {
+ kSpotLoopsBit, // Loop or once only?
+ kSpotOnArrivalBit,
+ kSpotOnTurnBit,
+ kSpotOnDoorOpenBit
+};
+
+static const SpotFlags kNoSpotFlags = 0;
+static const SpotFlags kSpotLoopsMask = 1 << kSpotLoopsBit;
+static const SpotFlags kSpotOnArrivalMask = 1 << kSpotOnArrivalBit;
+static const SpotFlags kSpotOnTurnMask = 1 << kSpotOnTurnBit;
+static const SpotFlags kSpotOnDoorOpenMask = 1 << kSpotOnDoorOpenBit;
+
+static const SpotFlags kSpotTriggers = kSpotOnArrivalMask | kSpotOnTurnMask | kSpotOnDoorOpenMask;
+
+class SpotTable {
+public:
+ SpotTable() {}
+ ~SpotTable() {}
+
+ static uint32 getResTag() { return MKTAG('S', 'p', 'o', 't'); }
+
+ void loadFromStream(Common::SeekableReadStream *stream);
+ void clear();
+
+ struct Entry {
+ Entry() { clear(); }
+ bool isEmpty() { return movieStart == 0xffffffff; }
+ void clear() {
+ room = kNoRoomID;
+ direction = kNoDirection;
+ srcFlags = kNoSpotFlags;
+ altCode = kNoAlternateID;
+ movieStart = 0xffffffff;
+ movieEnd = 0xffffffff;
+ dstFlags = kNoSpotFlags;
+ }
+
+ RoomID room;
+ DirectionConstant direction;
+ SpotFlags srcFlags;
+ AlternateID altCode;
+ TimeValue movieStart;
+ TimeValue movieEnd;
+ SpotFlags dstFlags;
+ };
+
+ Entry findEntry(RoomID room, DirectionConstant direction, SpotFlags srcFlags, AlternateID altCode);
+
+private:
+ Common::Array<Entry> _entries;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/tsa/fulltsa.cpp b/engines/pegasus/neighborhood/tsa/fulltsa.cpp
new file mode 100644
index 0000000000..b598841b45
--- /dev/null
+++ b/engines/pegasus/neighborhood/tsa/fulltsa.cpp
@@ -0,0 +1,3023 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/cursor.h"
+#include "pegasus/energymonitor.h"
+#include "pegasus/gamestate.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/biochips/aichip.h"
+#include "pegasus/items/biochips/opticalchip.h"
+#include "pegasus/neighborhood/caldoria/caldoria.h"
+#include "pegasus/neighborhood/norad/constants.h"
+#include "pegasus/neighborhood/prehistoric/prehistoric.h"
+#include "pegasus/neighborhood/mars/constants.h"
+#include "pegasus/neighborhood/tsa/fulltsa.h"
+#include "pegasus/neighborhood/wsc/wsc.h"
+
+namespace Pegasus {
+
+// TSA PICTs:
+
+static const ResIDType kTBPCloseBoxPICTID = 800;
+static const ResIDType kTBPRewindPICTID = 801;
+static const ResIDType kUnresolvedPICTID = 802;
+static const ResIDType kResolvedPICTID = 803;
+static const ResIDType kJumpMenuPICTID = 804;
+static const ResIDType kJumpMenuHilitedPICTID = 805;
+static const ResIDType kExitPICTID = 806;
+static const ResIDType kExitHilitedPICTID = 807;
+static const ResIDType kLeftRipPICTID = 808;
+static const ResIDType kComparisonCloseBoxPICTID = 809;
+static const ResIDType kComparisonLeftRewindPICTID = 810;
+static const ResIDType kComparisonRightRewindPICTID = 811;
+static const ResIDType kComparisonHiliteNoradPICTID = 812;
+static const ResIDType kComparisonHiliteMarsPICTID = 813;
+static const ResIDType kComparisonHiliteCaldoriaPICTID = 814;
+static const ResIDType kComparisonHiliteWSCPICTID = 815;
+static const ResIDType kComparisonChancesNoradPICTID = 816;
+static const ResIDType kComparisonChancesMarsPICTID = 817;
+static const ResIDType kComparisonChancesCaldoriaPICTID = 818;
+static const ResIDType kComparisonChancesWSCPICTID = 819;
+static const ResIDType kRedirectionCCRolloverPICTID = 820;
+static const ResIDType kRedirectionRRRolloverPICTID = 821;
+static const ResIDType kRedirectionFDRolloverPICTID = 822;
+static const ResIDType kRedirectionCCDoorPICTID = 823;
+static const ResIDType kRedirectionRRDoorPICTID = 824;
+static const ResIDType kRedirectionFDDoorPICTID = 825;
+static const ResIDType kRedirectionSecuredPICTID = 826;
+static const ResIDType kRedirectionNewTargetPICTID = 827;
+static const ResIDType kRedirectionClosePICTID = 828;
+
+static const int16 kCompassShift = 15;
+
+static const TimeScale kFullTSAMovieScale = 600;
+static const TimeScale kFullTSAFramesPerSecond = 15;
+static const TimeScale kFullTSAFrameDuration = 40;
+
+// Alternate IDs.
+static const AlternateID kAltTSANormal = 0;
+static const AlternateID kAltTSARobotsAtReadyRoom = 1;
+static const AlternateID kAltTSARobotsAtFrontDoor = 2;
+static const AlternateID kAltTSARedAlert = 3;
+
+// Room IDs.
+static const RoomID kTSA01 = 1;
+static const RoomID kTSA02 = 2;
+static const RoomID kTSA03 = 3;
+static const RoomID kTSA04 = 4;
+static const RoomID kTSA05 = 5;
+static const RoomID kTSA0A = 6;
+static const RoomID kTSA06 = 7;
+static const RoomID kTSA07 = 8;
+static const RoomID kTSA08 = 9;
+static const RoomID kTSA09 = 10;
+static const RoomID kTSA10 = 11;
+static const RoomID kTSA11 = 12;
+static const RoomID kTSA12 = 13;
+static const RoomID kTSA13 = 14;
+static const RoomID kTSA14 = 15;
+static const RoomID kTSA15 = 16;
+static const RoomID kTSA16 = 17;
+static const RoomID kTSA17 = 18;
+static const RoomID kTSA18 = 19;
+static const RoomID kTSA19 = 20;
+static const RoomID kTSA0B = 21;
+static const RoomID kTSA21Cyan = 22;
+static const RoomID kTSA22Cyan = 23;
+static const RoomID kTSA23Cyan = 24;
+static const RoomID kTSA24Cyan = 25;
+static const RoomID kTSA25Cyan = 26;
+static const RoomID kTSA21Red = 27;
+static const RoomID kTSA23Red = 29;
+static const RoomID kTSA24Red = 30;
+static const RoomID kTSA25Red = 31;
+static const RoomID kTSA26 = 32;
+static const RoomID kTSA27 = 33;
+static const RoomID kTSA28 = 34;
+static const RoomID kTSA29 = 35;
+static const RoomID kTSA30 = 36;
+static const RoomID kTSA31 = 37;
+static const RoomID kTSA32 = 38;
+static const RoomID kTSA33 = 39;
+static const RoomID kTSA34 = 40;
+static const RoomID kTSA35 = 41;
+static const RoomID kTSADeathRoom = 43;
+
+// Hot Spot Activation IDs.
+static const HotSpotActivationID kActivateTSAReadyForCard = 1;
+static const HotSpotActivationID kActivateTSAReadyToTransport = 2;
+static const HotSpotActivationID kActivateTSARobotsAwake = 3;
+static const HotSpotActivationID kActivateTSA0BZoomedOut = 4;
+static const HotSpotActivationID kActivateTSA0BZoomedIn = 5;
+static const HotSpotActivationID kActivateTSA0BComparisonVideo = 6;
+static const HotSpotActivationID kActivationLogReaderOpen = 7;
+static const HotSpotActivationID kActivateTSA0BTBPVideo = 8;
+static const HotSpotActivationID kActivationDoesntHaveKey = 9;
+static const HotSpotActivationID kActivationKeyVaultOpen = 10;
+static const HotSpotActivationID kActivationDoesntHaveChips = 11;
+static const HotSpotActivationID kActivationChipVaultOpen = 12;
+static const HotSpotActivationID kActivationJumpToPrehistoric = 13;
+static const HotSpotActivationID kActivationJumpToNorad = 14;
+static const HotSpotActivationID kActivationJumpToMars = 15;
+static const HotSpotActivationID kActivationJumpToWSC = 16;
+static const HotSpotActivationID kActivationReadyToExit = 17;
+static const HotSpotActivationID kActivationReadyForJumpMenu = 18;
+static const HotSpotActivationID kActivationMainJumpMenu = 19;
+
+// Hot Spot IDs.
+static const HotSpotID kTSAGTCardDropSpotID = 5000;
+static const HotSpotID kTSAGTTokyoSpotID = 5001;
+static const HotSpotID kTSAGTCaldoriaSpotID = 5002;
+static const HotSpotID kTSAGTBeachSpotID = 5003;
+static const HotSpotID kTSAGTOtherSpotID = 5004;
+static const HotSpotID kTSA02DoorSpotID = 5005;
+static const HotSpotID kTSA03EastJimenezSpotID = 5006;
+static const HotSpotID kTSA03WestCrenshawSpotID = 5007;
+static const HotSpotID kTSA04EastMatsumotoSpotID = 5008;
+static const HotSpotID kTSA04WestCastilleSpotID = 5009;
+static const HotSpotID kTSA05EastSinclairSpotID = 5010;
+static const HotSpotID kTSA05WestWhiteSpotID = 5011;
+static const HotSpotID kTSA0AEastSpotID = 5012;
+static const HotSpotID kTSA0AWastSpotID = 5013;
+static const HotSpotID kTSA0BEastMonitorSpotID = 5014;
+static const HotSpotID kTSA0BEastMonitorOutSpotID = 5015;
+static const HotSpotID kTSA0BEastCompareNoradSpotID = 5016;
+static const HotSpotID kTSA0BEastCompareMarsSpotID = 5017;
+static const HotSpotID kTSA0BEastCompareCaldoriaSpotID = 5018;
+static const HotSpotID kTSA0BEastCompareWSCSpotID = 5019;
+static const HotSpotID kTSA0BEastLeftRewindSpotID = 5020;
+static const HotSpotID kTSA0BEastLeftPlaySpotID = 5021;
+static const HotSpotID kTSA0BEastRightRewindSpotID = 5022;
+static const HotSpotID kTSA0BEastRightPlaySpotID = 5023;
+static const HotSpotID kTSA0BEastCloseVideoSpotID = 5024;
+static const HotSpotID kTSA0BNorthMonitorSpotID = 5025;
+static const HotSpotID kTSA0BNorthMonitorOutSpotID = 5026;
+static const HotSpotID kTSA0BNorthHistLogSpotID = 5027;
+static const HotSpotID kTSA0BNorthRobotsToCommandCenterSpotID = 5028;
+static const HotSpotID kTSA0BNorthRobotsToReadyRoomSpotID = 5029;
+static const HotSpotID kTSA0BNorthRobotsToFrontDoorSpotID = 5030;
+static const HotSpotID kTSA0BWestMonitorSpotID = 5031;
+static const HotSpotID kTSA0BWestMonitorOutSpotID = 5032;
+static const HotSpotID kTSA0BWestTheorySpotID = 5033;
+static const HotSpotID kTSA0BWestBackgroundSpotID = 5034;
+static const HotSpotID kTSA0BWestProcedureSpotID = 5035;
+static const HotSpotID kTSA0BWestCloseVideoSpotID = 5036;
+static const HotSpotID kTSA0BWestPlayVideoSpotID = 5037;
+static const HotSpotID kTSA0BWestRewindVideoSpotID = 5038;
+static const HotSpotID kTSA22EastMonitorSpotID = 5039;
+static const HotSpotID kTSA22EastKeySpotID = 5040;
+static const HotSpotID kTSA23WestMonitorSpotID = 5041;
+static const HotSpotID kTSA23WestChipsSpotID = 5042;
+static const HotSpotID kTSA34NorthDoorSpotID = 5043;
+static const HotSpotID kTSA37NorthJumpToPrehistoricSpotID = 5044;
+static const HotSpotID kTSA37NorthJumpToNoradSpotID = 5045;
+static const HotSpotID kTSA37NorthCancelNoradSpotID = 5046;
+static const HotSpotID kTSA37NorthJumpToMarsSpotID = 5047;
+static const HotSpotID kTSA37NorthCancelMarsSpotID = 5048;
+static const HotSpotID kTSA37NorthJumpToWSCSpotID = 5049;
+static const HotSpotID kTSA37NorthCancelWSCSpotID = 5050;
+static const HotSpotID kTSA37NorthExitSpotID = 5051;
+static const HotSpotID kTSA37NorthJumpMenuSpotID = 5052;
+static const HotSpotID kTSA37NorthNoradMenuSpotID = 5053;
+static const HotSpotID kTSA37NorthMarsMenuSpotID = 5054;
+static const HotSpotID kTSA37NorthWSCMenuSpotID = 5055;
+
+// Extra sequence IDs.
+static const ExtraID kTSATransporterArrowLoop = 0;
+static const ExtraID kTSAArriveFromCaldoria = 1;
+static const ExtraID kTSAGTOtherChoice = 2;
+static const ExtraID kTSAGTCardSwipe = 3;
+static const ExtraID kTSAGTSelectCaldoria = 4;
+static const ExtraID kTSAGTGoToCaldoria = 5;
+static const ExtraID kTSAGTSelectBeach = 6;
+static const ExtraID kTSAGTGoToBeach = 7;
+static const ExtraID kTSAGTArriveAtBeach = 8;
+static const ExtraID kTSAGTSelectTokyo = 9;
+static const ExtraID kTSAGTGoToTokyo = 10;
+static const ExtraID kTSAGTArriveAtTokyo = 11;
+static const ExtraID kTSA02NorthZoomIn = 12;
+static const ExtraID kTSA02NorthTenSecondDoor = 13;
+static const ExtraID kTSA02NorthZoomOut = 14;
+static const ExtraID kTSA02NorthDoorWithAgent3 = 15;
+static const ExtraID kTSA03JimenezZoomIn = 16;
+static const ExtraID kTSA03JimenezSpeech = 17;
+static const ExtraID kTSA03JimenezZoomOut = 18;
+static const ExtraID kTSA03CrenshawZoomIn = 19;
+static const ExtraID kTSA03CrenshawSpeech = 20;
+static const ExtraID kTSA03CrenshawZoomOut = 21;
+static const ExtraID kTSA03SouthRobotDeath = 22;
+static const ExtraID kTSA04NorthRobotGreeting = 23;
+static const ExtraID kTSA04MatsumotoZoomIn = 24;
+static const ExtraID kTSA04MatsumotoSpeech = 25;
+static const ExtraID kTSA04MatsumotoZoomOut = 26;
+static const ExtraID kTSA04CastilleZoomIn = 27;
+static const ExtraID kTSA04CastilleSpeech = 28;
+static const ExtraID kTSA04CastilleZoomOut = 29;
+static const ExtraID kTSA05SinclairZoomIn = 30;
+static const ExtraID kTSA05SinclairSpeech = 31;
+static const ExtraID kTSA05SinclairZoomOut = 32;
+static const ExtraID kTSA05WhiteZoomIn = 33;
+static const ExtraID kTSA05WhiteSpeech = 34;
+static const ExtraID kTSA05WhiteZoomOut = 35;
+static const ExtraID kTSA0AEastRobot = 36;
+static const ExtraID kTSA0AWestRobot = 37;
+static const ExtraID kTSA16NorthRobotDeath = 38;
+static const ExtraID kTSA0BEastZoomIn = 39;
+static const ExtraID kTSA0BEastZoomedView = 40;
+static const ExtraID kTSA0BEastZoomOut = 41;
+static const ExtraID kTSA0BEastTurnLeft = 42;
+static const ExtraID kTSA0BComparisonStartup = 43;
+static const ExtraID kTSA0BComparisonView0000 = 44;
+static const ExtraID kTSA0BComparisonView0002 = 45;
+static const ExtraID kTSA0BComparisonView0020 = 46;
+static const ExtraID kTSA0BComparisonView0022 = 47;
+static const ExtraID kTSA0BComparisonView0200 = 48;
+static const ExtraID kTSA0BComparisonView0202 = 49;
+static const ExtraID kTSA0BComparisonView0220 = 50;
+static const ExtraID kTSA0BComparisonView0222 = 51;
+static const ExtraID kTSA0BComparisonView2000 = 52;
+static const ExtraID kTSA0BComparisonView2002 = 53;
+static const ExtraID kTSA0BComparisonView2020 = 54;
+static const ExtraID kTSA0BComparisonView2022 = 55;
+static const ExtraID kTSA0BComparisonView2200 = 56;
+static const ExtraID kTSA0BComparisonView2202 = 57;
+static const ExtraID kTSA0BComparisonView2220 = 58;
+static const ExtraID kTSA0BComparisonView2222 = 59;
+static const ExtraID kTSA0BNoradComparisonView = 60;
+static const ExtraID kTSA0BNoradUnaltered = 61;
+static const ExtraID kTSA0BNoradAltered = 62;
+static const ExtraID kTSA0BMarsComparisonView = 63;
+static const ExtraID kTSA0BMarsUnaltered = 64;
+static const ExtraID kTSA0BMarsAltered = 65;
+static const ExtraID kTSA0BWSCComparisonView = 66;
+static const ExtraID kTSA0BWSCUnaltered = 67;
+static const ExtraID kTSA0BWSCAltered = 68;
+static const ExtraID kTSA0BCaldoriaComparisonView = 69;
+static const ExtraID kTSA0BCaldoriaUnaltered = 70;
+static const ExtraID kTSA0BCaldoriaAltered = 71;
+static const ExtraID kTSA0BNorthZoomIn = 72;
+static const ExtraID kTSA0BNorthZoomedView = 73;
+static const ExtraID kTSA0BNorthZoomOut = 74;
+static const ExtraID kTSA0BNorthTurnLeft = 75;
+static const ExtraID kTSA0BNorthTurnRight = 76;
+static const ExtraID kTSA0BNorthHistLogOpen = 77;
+static const ExtraID kTSA0BNorthHistLogClose = 78;
+static const ExtraID kTSA0BNorthHistLogCloseWithLog = 79;
+static const ExtraID kTSA0BNorthCantChangeHistory = 80;
+static const ExtraID kTSA0BNorthYoureBusted = 81;
+static const ExtraID kTSA0BNorthFinallyHappened = 82;
+static const ExtraID kTSA0BShowRip1 = 83;
+static const ExtraID kTSA0BNorthRipView1 = 84;
+static const ExtraID kTSA0BShowRip2 = 85;
+static const ExtraID kTSA0BShowGuardRobots = 86;
+static const ExtraID kTSA0BAIInterruption = 87;
+static const ExtraID kTSA0BRobotsToCommandCenter = 88;
+static const ExtraID kTSA0BNorthRobotsAtCCView = 89;
+static const ExtraID kTSA0BNorthRobotsAtRRView = 90;
+static const ExtraID kTSA0BNorthRobotsAtFDView = 91;
+static const ExtraID kTSA0BRobotsFromCommandCenterToReadyRoom = 92;
+static const ExtraID kTSA0BRobotsFromReadyRoomToCommandCenter = 93;
+static const ExtraID kTSA0BRobotsFromCommandCenterToFrontDoor = 94;
+static const ExtraID kTSA0BRobotsFromFrontDoorToCommandCenter = 95;
+static const ExtraID kTSA0BRobotsFromFrontDoorToReadyRoom = 96;
+static const ExtraID kTSA0BRobotsFromReadyRoomToFrontDoor = 97;
+static const ExtraID kTSA0BWestZoomIn = 98;
+static const ExtraID kTSA0BWestZoomedView = 99;
+static const ExtraID kTSA0BWestZoomOut = 100;
+static const ExtraID kTSA0BWestTurnRight = 101;
+static const ExtraID kTSA0BTBPTheoryHighlight = 102;
+static const ExtraID kTSA0BTBPBackgroundHighlight = 103;
+static const ExtraID kTSA0BTBPProcedureHighlight = 104;
+static const ExtraID kTSA0BTBPTheory = 105;
+static const ExtraID kTSA0BTBPBackground = 106;
+static const ExtraID kTSA0BTBPProcedure = 107;
+static const ExtraID kTSA0BRipAlarmScreen = 108;
+static const ExtraID kTSA22RedEastZoomInSequence = 109;
+static const ExtraID kTSA22RedEastVaultViewWithKey = 110;
+static const ExtraID kTSA22RedEastVaultViewNoKey = 111;
+static const ExtraID kTSA23RedWestVaultZoomInSequence = 112;
+static const ExtraID kTSA23RedWestVaultViewWithChips = 113;
+static const ExtraID kTSA23RedWestVaultViewNoChips = 114;
+static const ExtraID kTSA25NorthDeniedNoKey = 115;
+static const ExtraID kTSA25NorthDeniedNoChip = 116;
+static const ExtraID kTSA25NorthPutOnSuit = 117;
+static const ExtraID kTSA25NorthAlreadyHaveSuit = 118;
+static const ExtraID kTSA25NorthDescending1 = 119;
+static const ExtraID kTSA25NorthDescending2 = 120;
+static const ExtraID kTSA37HorseToAI1 = 121;
+static const ExtraID kTSA37PegasusAI1 = 122;
+static const ExtraID kTSA37AI1ToCommissioner1 = 123;
+static const ExtraID kTSA37Commissioner1 = 124;
+static const ExtraID kTSA37Commissioner1ToZoom = 125;
+static const ExtraID kTSA37ZoomToPrehistoric = 126;
+static const ExtraID kTSA37PrehistoricToAI2 = 127;
+static const ExtraID kTSA37PegasusAI2 = 128;
+static const ExtraID kTSA37AI2ToPrehistoric = 129;
+static const ExtraID kTSA37PrehistoricToDepart = 130;
+static const ExtraID kTSA37PegasusDepart = 131;
+static const ExtraID kTSA37TimeJumpToPegasus = 132;
+static const ExtraID kTSA37RecallToDownload = 133;
+static const ExtraID kTSA37DownloadToColonel1 = 134;
+static const ExtraID kTSA37Colonel1 = 135;
+static const ExtraID kTSA37Colonel1ToReviewRequired = 136;
+static const ExtraID kTSA37ReviewRequiredToExit = 137;
+static const ExtraID kTSA37ExitHilited = 138;
+static const ExtraID kTSA37ExitToHorse = 139;
+static const ExtraID kTSA37HorseToColonel2 = 140;
+static const ExtraID kTSA37Colonel2 = 141;
+static const ExtraID kTSA37PegasusAI3 = 142;
+static const ExtraID kTSA37AI3ToHorse = 143;
+static const ExtraID kTSA37HorseToZoom = 144;
+static const ExtraID kTSA37ZoomToMainMenu = 145;
+static const ExtraID kTSA37MainMenuToAI4 = 146;
+static const ExtraID kTSA37PegasusAI4 = 147;
+static const ExtraID kTSA37AI4ToMainMenu = 148;
+static const ExtraID kTSA37JumpMenu000 = 149;
+static const ExtraID kTSA37JumpMenu001 = 150;
+static const ExtraID kTSA37JumpMenu010 = 151;
+static const ExtraID kTSA37JumpMenu011 = 152;
+static const ExtraID kTSA37JumpMenu100 = 153;
+static const ExtraID kTSA37JumpMenu101 = 154;
+static const ExtraID kTSA37JumpMenu110 = 155;
+static const ExtraID kTSA37JumpMenu111 = 156;
+static const ExtraID kTSA37JumpToWSCMenu = 157;
+static const ExtraID kTSA37CancelWSC = 158;
+static const ExtraID kTSA37JumpToWSC = 159;
+static const ExtraID kTSA37WSCToAI5 = 160;
+static const ExtraID kTSA37PegasusAI5 = 161;
+static const ExtraID kTSA37AI5ToWSC = 162;
+static const ExtraID kTSA37WSCToDepart = 163;
+static const ExtraID kTSA37JumpToMarsMenu = 164;
+static const ExtraID kTSA37CancelMars = 165;
+static const ExtraID kTSA37JumpToMars = 166;
+static const ExtraID kTSA37MarsToAI6 = 167;
+static const ExtraID kTSA37PegasusAI6 = 168;
+static const ExtraID kTSA37AI6ToMars = 169;
+static const ExtraID kTSA37MarsToDepart = 170;
+static const ExtraID kTSA37JumpToNoradMenu = 171;
+static const ExtraID kTSA37CancelNorad = 172;
+static const ExtraID kTSA37JumpToNorad = 173;
+static const ExtraID kTSA37NoradToAI7 = 174;
+static const ExtraID kTSA37PegasusAI7 = 175;
+static const ExtraID kTSA37AI7ToNorad = 176;
+static const ExtraID kTSA37NoradToDepart = 177;
+static const ExtraID kTSA37EnvironmentalScan = 178;
+static const ExtraID kTSA37DownloadToMainMenu = 179;
+static const ExtraID kTSA37DownloadToOpMemReview = 180;
+static const ExtraID kTSA37OpMemReviewToMainMenu = 181;
+static const ExtraID kTSA37OpMemReviewToAllClear = 182;
+static const ExtraID kTSA37AllClearToCongratulations = 183;
+static const ExtraID kTSA37Congratulations = 184;
+static const ExtraID kTSA37CongratulationsToExit = 185;
+
+const DisplayOrder kRipTimerOrder = kMonitorLayer;
+
+
+const CoordType kUnresolvedLeft = kNavAreaLeft + 14;
+const CoordType kUnresolvedTop = kNavAreaTop + 236;
+
+const CoordType kResolvedLeft = kNavAreaLeft + 36;
+const CoordType kResolvedTop = kNavAreaTop + 236;
+
+const CoordType kJumpMenuLeft = kNavAreaLeft + 360;
+const CoordType kJumpMenuTop = kNavAreaTop + 202;
+
+const CoordType kJumpMenuHilitedLeft = kNavAreaLeft + 354;
+const CoordType kJumpMenuHilitedTop = kNavAreaTop + 196;
+
+const CoordType kExitLeft = kNavAreaLeft + 360;
+const CoordType kExitTop = kNavAreaTop + 216;
+
+const CoordType kExitHilitedLeft = kNavAreaLeft + 354;
+const CoordType kExitHilitedTop = kNavAreaTop + 210;
+
+const CoordType kRipTimerLeft = kNavAreaLeft + 95;
+const CoordType kRipTimerTop = kNavAreaTop + 87;
+
+const CoordType kTBPCloseLeft = kNavAreaLeft + 30;
+const CoordType kTBPCloseTop = kNavAreaTop + 16;
+
+const CoordType kTBPRewindLeft = kNavAreaLeft + 86;
+const CoordType kTBPRewindTop = kNavAreaTop + 218;
+
+const CoordType kComparisonCloseLeft = kNavAreaLeft + 50;
+const CoordType kComparisonCloseTop = kNavAreaTop + 14;
+
+const CoordType kComparisonLeftRewindLeft = kNavAreaLeft + 96;
+const CoordType kComparisonLeftRewindTop = kNavAreaTop + 190;
+
+const CoordType kComparisonRightRewindLeft = kNavAreaLeft + 282;
+const CoordType kComparisonRightRewindTop = kNavAreaTop + 190;
+
+const CoordType kComparisonHiliteSpriteLeft = kNavAreaLeft + 45;
+const CoordType kComparisonHiliteSpriteTop = kNavAreaTop + 65;
+
+const CoordType kComparisonHiliteNoradLeft = kNavAreaLeft + 45;
+const CoordType kComparisonHiliteNoradTop = kNavAreaTop + 65;
+
+const CoordType kComparisonHiliteMarsLeft = kNavAreaLeft + 45 + 4;
+const CoordType kComparisonHiliteMarsTop = kNavAreaTop + 65 + 23;
+
+const CoordType kComparisonHiliteCaldoriaLeft = kNavAreaLeft + 45 + 7;
+const CoordType kComparisonHiliteCaldoriaTop = kNavAreaTop + 65 + 46;
+
+const CoordType kComparisonHiliteWSCLeft = kNavAreaLeft + 45 + 11;
+const CoordType kComparisonHiliteWSCTop = kNavAreaTop + 65 + 68;
+
+const CoordType kComparisonChancesSpriteLeft = kNavAreaLeft + 148;
+const CoordType kComparisonChancesSpriteTop = kNavAreaTop + 162;
+
+const CoordType kComparisonChancesNoradLeft = kNavAreaLeft + 148;
+const CoordType kComparisonChancesNoradTop = kNavAreaTop + 162;
+
+const CoordType kComparisonChancesMarsLeft = kNavAreaLeft + 148;
+const CoordType kComparisonChancesMarsTop = kNavAreaTop + 162;
+
+const CoordType kComparisonChancesCaldoriaLeft = kNavAreaLeft + 148;
+const CoordType kComparisonChancesCaldoriaTop = kNavAreaTop + 162 + 1;
+
+const CoordType kComparisonChancesWSCLeft = kNavAreaLeft + 148;
+const CoordType kComparisonChancesWSCTop = kNavAreaTop + 162;
+
+const CoordType kRedirectionSprite1Left = kNavAreaLeft + 58;
+const CoordType kRedirectionSprite1Top = kNavAreaTop + 16;
+
+const CoordType kRedirectionSprite2Left = kNavAreaLeft + 36;
+const CoordType kRedirectionSprite2Top = kNavAreaTop + 166;
+
+const CoordType kRedirectionCCRolloverLeft = kNavAreaLeft + 58;
+const CoordType kRedirectionCCRolloverTop = kNavAreaTop + 16;
+
+const CoordType kRedirectionRRRolloverLeft = kNavAreaLeft + 430;
+const CoordType kRedirectionRRRolloverTop = kNavAreaTop + 30;
+
+const CoordType kRedirectionFDRolloverLeft = kNavAreaLeft + 278;
+const CoordType kRedirectionFDRolloverTop = kNavAreaTop + 160;
+
+const CoordType kRedirectionCCDoorLeft = kNavAreaLeft + 174;
+const CoordType kRedirectionCCDoorTop = kNavAreaTop + 36;
+
+const CoordType kRedirectionRRDoorLeft = kNavAreaLeft + 418;
+const CoordType kRedirectionRRDoorTop = kNavAreaTop + 32;
+
+const CoordType kRedirectionFDDoorLeft = kNavAreaLeft + 298;
+const CoordType kRedirectionFDDoorTop = kNavAreaTop + 240;
+
+const CoordType kRedirectionSecuredLeft = kNavAreaLeft + 36;
+const CoordType kRedirectionSecuredTop = kNavAreaTop + 166;
+
+const CoordType kRedirectionNewTargetLeft = kNavAreaLeft + 36;
+const CoordType kRedirectionNewTargetTop = kNavAreaTop + 166;
+
+const CoordType kRedirectionCloseLeft = kNavAreaLeft + 56;
+const CoordType kRedirectionCloseTop = kNavAreaTop + 220;
+
+static const TimeValue kTSABumpIntoWallIn = 0;
+static const TimeValue kTSABumpIntoWallOut = 148;
+
+static const TimeValue kTSAGTDoorCloseIn = 148;
+static const TimeValue kTSAGTDoorCloseOut = 1570;
+
+static const TimeValue kTSANoOtherDestinationIn = 1570;
+static const TimeValue kTSANoOtherDestinationOut = 3601;
+
+static const TimeValue kTSAEntryDoorCloseIn = 3601;
+static const TimeValue kTSAEntryDoorCloseOut = 4200;
+
+static const TimeValue kTSAInsideDoorCloseIn = 4200;
+static const TimeValue kTSAInsideDoorCloseOut = 4800;
+
+static const TimeValue kTSAVaultCloseIn = 4800;
+static const TimeValue kTSAVaultCloseOut = 5388;
+
+static const TimeValue kTSAPegasusDoorCloseIn = 5388;
+static const TimeValue kTSAPegasusDoorCloseOut = 6457;
+
+static const bool kPegasusUnresolved = false;
+static const bool kPegasusResolved = true;
+static const bool kPegasusCantExit = false;
+static const bool kPegasusCanExit = true;
+
+// Monitor modes
+enum {
+ kMonitorNeutral = 0,
+ kMonitorTheory = 1,
+ kMonitorProcedure = 2,
+ kMonitorBackground = 3,
+ kMonitorNoradComparison = 4,
+ kMonitorMarsComparison = 5,
+ kMonitorCaldoriaComparison = 6,
+ kMonitorWSCComparison = 7,
+
+ kRawModeMask = 0x0F,
+ kPlayingTBPMask = 0x10,
+ kPlayingLeftComparisonMask = 0x20,
+ kPlayingRightComparisonMask = 0x40,
+
+ kPlayingAnyMask = kPlayingTBPMask |
+ kPlayingLeftComparisonMask |
+ kPlayingRightComparisonMask,
+
+ kMonitorPlayingTheory = kMonitorTheory | kPlayingTBPMask,
+ kMonitorPlayingProcedure = kMonitorProcedure | kPlayingTBPMask,
+ kMonitorPlayingBackground = kMonitorBackground | kPlayingTBPMask,
+
+ kMonitorPlayingLeftNoradComparison = kMonitorNoradComparison |
+ kPlayingLeftComparisonMask,
+ kMonitorPlayingRightNoradComparison = kMonitorNoradComparison |
+ kPlayingRightComparisonMask,
+ kMonitorPlayingLeftMarsComparison = kMonitorMarsComparison |
+ kPlayingLeftComparisonMask,
+ kMonitorPlayingRightMarsComparison = kMonitorMarsComparison |
+ kPlayingRightComparisonMask,
+ kMonitorPlayingLeftCaldoriaComparison = kMonitorCaldoriaComparison |
+ kPlayingLeftComparisonMask,
+ kMonitorPlayingRightCaldoriaComparison = kMonitorCaldoriaComparison |
+ kPlayingRightComparisonMask,
+ kMonitorPlayingLeftWSCComparison = kMonitorWSCComparison |
+ kPlayingLeftComparisonMask,
+ kMonitorPlayingRightWSCComparison = kMonitorWSCComparison |
+ kPlayingRightComparisonMask
+};
+
+static const ExtraID s_historicalLogViews[16] = {
+ kTSA0BComparisonView0000,
+ kTSA0BComparisonView0002,
+ kTSA0BComparisonView0020,
+ kTSA0BComparisonView0022,
+ kTSA0BComparisonView0200,
+ kTSA0BComparisonView0202,
+ kTSA0BComparisonView0220,
+ kTSA0BComparisonView0222,
+ kTSA0BComparisonView2000,
+ kTSA0BComparisonView2002,
+ kTSA0BComparisonView2020,
+ kTSA0BComparisonView2022,
+ kTSA0BComparisonView2200,
+ kTSA0BComparisonView2202,
+ kTSA0BComparisonView2220,
+ kTSA0BComparisonView2222
+};
+
+static const int kRedirectionCCRolloverSprite = 0;
+static const int kRedirectionRRRolloverSprite = 1;
+static const int kRedirectionFDRolloverSprite = 2;
+static const int kRedirectionCCDoorSprite = 3;
+static const int kRedirectionRRDoorSprite = 4;
+static const int kRedirectionFDDoorSprite = 5;
+static const int kRedirectionCloseSprite = 6;
+static const int kRedirectionSecuredSprite = 0;
+static const int kRedirectionNewTargetSprite = 1;
+
+void RipTimer::initImage() {
+ _middle = -1;
+
+ _timerImage.getImageFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kLeftRipPICTID);
+
+ Common::Rect r;
+ _timerImage.getSurfaceBounds(r);
+ setBounds(r);
+}
+
+void RipTimer::releaseImage() {
+ _timerImage.deallocateSurface();
+}
+
+void RipTimer::draw(const Common::Rect &updateRect) {
+ Common::Rect bounds;
+ getBounds(bounds);
+
+ Common::Rect r1 = bounds;
+ r1.right = _middle;
+ r1 = updateRect.findIntersectingRect(r1);
+
+ if (!r1.isEmpty()) {
+ Common::Rect r2 = r1;
+ r2.moveTo(r1.left - _bounds.left, r1.top - bounds.top);
+ _timerImage.copyToCurrentPort(r2, r1);
+ }
+}
+
+void RipTimer::timeChanged(const TimeValue newTime) {
+ Common::Rect bounds;
+ getBounds(bounds);
+
+ CoordType newMiddle = bounds.left + bounds.width() * newTime / getDuration();
+
+ if (newMiddle != _middle) {
+ _middle = newMiddle;
+ triggerRedraw();
+ }
+
+ if (newTime == getStop())
+ ((PegasusEngine *)g_engine)->die(kDeathUncreatedInTSA);
+}
+
+FullTSA::FullTSA(InputHandler *nextHandler, PegasusEngine *owner) : Neighborhood(nextHandler, owner, "Full TSA", kFullTSAID),
+ _ripTimer(kNoDisplayElement), _sprite1(kNoDisplayElement), _sprite2(kNoDisplayElement), _sprite3(kNoDisplayElement) {
+ setIsItemTaken(kJourneymanKey);
+ setIsItemTaken(kPegasusBiochip);
+ setIsItemTaken(kMapBiochip);
+}
+
+void FullTSA::init() {
+ Neighborhood::init();
+ _ripTimer.setDisplayOrder(kRipTimerOrder);
+ _ripTimer.startDisplaying();
+
+ if (!GameState.getTSASeenRobotGreeting())
+ forceStridingStop(kTSA03, kNorth, kNoAlternateID);
+
+ _sprite1.setDisplayOrder(kMonitorLayer);
+ _sprite1.startDisplaying();
+ _sprite2.setDisplayOrder(kMonitorLayer);
+ _sprite2.startDisplaying();
+ _sprite3.setDisplayOrder(kMonitorLayer);
+ _sprite3.startDisplaying();
+
+ // Fix a mistake in the world builder tables.
+ HotspotInfoTable::Entry *entry = findHotspotEntry(kTSA23WestChipsSpotID);
+ entry->hotspotItem = kPegasusBiochip;
+}
+
+void FullTSA::dieUncreatedInTSA() {
+ die(kDeathUncreatedInTSA);
+}
+
+void FullTSA::start() {
+ g_energyMonitor->stopEnergyDraining();
+
+ if (!GameState.getScoringEnterTSA()) {
+ _utilityFuse.primeFuse(GameState.getTSAFuseTimeLimit());
+ _utilityFuse.setFunctor(new Common::Functor0Mem<void, FullTSA>(this, &FullTSA::dieUncreatedInTSA));
+ _utilityFuse.lightFuse();
+ } else if (GameState.getTSAState() == kTSAPlayerDetectedRip || GameState.getTSAState() == kTSAPlayerNeedsHistoricalLog) {
+ _ripTimer.initImage();
+ _ripTimer.moveElementTo(kRipTimerLeft, kRipTimerTop);
+ _ripTimer.setSegment(0, kRipTimeLimit, kRipTimeScale);
+ _ripTimer.setTime(GameState.getRipTimerTime());
+ _ripTimer.start();
+ }
+
+ Neighborhood::start();
+}
+
+void FullTSA::flushGameState() {
+ GameState.setRipTimerTime(_ripTimer.getTime());
+ GameState.setTSAFuseTimeLimit(_utilityFuse.getTimeRemaining());
+}
+
+Common::String FullTSA::getBriefingMovie() {
+ Common::String movieName = Neighborhood::getBriefingMovie();
+
+ if (movieName.empty()) {
+ RoomID room = GameState.getCurrentRoom();
+
+ switch (GameState.getTSAState()) {
+ case kTSAPlayerNotArrived:
+ case kTSAPlayerForcedReview:
+ if (room >= kTSA16 && room <= kTSA0B)
+ return "Images/AI/TSA/XT01A";
+
+ return "Images/AI/TSA/XT01";
+ case kTSAPlayerDetectedRip:
+ case kTSAPlayerNeedsHistoricalLog:
+ return "Images/AI/TSA/XT02";
+ case kTSAPlayerGotHistoricalLog:
+ case kTSAPlayerInstalledHistoricalLog:
+ return "Images/AI/TSA/XT03";
+ default:
+ switch (getCurrentActivation()) {
+ case kActivationJumpToPrehistoric:
+ g_AIChip->showBriefingClicked();
+ startExtraSequenceSync(kTSA37PegasusAI2, kHintInterruption);
+ startExtraSequenceSync(kTSA37AI2ToPrehistoric, kFilterNoInput);
+ g_AIChip->clearClicked();
+ break;
+ case kActivationJumpToNorad:
+ g_AIChip->showBriefingClicked();
+ startExtraSequenceSync(kTSA37PegasusAI7, kHintInterruption);
+ startExtraSequenceSync(kTSA37AI7ToNorad, kFilterNoInput);
+ g_AIChip->clearClicked();
+ break;
+ case kActivationJumpToMars:
+ g_AIChip->showBriefingClicked();
+ startExtraSequenceSync(kTSA37PegasusAI6, kHintInterruption);
+ startExtraSequenceSync(kTSA37AI6ToMars, kFilterNoInput);
+ g_AIChip->clearClicked();
+ break;
+ case kActivationJumpToWSC:
+ g_AIChip->showBriefingClicked();
+ startExtraSequenceSync(kTSA37PegasusAI5, kHintInterruption);
+ startExtraSequenceSync(kTSA37AI5ToWSC, kFilterNoInput);
+ g_AIChip->clearClicked();
+ break;
+ default:
+ if (GameState.allTimeZonesFinished())
+ return "Images/AI/TSA/XT05";
+
+ return "Images/AI/TSA/XT04";
+ }
+ break;
+ }
+ }
+
+ return movieName;
+}
+
+Common::String FullTSA::getEnvScanMovie() {
+ Common::String movieName = Neighborhood::getEnvScanMovie();
+
+ if (movieName.empty()) {
+ switch (GameState.getTSAState()) {
+ case kTSAPlayerNotArrived:
+ case kTSAPlayerForcedReview:
+ case kTSAPlayerDetectedRip:
+ case kTSAPlayerNeedsHistoricalLog:
+ return "Images/AI/TSA/XTE1";
+ default:
+ if (GameState.getCurrentRoom() == kTSA37) {
+ g_AIChip->showEnvScanClicked();
+ startExtraSequenceSync(kTSA37EnvironmentalScan, kHintInterruption);
+
+ switch (getCurrentActivation()) {
+ case kActivationJumpToPrehistoric:
+ startExtraSequenceSync(kTSA37AI2ToPrehistoric, kFilterNoInput);
+ break;
+ case kActivationJumpToNorad:
+ startExtraSequenceSync(kTSA37AI7ToNorad, kFilterNoInput);
+ showExtraView(kTSA37JumpToNoradMenu);
+ break;
+ case kActivationJumpToMars:
+ startExtraSequenceSync(kTSA37AI6ToMars, kFilterNoInput);
+ showExtraView(kTSA37JumpToMarsMenu);
+ break;
+ case kActivationJumpToWSC:
+ startExtraSequenceSync(kTSA37AI5ToWSC, kFilterNoInput);
+ showExtraView(kTSA37JumpToWSCMenu);
+ break;
+ default:
+ startExtraSequenceSync(kTSA37AI4ToMainMenu, kFilterNoInput);
+ break;
+ }
+
+ g_AIChip->clearClicked();
+ } else if (GameState.allTimeZonesFinished()) {
+ return "Images/AI/TSA/XTE1";
+ } else {
+ return "Images/AI/TSA/XTE2";
+ }
+ break;
+ }
+ }
+
+ return movieName;
+}
+
+uint FullTSA::getNumHints() {
+ uint numHints = Neighborhood::getNumHints();
+
+ if (numHints == 0) {
+ switch (GameState.getTSAState()) {
+ case kRobotsAtCommandCenter:
+ case kRobotsAtFrontDoor:
+ case kRobotsAtReadyRoom:
+ if (GameState.getCurrentRoom() == kTSA0B && GameState.getTSA0BZoomedIn())
+ numHints = 3;
+ break;
+ }
+ }
+
+ return numHints;
+}
+
+Common::String FullTSA::getHintMovie(uint hintNum) {
+ Common::String movieName = Neighborhood::getHintMovie(hintNum);
+
+ if (movieName.empty())
+ movieName = Common::String::format("Images/AI/TSA/XT20NH%d", hintNum);
+
+ return movieName;
+}
+
+void FullTSA::loadAmbientLoops() {
+ RoomID room = GameState.getCurrentRoom();
+
+ switch (GameState.getTSAState()) {
+ case kTSAPlayerDetectedRip:
+ case kTSAPlayerNeedsHistoricalLog:
+ if ((room >= kTSA16 && room <= kTSA0B) || (room >= kTSA21Cyan && room <= kTSA24Cyan) || (room >= kTSA21Red && room <= kTSA24Red))
+ loadLoopSound1("Sounds/TSA/TSA CLAXON.22K.AIFF", 0x100 / 4, 0, 0);
+ else if (room == kTSA25Cyan || room == kTSA25Red)
+ loadLoopSound1("Sounds/TSA/TSA CLAXON.22K.AIFF", 0x100 / 6, 0, 0);
+ else
+ loadLoopSound1("Sounds/TSA/TSA EchoClaxon.22K.AIFF", 0x100 / 4, 0, 0);
+ break;
+ default:
+ if (room >= kTSA00 && room <= kTSA02)
+ loadLoopSound1("Sounds/TSA/T01NAE.NEW.22K.AIFF");
+ else if (room >= kTSA03 && room <= kTSA15)
+ loadLoopSound1("Sounds/TSA/T01NAE.NEW.22K.AIFF");
+ else if (room >= kTSA16 && room <= kTSA0B)
+ loadLoopSound1("Sounds/TSA/T14SAEO1.22K.AIFF");
+ else if (room >= kTSA21Cyan && room <= kTSA25Red)
+ loadLoopSound1("Sounds/TSA/T15SAE01.22K.AIFF");
+ else if (room >= kTSA26 && room <= kTSA37)
+ loadLoopSound1("Sounds/TSA/T01NAE.NEW.22K.AIFF");
+ break;
+ }
+}
+
+short FullTSA::getStaticCompassAngle(const RoomID room, const DirectionConstant dir) {
+ int16 result = Neighborhood::getStaticCompassAngle(room, dir);
+
+ switch (room) {
+ case kTSA08:
+ result += kCompassShift;
+ break;
+ case kTSA09:
+ result -= kCompassShift;
+ break;
+ case kTSA10:
+ result += kCompassShift * 2;
+ break;
+ case kTSA11:
+ case kTSA22Cyan:
+ case kTSA22Red:
+ result -= kCompassShift * 2;
+ break;
+ case kTSA12:
+ result += kCompassShift * 3;
+ break;
+ case kTSA13:
+ result -= kCompassShift * 3;
+ break;
+ case kTSA14:
+ case kTSA16:
+ case kTSA17:
+ case kTSA18:
+ case kTSA19:
+ result += kCompassShift * 4;
+ break;
+ case kTSA0B:
+ result += kCompassShift * 4;
+
+ if (dir == kWest)
+ result += 30;
+ else if (dir == kEast)
+ result -= 30;
+ break;
+ case kTSA33:
+ result += kCompassShift * 4;
+ break;
+ case kTSA15:
+ case kTSA21Cyan:
+ case kTSA24Cyan:
+ case kTSA25Cyan:
+ case kTSA21Red:
+ case kTSA24Red:
+ case kTSA25Red:
+ case kTSA26:
+ case kTSA27:
+ case kTSA28:
+ case kTSA29:
+ case kTSA30:
+ result -= kCompassShift * 4;
+ break;
+ case kTSA23Cyan:
+ case kTSA23Red:
+ result -= kCompassShift * 6;
+ break;
+ case kTSA32:
+ result -= kCompassShift * 8;
+ break;
+ case kTSA34:
+ result -= kCompassShift * 12;
+ break;
+ case kTSA35:
+ result += kCompassShift * 8;
+ break;
+ case kTSA37:
+ result -= kCompassShift * 2;
+ break;
+ }
+
+ return result;
+}
+
+void FullTSA::getExitCompassMove(const ExitTable::Entry &exitEntry, FaderMoveSpec &compassMove) {
+ Neighborhood::getExitCompassMove(exitEntry, compassMove);
+
+ switch (MakeRoomView(exitEntry.room, exitEntry.direction)) {
+ case MakeRoomView(kTSA01, kSouth):
+ compassMove.insertFaderKnot(exitEntry.movieStart, -180);
+ compassMove.insertFaderKnot(exitEntry.movieStart + kFullTSAFrameDuration * 3, -180);
+ compassMove.insertFaderKnot(exitEntry.movieStart + kFullTSAFrameDuration * 33,
+ getStaticCompassAngle(exitEntry.exitRoom, exitEntry.exitDirection));
+ break;
+ case MakeRoomView(kTSA11, kEast):
+ if (getCurrentAlternate() == kAltTSARobotsAtReadyRoom) {
+ compassMove.makeTwoKnotFaderSpec(kFullTSAMovieScale, exitEntry.movieStart,
+ getStaticCompassAngle(kTSA11, kEast), exitEntry.movieEnd,
+ getStaticCompassAngle(kTSA13, kEast));
+ compassMove.insertFaderKnot(exitEntry.movieStart + kFullTSAFrameDuration * 13, compassMove.getNthKnotValue(1));
+ }
+ break;
+ case MakeRoomView(kTSA34, kNorth):
+ compassMove.insertFaderKnot(exitEntry.movieStart + kFullTSAFrameDuration * 48,
+ getStaticCompassAngle(exitEntry.room, exitEntry.direction));
+ compassMove.insertFaderKnot(exitEntry.movieStart + kFullTSAFrameDuration * 68,
+ getStaticCompassAngle(exitEntry.exitRoom, exitEntry.exitDirection));
+ break;
+ case MakeRoomView(kTSA37, kNorth):
+ compassMove.insertFaderKnot(exitEntry.movieStart + kFullTSAFrameDuration * 38,
+ getStaticCompassAngle(exitEntry.room, exitEntry.direction));
+ compassMove.insertFaderKnot(exitEntry.movieStart + kFullTSAFrameDuration * 64,
+ getStaticCompassAngle(exitEntry.room, exitEntry.direction) + kCompassShift * 3 / 2);
+ compassMove.insertFaderKnot(exitEntry.movieStart + kFullTSAFrameDuration * 105,
+ getStaticCompassAngle(exitEntry.exitRoom, exitEntry.exitDirection));
+ break;
+ }
+}
+
+void FullTSA::getExtraCompassMove(const ExtraTable::Entry &extraEntry, FaderMoveSpec &compassMove) {
+ int16 angle;
+
+ switch (extraEntry.extra) {
+ case kTSA0BEastTurnLeft:
+ case kTSA0BNorthTurnLeft:
+ angle =getStaticCompassAngle(GameState.getCurrentRoom(), GameState.getCurrentDirection());
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), extraEntry.movieStart, angle,
+ extraEntry.movieEnd, angle - 60);
+ break;
+ case kTSA0BNorthTurnRight:
+ case kTSA0BWestTurnRight:
+ angle = getStaticCompassAngle(GameState.getCurrentRoom(), GameState.getCurrentDirection());
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), extraEntry.movieStart, angle,
+ extraEntry.movieEnd, angle + 60);
+ break;
+ case kTSA22RedEastZoomInSequence:
+ angle = getStaticCompassAngle(GameState.getCurrentRoom(), GameState.getCurrentDirection());
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), extraEntry.movieStart, angle,
+ extraEntry.movieEnd, angle);
+ compassMove.insertFaderKnot(extraEntry.movieStart + 1200, angle - kCompassShift * 2);
+ compassMove.insertFaderKnot(extraEntry.movieStart + 8160, angle - kCompassShift * 2);
+ compassMove.insertFaderKnot(extraEntry.movieStart + 9840, angle);
+ break;
+ case kTSA23RedWestVaultZoomInSequence:
+ angle = getStaticCompassAngle(GameState.getCurrentRoom(), GameState.getCurrentDirection());
+ compassMove.makeTwoKnotFaderSpec(_navMovie.getScale(), extraEntry.movieStart, angle,
+ extraEntry.movieEnd, angle);
+ compassMove.insertFaderKnot(extraEntry.movieStart + 1200, angle - kCompassShift * 2);
+ compassMove.insertFaderKnot(extraEntry.movieStart + 10100, angle - kCompassShift * 2);
+ compassMove.insertFaderKnot(extraEntry.movieStart + 11880, angle);
+ break;
+ default:
+ Neighborhood::getExtraCompassMove(extraEntry, compassMove);
+ break;
+ }
+}
+
+uint16 FullTSA::getDateResID() const {
+ return kDate2318ID;
+}
+
+TimeValue FullTSA::getViewTime(const RoomID room, const DirectionConstant direction) {
+ ExtraID extraID = 0xffffffff;
+
+ switch (MakeRoomView(room, direction)) {
+ case MakeRoomView(kTSA0B, kEast):
+ if (GameState.getTSA0BZoomedIn())
+ switch (GameState.getTSAState()) {
+ case kTSAPlayerInstalledHistoricalLog:
+ case kTSABossSawHistoricalLog:
+ case kRobotsAtCommandCenter:
+ case kRobotsAtFrontDoor:
+ case kRobotsAtReadyRoom:
+ extraID = s_historicalLogViews[getHistoricalLogIndex()];
+ break;
+ default:
+ extraID = kTSA0BEastZoomedView;
+ break;
+ }
+ break;
+ case MakeRoomView(kTSA0B, kNorth):
+ if (GameState.getTSA0BZoomedIn())
+ switch (GameState.getTSAState()) {
+ case kTSAPlayerNeedsHistoricalLog:
+ extraID = kTSA0BNorthRipView1;
+ break;
+ default:
+ extraID = kTSA0BNorthZoomedView;
+ break;
+ }
+ break;
+ case MakeRoomView(kTSA0B, kWest):
+ if (GameState.getTSA0BZoomedIn())
+ extraID = kTSA0BWestZoomedView;
+ break;
+ case MakeRoomView(kTSA22Red, kEast):
+ if (_privateFlags.getFlag(kTSAPrivateKeyVaultOpenFlag)) {
+ if (_vm->itemInLocation(kJourneymanKey, kFullTSAID, kTSA22Red, kEast))
+ extraID = kTSA22RedEastVaultViewWithKey;
+ else
+ extraID = kTSA22RedEastVaultViewNoKey;
+ }
+ break;
+ case MakeRoomView(kTSA23Red, kWest):
+ if (_privateFlags.getFlag(kTSAPrivateChipVaultOpenFlag)) {
+ if (_vm->itemInLocation(kPegasusBiochip, kFullTSAID, kTSA23Red, kWest))
+ extraID = kTSA23RedWestVaultViewWithChips;
+ else
+ extraID = kTSA23RedWestVaultViewNoChips;
+ }
+ break;
+ case MakeRoomView(kTSA37, kNorth):
+ switch (GameState.getTSAState()) {
+ case kTSAPlayerGotHistoricalLog:
+ extraID = kTSA37ReviewRequiredToExit;
+ break;
+ case kPlayerFinishedWithTSA:
+ extraID = kTSA37CongratulationsToExit;
+ break;
+ default:
+ extraID = kTSA37AI3ToHorse;
+ break;
+ }
+ break;
+ }
+
+ if (extraID != 0xffffffff) {
+ ExtraTable::Entry entry;
+ getExtraEntry(extraID, entry);
+ return entry.movieEnd - 1;
+ }
+
+ return Neighborhood::getViewTime(room, direction);
+}
+
+void FullTSA::findSpotEntry(const RoomID room, const DirectionConstant direction, SpotFlags flags, SpotTable::Entry &entry) {
+ switch (MakeRoomView(room, direction)) {
+ case MakeRoomView(kTSA0B, kNorth):
+ case MakeRoomView(kTSA0B, kEast):
+ case MakeRoomView(kTSA0B, kWest):
+ if (!GameState.getTSA0BZoomedIn())
+ Neighborhood::findSpotEntry(room, direction, flags, entry);
+ break;
+ default:
+ Neighborhood::findSpotEntry(room, direction, flags, entry);
+ break;
+ }
+}
+
+void FullTSA::getExtraEntry(const uint32 id, ExtraTable::Entry &extraEntry) {
+ Neighborhood::getExtraEntry(id, extraEntry);
+
+ if (id == kTSA0BShowGuardRobots)
+ extraEntry.movieStart += kFullTSAFrameDuration * 3;
+}
+
+void FullTSA::pickedUpItem(Item *item) {
+ BiochipItem *biochip;
+
+ switch (item->getObjectID()) {
+ case kJourneymanKey:
+ GameState.setScoringGotJourneymanKey(true);
+ break;
+ case kPegasusBiochip:
+ biochip = (BiochipItem *)_vm->getAllItems().findItemByID(kMapBiochip);
+ _vm->addItemToBiochips(biochip);
+ GameState.setScoringGotPegasusBiochip(true);
+ break;
+ }
+}
+
+void FullTSA::playExtraMovie(const ExtraTable::Entry &extraEntry, const NotificationFlags flags, const InputBits interruptionInput) {
+ switch (extraEntry.extra) {
+ case kTSA0BNorthZoomIn:
+ if (_privateFlags.getFlag(kTSAPrivateLogReaderOpenFlag)) {
+ _privateFlags.setFlag(kTSAPrivateLogReaderOpenFlag, false);
+ requestExtraSequence(kTSA0BNorthHistLogClose, 0, kFilterNoInput);
+ requestExtraSequence(kTSA0BNorthZoomIn, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ Neighborhood::playExtraMovie(extraEntry, flags, interruptionInput);
+ }
+ break;
+ case kTSA0BNorthZoomOut:
+ if (_ripTimer.isVisible())
+ _ripTimer.hide();
+
+ shutDownRobotMonitor();
+ Neighborhood::playExtraMovie(extraEntry, flags, interruptionInput);
+ break;
+ case kTSA0BEastZoomOut:
+ shutDownComparisonMonitor();
+ Neighborhood::playExtraMovie(extraEntry, flags, interruptionInput);
+ break;
+ default:
+ Neighborhood::playExtraMovie(extraEntry, flags, interruptionInput);
+ break;
+ }
+}
+
+void FullTSA::startDoorOpenMovie(const TimeValue startTime, const TimeValue stopTime) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kTSA00, kNorth):
+ if (GameState.getLastNeighborhood() != kFullTSAID) {
+ startExtraSequence(kTSAArriveFromCaldoria, kDoorOpenCompletedFlag, kFilterNoInput);
+ return;
+ }
+ break;
+ case MakeRoomView(kTSA02, kNorth):
+ if (!GameState.getTSAIDedAtDoor()) {
+ GameState.setTSAIDedAtDoor(true);
+ requestExtraSequence(kTSA02NorthZoomIn, 0, kFilterNoInput);
+ requestExtraSequence(kTSA02NorthTenSecondDoor, 0, kFilterNoInput);
+
+ if (GameState.getTSASeenAgent3AtDoor()) {
+ requestExtraSequence(kTSA02NorthZoomOut, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ GameState.setTSASeenAgent3AtDoor(true);
+ requestExtraSequence(kTSA02NorthZoomOut, 0, kFilterNoInput);
+ requestExtraSequence(kTSA02NorthDoorWithAgent3, kDoorOpenCompletedFlag, kFilterNoInput);
+ }
+ return;
+ }
+ break;
+ case MakeRoomView(kTSA03, kSouth):
+ if (GameState.getTSAState() == kRobotsAtFrontDoor) {
+ playDeathExtra(kTSA03SouthRobotDeath, kDeathShotByTSARobots);
+ return;
+ }
+ break;
+ case MakeRoomView(kTSA16, kNorth):
+ if (GameState.getTSAState() == kRobotsAtCommandCenter) {
+ playDeathExtra(kTSA16NorthRobotDeath, kDeathShotByTSARobots);
+ return;
+ }
+ break;
+ }
+
+ Neighborhood::startDoorOpenMovie(startTime, stopTime);
+}
+
+InputBits FullTSA::getInputFilter() {
+ InputBits result = Neighborhood::getInputFilter();
+
+ switch (GameState.getCurrentRoom()) {
+ case kTSA0B:
+ if (GameState.getT0BMonitorMode() != kMonitorNeutral)
+ // Only allow a click.
+ result &= JMPPPInput::getClickInputFilter();
+ break;
+ case kTSA37:
+ // Can't move forward in Pegasus. Only press the exit button.
+ result &= ~(kFilterUpButton | kFilterUpAuto);
+ break;
+ }
+
+ return result;
+}
+
+void FullTSA::turnLeft() {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kTSA15, kNorth):
+ if (GameState.getTSAState() == kTSAPlayerNeedsHistoricalLog)
+ setCurrentAlternate(kAltTSANormal);
+ break;
+ case MakeRoomView(kTSA0B, kNorth):
+ if (_ripTimer.isVisible())
+ _ripTimer.hide();
+ releaseSprites();
+ break;
+ case MakeRoomView(kTSA0B, kEast):
+ shutDownComparisonMonitor();
+ break;
+ }
+
+ Neighborhood::turnLeft();
+}
+
+void FullTSA::turnRight() {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kTSA15, kSouth):
+ if (GameState.getTSAState() == kTSAPlayerNeedsHistoricalLog)
+ setCurrentAlternate(kAltTSANormal);
+ break;
+ case MakeRoomView(kTSA0B, kNorth):
+ if (_ripTimer.isVisible())
+ _ripTimer.hide();
+ releaseSprites();
+ break;
+ case MakeRoomView(kTSA0B, kEast):
+ shutDownComparisonMonitor();
+ break;
+ }
+
+ Neighborhood::turnRight();
+}
+
+void FullTSA::openDoor() {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kTSA15, kSouth):
+ if (GameState.getTSAState() == kTSAPlayerNeedsHistoricalLog || GameState.getTSAState() == kRobotsAtFrontDoor)
+ setCurrentAlternate(kAltTSARedAlert);
+ break;
+ }
+
+ Neighborhood::openDoor();
+}
+
+CanMoveForwardReason FullTSA::canMoveForward(ExitTable::Entry &entry) {
+ if (GameState.getCurrentRoomAndView() == MakeRoomView(kTSA25Red, kNorth))
+ return kCantMoveBlocked;
+
+ return Neighborhood::canMoveForward(entry);
+}
+
+CanOpenDoorReason FullTSA::canOpenDoor(DoorTable::Entry &entry) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kTSA02, kNorth):
+ if (!GameState.getTSAFrontDoorUnlockedOutside())
+ return kCantOpenLocked;
+ break;
+ case MakeRoomView(kTSA03, kSouth):
+ if (!GameState.getTSAFrontDoorUnlockedInside())
+ return kCantOpenLocked;
+ break;
+ case MakeRoomView(kTSA16, kNorth):
+ if (GameState.getTSACommandCenterLocked())
+ return kCantOpenLocked;
+ break;
+ }
+
+ return Neighborhood::canOpenDoor(entry);
+}
+
+void FullTSA::bumpIntoWall() {
+ requestSpotSound(kTSABumpIntoWallIn, kTSABumpIntoWallOut, kFilterAllInput, 0);
+ Neighborhood::bumpIntoWall();
+}
+
+void FullTSA::downButton(const Input &input) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kTSA0B, kEast):
+ if (GameState.getTSA0BZoomedIn())
+ startExtraSequence(kTSA0BEastZoomOut, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case MakeRoomView(kTSA0B, kNorth):
+ if (GameState.getTSA0BZoomedIn())
+ startExtraSequence(kTSA0BNorthZoomOut, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case MakeRoomView(kTSA0B, kWest):
+ if (GameState.getTSA0BZoomedIn() && GameState.getT0BMonitorMode() == kMonitorNeutral)
+ startExtraSequence(kTSA0BWestZoomOut, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ default:
+ Neighborhood::downButton(input);
+ }
+}
+
+void FullTSA::activateOneHotspot(HotspotInfoTable::Entry &entry, Hotspot *spot) {
+ switch (spot->getObjectID()) {
+ case kTSA0BEastLeftRewindSpotID:
+ case kTSA0BEastLeftPlaySpotID:
+ if (_privateFlags.getFlag(kTSAPrivatePlayingRightComparisonFlag))
+ spot->setInactive();
+ else
+ Neighborhood::activateOneHotspot(entry, spot);
+ break;
+ case kTSA0BEastRightRewindSpotID:
+ case kTSA0BEastRightPlaySpotID:
+ if (_privateFlags.getFlag(kTSAPrivatePlayingLeftComparisonFlag))
+ spot->setInactive();
+ else
+ Neighborhood::activateOneHotspot(entry, spot);
+ break;
+ default:
+ Neighborhood::activateOneHotspot(entry, spot);
+ break;
+ }
+}
+
+void FullTSA::activateHotspots() {
+ Neighborhood::activateHotspots();
+
+ switch (MakeRoomView(GameState.getCurrentRoom(), GameState.getCurrentDirection())) {
+ case MakeRoomView(kTSA02, kNorth):
+ if (!GameState.getTSAFrontDoorUnlockedOutside())
+ _vm->getAllHotspots().activateOneHotspot(kTSA02DoorSpotID);
+ break;
+ case MakeRoomView(kTSA0B, kEast):
+ if (GameState.getTSA0BZoomedIn())
+ switch (GameState.getTSAState()) {
+ case kTSAPlayerInstalledHistoricalLog:
+ case kTSABossSawHistoricalLog:
+ case kRobotsAtCommandCenter:
+ case kRobotsAtFrontDoor:
+ case kRobotsAtReadyRoom:
+ if (getCurrentActivation() != kActivateTSA0BComparisonVideo) {
+ _vm->getAllHotspots().activateOneHotspot(kTSA0BEastCompareNoradSpotID);
+ _vm->getAllHotspots().activateOneHotspot(kTSA0BEastCompareMarsSpotID);
+ _vm->getAllHotspots().activateOneHotspot(kTSA0BEastCompareCaldoriaSpotID);
+ _vm->getAllHotspots().activateOneHotspot(kTSA0BEastCompareWSCSpotID);
+ }
+ break;
+ }
+ break;
+ case MakeRoomView(kTSA0B, kNorth):
+ if (GameState.getTSA0BZoomedIn())
+ switch (GameState.getTSAState()) {
+ case kRobotsAtCommandCenter:
+ case kRobotsAtFrontDoor:
+ case kRobotsAtReadyRoom:
+ _vm->getAllHotspots().activateOneHotspot(kTSA0BNorthRobotsToCommandCenterSpotID);
+ _vm->getAllHotspots().activateOneHotspot(kTSA0BNorthRobotsToReadyRoomSpotID);
+ _vm->getAllHotspots().activateOneHotspot(kTSA0BNorthRobotsToFrontDoorSpotID);
+ break;
+ }
+ break;
+ }
+}
+
+void FullTSA::clickInHotspot(const Input &input, const Hotspot *clickedSpot) {
+ switch (clickedSpot->getObjectID()) {
+ case kTSAGTOtherSpotID:
+ showExtraView(kTSAGTOtherChoice);
+ playSpotSoundSync(kTSANoOtherDestinationIn, kTSANoOtherDestinationOut);
+ showExtraView(kTSAGTCardSwipe);
+ break;
+ case kTSA02DoorSpotID:
+ GameState.setTSAFrontDoorUnlockedOutside(true);
+ Neighborhood::clickInHotspot(input, clickedSpot);
+ break;
+ case kTSA03EastJimenezSpotID:
+ startExtraLongSequence(kTSA03JimenezZoomIn, kTSA03JimenezZoomOut, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kTSA03WestCrenshawSpotID:
+ startExtraLongSequence(kTSA03CrenshawZoomIn, kTSA03CrenshawZoomOut, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kTSA04EastMatsumotoSpotID:
+ startExtraLongSequence(kTSA04MatsumotoZoomIn, kTSA04MatsumotoZoomOut, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kTSA04WestCastilleSpotID:
+ startExtraLongSequence(kTSA04CastilleZoomIn, kTSA04CastilleZoomOut, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kTSA05EastSinclairSpotID:
+ startExtraLongSequence(kTSA05SinclairZoomIn, kTSA05SinclairZoomOut, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kTSA05WestWhiteSpotID:
+ startExtraLongSequence(kTSA05WhiteZoomIn, kTSA05WhiteZoomOut, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kTSA0BEastCompareNoradSpotID:
+ initializeComparisonMonitor(kMonitorNoradComparison, kTSA0BNoradComparisonView);
+ break;
+ case kTSA0BEastCompareMarsSpotID:
+ initializeComparisonMonitor(kMonitorMarsComparison, kTSA0BMarsComparisonView);
+ break;
+ case kTSA0BEastCompareCaldoriaSpotID:
+ initializeComparisonMonitor(kMonitorCaldoriaComparison, kTSA0BCaldoriaComparisonView);
+ break;
+ case kTSA0BEastCompareWSCSpotID:
+ initializeComparisonMonitor(kMonitorWSCComparison, kTSA0BWSCComparisonView);
+ break;
+ case kTSA0BEastCloseVideoSpotID:
+ _navMovie.stop();
+ _sprite3.show();
+ _vm->delayShell(1, 2);
+ _sprite3.hide();
+ initializeComparisonMonitor(kMonitorNeutral, 0);
+ break;
+ case kTSA0BEastLeftPlaySpotID:
+ playLeftComparison();
+ break;
+ case kTSA0BEastRightPlaySpotID:
+ playRightComparison();
+ break;
+
+ // Command center
+ case kTSA0BWestTheorySpotID:
+ initializeTBPMonitor(kMonitorTheory, kTSA0BTBPTheoryHighlight);
+ break;
+ case kTSA0BWestBackgroundSpotID:
+ initializeTBPMonitor(kMonitorBackground, kTSA0BTBPBackgroundHighlight);
+ break;
+ case kTSA0BWestProcedureSpotID:
+ initializeTBPMonitor(kMonitorProcedure, kTSA0BTBPProcedureHighlight);
+ break;
+ case kTSA0BWestCloseVideoSpotID:
+ _navMovie.stop();
+ _sprite2.show();
+ _vm->delayShell(1, 2);
+ _sprite2.hide();
+ initializeTBPMonitor(kMonitorNeutral, 0);
+ break;
+ case kTSA0BWestPlayVideoSpotID:
+ playTBPMonitor();
+ break;
+ case kTSA0BEastLeftRewindSpotID:
+ case kTSA0BEastRightRewindSpotID:
+ case kTSA0BWestRewindVideoSpotID:
+ if ((GameState.getT0BMonitorMode() & kPlayingAnyMask) != 0) {
+ bool playing = _navMovie.isRunning();
+ if (playing)
+ _navMovie.stop();
+
+ if (clickedSpot->getObjectID() == kTSA0BEastRightRewindSpotID)
+ _sprite2.show();
+ else
+ _sprite1.show();
+
+ _vm->delayShell(1, 2);
+
+ if (clickedSpot->getObjectID() == kTSA0BEastRightRewindSpotID)
+ _sprite2.hide();
+ else
+ _sprite1.hide();
+
+ _navMovie.setTime(GameState.getT0BMonitorStart());
+
+ if (playing) {
+ _navMovie.start();
+ } else {
+ _privateFlags.setFlag(kTSAPrivatePlayingLeftComparisonFlag, false);
+ _privateFlags.setFlag(kTSAPrivatePlayingRightComparisonFlag, false);
+ }
+ }
+ break;
+ case kTSA22EastMonitorSpotID:
+ requestExtraSequence(kTSA22RedEastZoomInSequence, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kTSA23WestMonitorSpotID:
+ requestExtraSequence(kTSA23RedWestVaultZoomInSequence, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kTSA0BNorthRobotsToCommandCenterSpotID:
+ _sprite1.setCurrentFrameIndex(kRedirectionCCDoorSprite);
+ _sprite1.show();
+ _vm->delayShell(1, 2);
+ _sprite1.hide();
+
+ switch (GameState.getTSAState()) {
+ case kRobotsAtCommandCenter:
+ // Nothing
+ break;
+ case kRobotsAtFrontDoor:
+ GameState.setTSAState(kRobotsAtCommandCenter);
+ _sprite2.setCurrentFrameIndex(kRedirectionNewTargetSprite);
+ startExtraSequence(kTSA0BRobotsFromFrontDoorToCommandCenter, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kRobotsAtReadyRoom:
+ GameState.setTSAState(kRobotsAtCommandCenter);
+ _sprite2.setCurrentFrameIndex(kRedirectionNewTargetSprite);
+ startExtraSequence(kTSA0BRobotsFromReadyRoomToCommandCenter, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ }
+ break;
+ case kTSA0BNorthRobotsToReadyRoomSpotID:
+ _sprite1.setCurrentFrameIndex(kRedirectionRRDoorSprite);
+ _sprite1.show();
+ _vm->delayShell(1, 2);
+ _sprite1.hide();
+
+ switch (GameState.getTSAState()) {
+ case kRobotsAtCommandCenter:
+ GameState.setTSAState(kRobotsAtReadyRoom);
+ _sprite2.setCurrentFrameIndex(kRedirectionNewTargetSprite);
+ startExtraSequence(kTSA0BRobotsFromCommandCenterToReadyRoom, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kRobotsAtFrontDoor:
+ GameState.setTSAState(kRobotsAtReadyRoom);
+ _sprite2.setCurrentFrameIndex(kRedirectionNewTargetSprite);
+ startExtraSequence(kTSA0BRobotsFromFrontDoorToReadyRoom, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kRobotsAtReadyRoom:
+ // Nothing
+ break;
+ }
+ break;
+ case kTSA0BNorthRobotsToFrontDoorSpotID:
+ _sprite1.setCurrentFrameIndex(kRedirectionFDDoorSprite);
+ _sprite1.show();
+ _vm->delayShell(1, 2);
+ _sprite1.hide();
+
+ switch (GameState.getTSAState()) {
+ case kRobotsAtCommandCenter:
+ GameState.setTSAState(kRobotsAtFrontDoor);
+ _sprite2.setCurrentFrameIndex(kRedirectionNewTargetSprite);
+ startExtraSequence(kTSA0BRobotsFromCommandCenterToFrontDoor, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kRobotsAtFrontDoor:
+ // Nothing
+ break;
+ case kRobotsAtReadyRoom:
+ GameState.setTSAState(kRobotsAtFrontDoor);
+ _sprite2.setCurrentFrameIndex(kRedirectionNewTargetSprite);
+ startExtraSequence(kTSA0BRobotsFromReadyRoomToFrontDoor, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ }
+ break;
+
+ // Pegasus
+ case kTSA37NorthJumpToPrehistoricSpotID:
+ startExtraSequence(kTSA37PegasusDepart, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kTSA37NorthExitSpotID:
+ _sprite2.setCurrentFrameIndex(1);
+ _vm->delayShell(1, 2);
+ releaseSprites();
+ moveForward();
+ break;
+ case kTSA37NorthJumpMenuSpotID:
+ _sprite2.setCurrentFrameIndex(1);
+ _vm->delayShell(1, 2);
+ releaseSprites();
+ break;
+ case kTSA37NorthJumpToNoradSpotID:
+ GameState.setTSAState(kPlayerOnWayToNorad);
+ requestExtraSequence(kTSA37JumpToNorad, 0, kFilterNoInput);
+
+ if (!GameState.getBeenToNorad()) {
+ requestExtraSequence(kTSA37NoradToAI7, 0, kFilterNoInput);
+ requestExtraSequence(kTSA37PegasusAI7, 0, kFilterNoInput);
+ requestExtraSequence(kTSA37AI7ToNorad, 0, kFilterNoInput);
+ GameState.setBeenToNorad(true);
+ }
+
+ requestExtraSequence(kTSA37NoradToDepart, 0, kFilterNoInput);
+ requestExtraSequence(kTSA37PegasusDepart, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kTSA37NorthJumpToMarsSpotID:
+ GameState.setTSAState(kPlayerOnWayToMars);
+ requestExtraSequence(kTSA37JumpToMars, 0, kFilterNoInput);
+
+ if (!GameState.getBeenToMars()) {
+ requestExtraSequence(kTSA37MarsToAI6, 0, kFilterNoInput);
+ requestExtraSequence(kTSA37PegasusAI6, 0, kFilterNoInput);
+ requestExtraSequence(kTSA37AI6ToMars, 0, kFilterNoInput);
+ GameState.setBeenToMars(true);
+ }
+
+ requestExtraSequence(kTSA37MarsToDepart, 0, kFilterNoInput);
+ requestExtraSequence(kTSA37PegasusDepart, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kTSA37NorthJumpToWSCSpotID:
+ GameState.setTSAState(kPlayerOnWayToWSC);
+ requestExtraSequence(kTSA37JumpToWSC, 0, kFilterNoInput);
+
+ if (!GameState.getBeenToWSC()) {
+ requestExtraSequence(kTSA37WSCToAI5, 0, kFilterNoInput);
+ requestExtraSequence(kTSA37PegasusAI5, 0, kFilterNoInput);
+ requestExtraSequence(kTSA37AI5ToWSC, 0, kFilterNoInput);
+ GameState.setBeenToWSC(true);
+ }
+
+ requestExtraSequence(kTSA37WSCToDepart, 0, kFilterNoInput);
+ requestExtraSequence(kTSA37PegasusDepart, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ default:
+ Neighborhood::clickInHotspot(input, clickedSpot);
+ break;
+ }
+}
+
+void FullTSA::showMainJumpMenu() {
+ ExtraID jumpMenuView = kTSA37JumpMenu000;
+
+ if (GameState.getNoradFinished())
+ jumpMenuView += 4;
+ if (GameState.getMarsFinished())
+ jumpMenuView += 2;
+ if (GameState.getWSCFinished())
+ jumpMenuView += 1;
+
+ showExtraView(jumpMenuView);
+ setCurrentActivation(kActivationMainJumpMenu);
+}
+
+void FullTSA::playTBPMonitor() {
+ InputDevice.waitInput(kFilterAllButtons);
+
+ if ((GameState.getT0BMonitorMode() & kPlayingTBPMask) == 0) {
+ ExtraID extra;
+
+ switch (GameState.getT0BMonitorMode() & kRawModeMask) {
+ case kMonitorTheory:
+ GameState.setTSASeenTheory(true);
+ extra = kTSA0BTBPTheory;
+ GameState.setScoringSawTheory(true);
+ break;
+ case kMonitorBackground:
+ GameState.setTSASeenBackground(true);
+ extra = kTSA0BTBPBackground;
+ GameState.setScoringSawBackground(true);
+ break;
+ case kMonitorProcedure:
+ GameState.setTSASeenProcedure(true);
+ extra = kTSA0BTBPProcedure;
+ GameState.setScoringSawProcedure(true);
+ break;
+ default:
+ error("Invalid monitor mode");
+ }
+
+ GameState.setT0BMonitorMode(GameState.getT0BMonitorMode() | kPlayingTBPMask);
+
+ ExtraTable::Entry entry;
+ getExtraEntry(extra, entry);
+ _lastExtra = extra;
+
+ GameState.setT0BMonitorStart(entry.movieStart + kFullTSAFrameDuration * 5);
+ startMovieSequence(GameState.getT0BMonitorStart(), entry.movieEnd, kExtraCompletedFlag, false, kFilterAllInput);
+ } else if (_navMovie.isRunning()) {
+ _navMovie.stop();
+ } else {
+ _navMovie.start();
+ }
+}
+
+void FullTSA::initializeTBPMonitor(const int newMode, const ExtraID highlightExtra) {
+ GameState.setT0BMonitorMode(newMode);
+
+ if (newMode != kMonitorNeutral) {
+ showExtraView(highlightExtra);
+ _vm->delayShell(1, 2);
+ setCurrentActivation(kActivateTSA0BTBPVideo);
+ _sprite1.addPICTResourceFrame(kTBPRewindPICTID, false, 0, 0);
+ _sprite1.moveElementTo(kTBPRewindLeft, kTBPRewindTop);
+ _sprite1.setCurrentFrameIndex(0);
+ _sprite2.addPICTResourceFrame(kTBPCloseBoxPICTID, false, 0, 0);
+ _sprite2.moveElementTo(kTBPCloseLeft, kTBPCloseTop);
+ _sprite2.setCurrentFrameIndex(0);
+ playTBPMonitor();
+ } else {
+ if (GameState.getTSAState() == kTSAPlayerForcedReview && GameState.getTSASeenTheory() &&
+ GameState.getTSASeenBackground() && GameState.getTSASeenProcedure()) {
+ setOffRipAlarm();
+ } else {
+ setCurrentActivation(kActivateTSA0BZoomedIn);
+ updateViewFrame();
+ }
+
+ releaseSprites();
+ }
+
+ _interruptionFilter = kFilterAllInput;
+}
+
+void FullTSA::startUpComparisonMonitor() {
+ releaseSprites();
+
+ _sprite1.addPICTResourceFrame(kComparisonHiliteNoradPICTID, false,
+ kComparisonHiliteNoradLeft - kComparisonHiliteSpriteLeft,
+ kComparisonHiliteNoradTop - kComparisonHiliteSpriteTop);
+ _sprite1.addPICTResourceFrame(kComparisonHiliteMarsPICTID, false,
+ kComparisonHiliteMarsLeft - kComparisonHiliteSpriteLeft,
+ kComparisonHiliteMarsTop - kComparisonHiliteSpriteTop);
+ _sprite1.addPICTResourceFrame(kComparisonHiliteCaldoriaPICTID, false,
+ kComparisonHiliteCaldoriaLeft - kComparisonHiliteSpriteLeft,
+ kComparisonHiliteCaldoriaTop - kComparisonHiliteSpriteTop);
+ _sprite1.addPICTResourceFrame(kComparisonHiliteWSCPICTID, false,
+ kComparisonHiliteWSCLeft - kComparisonHiliteSpriteLeft,
+ kComparisonHiliteWSCTop - kComparisonHiliteSpriteTop);
+
+ _sprite1.setCurrentFrameIndex(0);
+ _sprite1.moveElementTo(kComparisonHiliteSpriteLeft, kComparisonHiliteSpriteTop);
+
+ _sprite2.addPICTResourceFrame(kComparisonChancesNoradPICTID, false,
+ kComparisonChancesNoradLeft - kComparisonChancesSpriteLeft,
+ kComparisonChancesNoradTop - kComparisonChancesSpriteTop);
+ _sprite2.addPICTResourceFrame(kComparisonChancesMarsPICTID, false,
+ kComparisonChancesMarsLeft - kComparisonChancesSpriteLeft,
+ kComparisonChancesMarsTop - kComparisonChancesSpriteTop);
+ _sprite2.addPICTResourceFrame(kComparisonChancesCaldoriaPICTID, false,
+ kComparisonChancesCaldoriaLeft - kComparisonChancesSpriteLeft,
+ kComparisonChancesCaldoriaTop - kComparisonChancesSpriteTop);
+ _sprite2.addPICTResourceFrame(kComparisonChancesWSCPICTID, false,
+ kComparisonChancesWSCLeft - kComparisonChancesSpriteLeft,
+ kComparisonChancesWSCTop - kComparisonChancesSpriteTop);
+
+ _sprite2.setCurrentFrameIndex(0);
+ _sprite2.moveElementTo(kComparisonChancesSpriteLeft, kComparisonChancesSpriteTop);
+ updateViewFrame();
+}
+
+void FullTSA::shutDownComparisonMonitor() {
+ releaseSprites();
+}
+
+void FullTSA::initializeComparisonMonitor(const int newMode, const ExtraID comparisonView) {
+ GameState.setT0BMonitorMode(newMode);
+ _privateFlags.setFlag(kTSAPrivatePlayingLeftComparisonFlag, false);
+ _privateFlags.setFlag(kTSAPrivatePlayingRightComparisonFlag, false);
+
+ if (newMode != kMonitorNeutral) {
+ shutDownComparisonMonitor();
+ setCurrentActivation(kActivateTSA0BComparisonVideo);
+ _sprite1.addPICTResourceFrame(kComparisonLeftRewindPICTID, false, 0, 0);
+ _sprite1.moveElementTo(kComparisonLeftRewindLeft, kComparisonLeftRewindTop);
+ _sprite1.setCurrentFrameIndex(0);
+ _sprite2.addPICTResourceFrame(kComparisonRightRewindPICTID, false, 0, 0);
+ _sprite2.moveElementTo(kComparisonRightRewindLeft, kComparisonRightRewindTop);
+ _sprite2.setCurrentFrameIndex(0);
+ _sprite3.addPICTResourceFrame(kComparisonCloseBoxPICTID, false, 0, 0);
+ _sprite3.moveElementTo(kComparisonCloseLeft, kComparisonCloseTop);
+ _sprite3.setCurrentFrameIndex(0);
+ showExtraView(comparisonView);
+ } else {
+ if (GameState.getTSAState() == kTSAPlayerInstalledHistoricalLog &&
+ GameState.getTSASeenNoradNormal() &&
+ GameState.getTSASeenNoradAltered() &&
+ GameState.getTSASeenMarsNormal() &&
+ GameState.getTSASeenMarsAltered() &&
+ GameState.getTSASeenCaldoriaNormal() &&
+ GameState.getTSASeenCaldoriaAltered() &&
+ GameState.getTSASeenWSCNormal() &&
+ GameState.getTSASeenWSCAltered()) {
+ GameState.setTSAState(kTSABossSawHistoricalLog);
+ requestExtraSequence(kTSA0BEastZoomOut, kExtraCompletedFlag, kFilterNoInput);
+ requestExtraSequence(kTSA0BEastTurnLeft, kExtraCompletedFlag, kFilterNoInput);
+ requestExtraSequence(kTSA0BNorthZoomIn, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ setCurrentActivation(kActivateTSA0BZoomedIn);
+ releaseSprites();
+ startUpComparisonMonitor();
+ }
+ }
+
+ _interruptionFilter = kFilterAllInput;
+}
+
+void FullTSA::playLeftComparison() {
+ InputDevice.waitInput(kFilterAllButtons);
+
+ if ((GameState.getT0BMonitorMode() & kPlayingLeftComparisonMask) == 0) {
+ ExtraID extra;
+
+ switch (GameState.getT0BMonitorMode() & kRawModeMask) {
+ case kMonitorNoradComparison:
+ GameState.setTSASeenNoradAltered(true);
+ extra = kTSA0BNoradAltered;
+ GameState.setScoringSawNoradAltered(true);
+ break;
+ case kMonitorMarsComparison:
+ GameState.setTSASeenMarsAltered(true);
+ extra = kTSA0BMarsAltered;
+ GameState.setScoringSawMarsAltered(true);
+ break;
+ case kMonitorCaldoriaComparison:
+ GameState.setTSASeenCaldoriaAltered(true);
+ extra = kTSA0BCaldoriaAltered;
+ GameState.setScoringSawCaldoriaAltered(true);
+ break;
+ case kMonitorWSCComparison:
+ GameState.setTSASeenWSCAltered(true);
+ extra = kTSA0BWSCAltered;
+ GameState.setScoringSawWSCAltered(true);
+ break;
+ default:
+ error("Invalid monitor mode");
+ }
+
+ GameState.setT0BMonitorMode(GameState.getT0BMonitorMode() | kPlayingLeftComparisonMask);
+
+ ExtraTable::Entry entry;
+ getExtraEntry(extra, entry);
+ _lastExtra = extra;
+
+ // skip first five frames of movie
+ // (this is a dissolve that doesn't belong...)
+ GameState.setT0BMonitorStart(entry.movieStart + kFullTSAFrameDuration * 5);
+ _privateFlags.setFlag(kTSAPrivatePlayingLeftComparisonFlag);
+
+ // Allow clicking...
+ startMovieSequence(GameState.getT0BMonitorStart(), entry.movieEnd,
+ kExtraCompletedFlag, false, JMPPPInput::getClickInputFilter());
+ } else if (_navMovie.isRunning()) {
+ _navMovie.stop();
+ } else {
+ _navMovie.start();
+ }
+}
+
+void FullTSA::playRightComparison() {
+ InputDevice.waitInput(kFilterAllButtons);
+
+ if ((GameState.getT0BMonitorMode() & kPlayingRightComparisonMask) == 0) {
+ ExtraID extra;
+
+ switch (GameState.getT0BMonitorMode() & kRawModeMask) {
+ case kMonitorNoradComparison:
+ GameState.setTSASeenNoradNormal(true);
+ extra = kTSA0BNoradUnaltered;
+ GameState.setScoringSawNoradNormal(true);
+ break;
+ case kMonitorMarsComparison:
+ GameState.setTSASeenMarsNormal(true);
+ extra = kTSA0BMarsUnaltered;
+ GameState.setScoringSawMarsNormal(true);
+ break;
+ case kMonitorCaldoriaComparison:
+ GameState.setTSASeenCaldoriaNormal(true);
+ extra = kTSA0BCaldoriaUnaltered;
+ GameState.setScoringSawCaldoriaNormal(true);
+ break;
+ case kMonitorWSCComparison:
+ GameState.setTSASeenWSCNormal(true);
+ extra = kTSA0BWSCUnaltered;
+ GameState.setScoringSawWSCNormal(true);
+ break;
+ default:
+ error("Invalid monitor mode");
+ }
+
+ GameState.setT0BMonitorMode(GameState.getT0BMonitorMode() | kPlayingRightComparisonMask);
+
+ ExtraTable::Entry entry;
+ getExtraEntry(extra, entry);
+ _lastExtra = extra;
+
+ // skip first five frames of movie
+ // (this is a dissolve that doesn't belong...)
+ GameState.setT0BMonitorStart(entry.movieStart + kFullTSAFrameDuration * 5);
+ _privateFlags.setFlag(kTSAPrivatePlayingRightComparisonFlag);
+
+ // Allow clicking...
+ startMovieSequence(GameState.getT0BMonitorStart(), entry.movieEnd,
+ kExtraCompletedFlag, false, JMPPPInput::getClickInputFilter());
+ } else if (_navMovie.isRunning()) {
+ _navMovie.stop();
+ } else {
+ _navMovie.start();
+ }
+}
+
+// When this function is called, the player is zoomed up on the center monitor, and the
+// TSA state is kTSABossSawHistoricalLog.
+void FullTSA::startRobotGame() {
+ requestExtraSequence(kTSA0BNorthCantChangeHistory, 0, kFilterNoInput);
+ requestExtraSequence(kTSA0BAIInterruption, 0, kFilterNoInput);
+ requestExtraSequence(kTSA0BShowGuardRobots, 0, kFilterNoInput);
+ requestExtraSequence(kTSA0BRobotsToCommandCenter, kExtraCompletedFlag, kFilterNoInput);
+}
+
+void FullTSA::startUpRobotMonitor() {
+ releaseSprites();
+
+ _sprite1.addPICTResourceFrame(kRedirectionCCRolloverPICTID, true,
+ kRedirectionCCRolloverLeft - kRedirectionSprite1Left,
+ kRedirectionCCRolloverTop - kRedirectionSprite1Top);
+ _sprite1.addPICTResourceFrame(kRedirectionRRRolloverPICTID, true,
+ kRedirectionRRRolloverLeft - kRedirectionSprite1Left,
+ kRedirectionRRRolloverTop - kRedirectionSprite1Top);
+ _sprite1.addPICTResourceFrame(kRedirectionFDRolloverPICTID, false,
+ kRedirectionFDRolloverLeft - kRedirectionSprite1Left,
+ kRedirectionFDRolloverTop - kRedirectionSprite1Top);
+ _sprite1.addPICTResourceFrame(kRedirectionCCDoorPICTID, true,
+ kRedirectionCCDoorLeft - kRedirectionSprite1Left,
+ kRedirectionCCDoorTop - kRedirectionSprite1Top);
+ _sprite1.addPICTResourceFrame(kRedirectionRRDoorPICTID, true,
+ kRedirectionRRDoorLeft - kRedirectionSprite1Left,
+ kRedirectionRRDoorTop - kRedirectionSprite1Top);
+ _sprite1.addPICTResourceFrame(kRedirectionFDDoorPICTID, false,
+ kRedirectionFDDoorLeft - kRedirectionSprite1Left,
+ kRedirectionFDDoorTop - kRedirectionSprite1Top);
+ _sprite1.addPICTResourceFrame(kRedirectionClosePICTID, false,
+ kRedirectionCloseLeft - kRedirectionSprite1Left,
+ kRedirectionCloseTop - kRedirectionSprite1Top);
+ _sprite1.moveElementTo(kRedirectionSprite1Left, kRedirectionSprite1Top);
+
+ _sprite2.addPICTResourceFrame(kRedirectionSecuredPICTID, false,
+ kRedirectionSecuredLeft - kRedirectionSprite2Left,
+ kRedirectionSecuredTop - kRedirectionSprite2Top);
+ _sprite2.addPICTResourceFrame(kRedirectionNewTargetPICTID, false,
+ kRedirectionNewTargetLeft - kRedirectionSprite2Left,
+ kRedirectionNewTargetTop - kRedirectionSprite2Top);
+ _sprite2.moveElementTo(kRedirectionSprite2Left, kRedirectionSprite2Top);
+
+ switch (GameState.getTSAState()) {
+ case kRobotsAtCommandCenter:
+ showExtraView(kTSA0BNorthRobotsAtCCView);
+ break;
+ case kRobotsAtFrontDoor:
+ showExtraView(kTSA0BNorthRobotsAtFDView);
+ break;
+ case kRobotsAtReadyRoom:
+ showExtraView(kTSA0BNorthRobotsAtRRView);
+ break;
+ }
+}
+
+void FullTSA::shutDownRobotMonitor() {
+ releaseSprites();
+}
+
+// Assume this is called only when zoomed in at T0B west
+void FullTSA::setOffRipAlarm() {
+ GameState.setTSAState(kTSAPlayerDetectedRip);
+ _ripTimer.initImage();
+ _ripTimer.moveElementTo(kRipTimerLeft, kRipTimerTop);
+ _ripTimer.setSegment(0, kRipTimeLimit, kRipTimeScale);
+ _ripTimer.start();
+ loadAmbientLoops();
+ startExtraSequenceSync(kTSA0BRipAlarmScreen, kFilterNoInput);
+ _vm->delayShell(2, 1); // Two seconds..
+ requestExtraSequence(kTSA0BWestZoomOut, kExtraCompletedFlag, kFilterNoInput);
+ requestExtraSequence(kTSA0BWestTurnRight, 0, kFilterNoInput);
+ requestExtraSequence(kTSA0BNorthZoomIn, kExtraCompletedFlag, kFilterNoInput);
+ requestExtraSequence(kTSA0BNorthFinallyHappened, 0, kFilterNoInput);
+ requestExtraSequence(kTSA0BShowRip1, kExtraCompletedFlag, kFilterNoInput);
+}
+
+void FullTSA::checkContinuePoint(const RoomID room, const DirectionConstant direction) {
+ switch (MakeRoomView(room, direction)) {
+ case MakeRoomView(kTSA04, kNorth):
+ case MakeRoomView(kTSA14, kEast):
+ case MakeRoomView(kTSA15, kWest):
+ case MakeRoomView(kTSA16, kNorth):
+ case MakeRoomView(kTSA16, kSouth):
+ case MakeRoomView(kTSA21Cyan, kSouth):
+ case MakeRoomView(kTSA21Red, kSouth):
+ case MakeRoomView(kTSA26, kNorth):
+ makeContinuePoint();
+ break;
+ }
+}
+
+void FullTSA::arriveAt(const RoomID room, const DirectionConstant direction) {
+ checkRobotLocations(room, direction);
+ Neighborhood::arriveAt(room, direction);
+
+ switch (MakeRoomView(room, direction)) {
+ case MakeRoomView(kTSADeathRoom, kNorth):
+ case MakeRoomView(kTSADeathRoom, kSouth):
+ case MakeRoomView(kTSADeathRoom, kEast):
+ case MakeRoomView(kTSADeathRoom, kWest):
+ die(kDeathShotByTSARobots);
+ break;
+ case MakeRoomView(kTSA00, kNorth):
+ if (GameState.getLastNeighborhood() != kFullTSAID) {
+ makeContinuePoint();
+ openDoor();
+ } else {
+ setCurrentActivation(kActivateTSAReadyForCard);
+ loopExtraSequence(kTSATransporterArrowLoop, 0);
+ }
+ break;
+ case MakeRoomView(kTSA03, kNorth):
+ case MakeRoomView(kTSA05, kNorth):
+ case MakeRoomView(kTSA0A, kNorth):
+ case MakeRoomView(kTSA06, kNorth):
+ case MakeRoomView(kTSA07, kNorth):
+ if (_utilityFuse.isFuseLit())
+ _utilityFuse.stopFuse();
+ GameState.setScoringEnterTSA(true);
+ break;
+ case MakeRoomView(kTSA04, kNorth):
+ if (_utilityFuse.isFuseLit())
+ _utilityFuse.stopFuse();
+ if (!GameState.getTSASeenRobotGreeting())
+ startExtraSequence(kTSA04NorthRobotGreeting, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case MakeRoomView(kTSA03, kSouth):
+ GameState.setTSAFrontDoorUnlockedInside(GameState.getTSAState() == kRobotsAtFrontDoor || GameState.allTimeZonesFinished());
+ break;
+ case MakeRoomView(kTSA0A, kEast):
+ case MakeRoomView(kTSA0A, kWest):
+ if (GameState.getTSAState() == kTSAPlayerNotArrived)
+ setCurrentActivation(kActivateTSARobotsAwake);
+ break;
+ case MakeRoomView(kTSA0B, kNorth):
+ if (GameState.getTSA0BZoomedIn()) {
+ setCurrentActivation(kActivateTSA0BZoomedIn);
+
+ switch (GameState.getTSAState()) {
+ case kTSAPlayerNeedsHistoricalLog:
+ _ripTimer.show();
+ break;
+ case kRobotsAtCommandCenter:
+ case kRobotsAtFrontDoor:
+ case kRobotsAtReadyRoom:
+ startUpRobotMonitor();
+ break;
+ }
+ } else {
+ setCurrentActivation(kActivateTSA0BZoomedOut);
+
+ switch (GameState.getTSAState()) {
+ case kTSAPlayerNotArrived:
+ requestExtraSequence(kTSA0BNorthZoomIn, kExtraCompletedFlag, kFilterNoInput);
+ requestExtraSequence(kTSA0BNorthYoureBusted, 0, kFilterNoInput);
+ requestExtraSequence(kTSA0BNorthZoomOut, kExtraCompletedFlag, kFilterNoInput);
+ requestExtraSequence(kTSA0BNorthTurnLeft, 0, kFilterNoInput);
+ requestExtraSequence(kTSA0BWestZoomIn, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kTSAPlayerGotHistoricalLog:
+ startExtraSequence(kTSA0BNorthHistLogOpen, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ }
+ }
+ break;
+ case MakeRoomView(kTSA0B, kSouth):
+ GameState.setTSA0BZoomedIn(false);
+ setCurrentActivation(kActivateTSA0BZoomedOut);
+ break;
+ case MakeRoomView(kTSA0B, kWest):
+ if (GameState.getTSA0BZoomedIn()) {
+ setCurrentActivation(kActivateTSA0BZoomedIn);
+ initializeTBPMonitor(kMonitorNeutral, 0);
+ } else {
+ setCurrentActivation(kActivateTSA0BZoomedOut);
+ }
+ break;
+ case MakeRoomView(kTSA0B, kEast):
+ if (GameState.getTSA0BZoomedIn()) {
+ setCurrentActivation(kActivateTSA0BZoomedIn);
+
+ switch (GameState.getTSAState()) {
+ case kTSAPlayerInstalledHistoricalLog:
+ case kTSABossSawHistoricalLog:
+ case kRobotsAtCommandCenter:
+ case kRobotsAtFrontDoor:
+ case kRobotsAtReadyRoom:
+ initializeComparisonMonitor(kMonitorNeutral, 0);
+ break;
+ }
+ } else {
+ setCurrentActivation(kActivateTSA0BZoomedOut);
+ }
+ break;
+ case MakeRoomView(kTSA21Red, kSouth):
+ if (GameState.getTSAState() == kRobotsAtFrontDoor)
+ GameState.setScoringWentToReadyRoom2(true);
+ break;
+ case MakeRoomView(kTSA22Red, kEast):
+ if (!_vm->playerHasItemID(kJourneymanKey))
+ setCurrentActivation(kActivationDoesntHaveKey);
+ break;
+ case MakeRoomView(kTSA23Red, kWest):
+ if (!_vm->playerHasItemID(kPegasusBiochip))
+ setCurrentActivation(kActivationDoesntHaveChips);
+ break;
+ case MakeRoomView(kTSA25Red, kNorth):
+ arriveAtTSA25Red();
+ break;
+ case MakeRoomView(kTSA34, kSouth):
+ if (GameState.getLastRoom() == kTSA37)
+ closeDoorOffScreen(kTSA37, kNorth);
+ break;
+ case MakeRoomView(kTSA37, kNorth):
+ arriveAtTSA37();
+ break;
+ }
+}
+
+void FullTSA::checkRobotLocations(const RoomID room, const DirectionConstant dir) {
+ switch (room) {
+ case kTSA03:
+ case kTSA04:
+ case kTSA05:
+ case kTSA06:
+ case kTSA0A:
+ case kTSA07:
+ case kTSA08:
+ case kTSA09:
+ case kTSA10:
+ case kTSA11:
+ case kTSA12:
+ case kTSA13:
+ case kTSA14:
+ case kTSA15:
+ switch (GameState.getTSAState()) {
+ case kRobotsAtFrontDoor:
+ setCurrentAlternate(kAltTSARobotsAtFrontDoor);
+ break;
+ case kRobotsAtReadyRoom:
+ setCurrentAlternate(kAltTSARobotsAtReadyRoom);
+ break;
+ }
+ break;
+ case kTSA16:
+ if (dir == kNorth) {
+ switch (GameState.getTSAState()) {
+ case kRobotsAtCommandCenter:
+ if (!_privateFlags.getFlag(kTSAPrivateSeenRobotWarningFlag)) {
+ g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/TSA/XT11WB", false, kWarningInterruption);
+ _privateFlags.setFlag(kTSAPrivateSeenRobotWarningFlag, true);
+ }
+ break;
+ case kRobotsAtFrontDoor:
+ setCurrentAlternate(kAltTSARobotsAtFrontDoor);
+ break;
+ case kRobotsAtReadyRoom:
+ setCurrentAlternate(kAltTSARobotsAtReadyRoom);
+ break;
+ }
+ }
+ break;
+ }
+}
+
+void FullTSA::arriveAtTSA25Red() {
+ if (!_vm->playerHasItemID(kJourneymanKey))
+ startExtraSequence(kTSA25NorthDeniedNoKey, kExtraCompletedFlag, kFilterNoInput);
+ else if (!_vm->playerHasItemID(kPegasusBiochip))
+ startExtraSequence(kTSA25NorthDeniedNoChip, kExtraCompletedFlag, kFilterNoInput);
+ else if (GameState.getTSABiosuitOn())
+ startExtraSequence(kTSA25NorthAlreadyHaveSuit, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kTSA25NorthPutOnSuit, kExtraCompletedFlag, kFilterNoInput);
+}
+
+void FullTSA::arriveAtTSA37() {
+ _ripTimer.stop();
+ _ripTimer.releaseImage();
+
+ switch (GameState.getTSAState()) {
+ case kTSAPlayerNeedsHistoricalLog:
+ startExtraLongSequence(kTSA37HorseToAI1, kTSA37AI2ToPrehistoric, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kPlayerOnWayToPrehistoric:
+ setCurrentActivation(kActivationJumpToPrehistoric);
+ showExtraView(kTSA37AI2ToPrehistoric);
+ break;
+ case kTSAPlayerGotHistoricalLog:
+ initializePegasusButtons(false);
+ break;
+ case kPlayerWentToPrehistoric:
+ case kPlayerOnWayToNorad:
+ case kPlayerOnWayToMars:
+ case kPlayerOnWayToWSC:
+ startExtraSequence(kTSA37TimeJumpToPegasus, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kRobotsAtFrontDoor:
+ startExtraLongSequence(kTSA37HorseToColonel2, kTSA37AI4ToMainMenu, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kPlayerLockedInPegasus:
+ showMainJumpMenu();
+ break;
+ case kPlayerFinishedWithTSA:
+ initializePegasusButtons(true);
+ break;
+ }
+}
+
+void FullTSA::turnTo(const DirectionConstant newDirection) {
+ Neighborhood::turnTo(newDirection);
+
+ switch (MakeRoomView(GameState.getCurrentRoom(), newDirection)) {
+ case MakeRoomView(kTSA03, kSouth):
+ if (GameState.getTSAState() == kRobotsAtFrontDoor || GameState.allTimeZonesFinished())
+ GameState.setTSAFrontDoorUnlockedInside(true);
+ else
+ GameState.setTSAFrontDoorUnlockedInside(false);
+ break;
+ case MakeRoomView(kTSA0A, kEast):
+ case MakeRoomView(kTSA0A, kWest):
+ setCurrentActivation(kActivateTSARobotsAwake);
+ break;
+ case MakeRoomView(kTSA0B, kEast):
+ if (GameState.getTSA0BZoomedIn())
+ setCurrentActivation(kActivateTSA0BZoomedIn);
+ else
+ setCurrentActivation(kActivateTSA0BZoomedOut);
+
+ GameState.setT0BMonitorMode(GameState.getT0BMonitorMode() & ~kPlayingAnyMask);
+
+ if (_privateFlags.getFlag(kTSAPrivateLogReaderOpenFlag))
+ _privateFlags.setFlag(kTSAPrivateLogReaderOpenFlag, false);
+
+ switch (GameState.getTSAState()) {
+ case kTSAPlayerInstalledHistoricalLog:
+ case kTSABossSawHistoricalLog:
+ case kRobotsAtCommandCenter:
+ case kRobotsAtFrontDoor:
+ case kRobotsAtReadyRoom:
+ if (GameState.getTSA0BZoomedIn())
+ startUpComparisonMonitor();
+ break;
+ }
+ break;
+ case MakeRoomView(kTSA0B, kNorth):
+ if (GameState.getTSA0BZoomedIn())
+ setCurrentActivation(kActivateTSA0BZoomedIn);
+ else
+ setCurrentActivation(kActivateTSA0BZoomedOut);
+
+ GameState.setT0BMonitorMode(GameState.getT0BMonitorMode() & ~kPlayingAnyMask);
+
+ switch (GameState.getTSAState()) {
+ case kTSAPlayerNeedsHistoricalLog:
+ if (GameState.getTSA0BZoomedIn())
+ _ripTimer.show();
+ break;
+ case kTSAPlayerGotHistoricalLog:
+ if (!GameState.getTSA0BZoomedIn())
+ startExtraSequence(kTSA0BNorthHistLogOpen, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kTSAPlayerInstalledHistoricalLog:
+ if (GameState.getTSA0BZoomedIn()) {
+ if ((GameState.getTSASeenNoradNormal() || GameState.getTSASeenNoradAltered()) &&
+ (GameState.getTSASeenMarsNormal() || GameState.getTSASeenMarsAltered()) &&
+ (GameState.getTSASeenCaldoriaNormal() || GameState.getTSASeenCaldoriaAltered()) &&
+ (GameState.getTSASeenWSCNormal() || GameState.getTSASeenWSCAltered())) {
+ GameState.setTSAState(kTSABossSawHistoricalLog);
+ startRobotGame();
+ }
+ }
+ break;
+ case kRobotsAtCommandCenter:
+ case kRobotsAtFrontDoor:
+ case kRobotsAtReadyRoom:
+ if (GameState.getTSA0BZoomedIn())
+ startExtraSequence(kTSA0BShowGuardRobots, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ }
+ break;
+ case MakeRoomView(kTSA0B, kWest):
+ if (GameState.getTSA0BZoomedIn())
+ setCurrentActivation(kActivateTSA0BZoomedIn);
+ else
+ setCurrentActivation(kActivateTSA0BZoomedOut);
+
+ GameState.setT0BMonitorMode(GameState.getT0BMonitorMode() & ~kPlayingAnyMask);
+
+ if (_privateFlags.getFlag(kTSAPrivateLogReaderOpenFlag))
+ _privateFlags.setFlag(kTSAPrivateLogReaderOpenFlag, false);
+
+ if (GameState.getTSA0BZoomedIn())
+ initializeTBPMonitor(kMonitorNeutral, 0);
+ break;
+ case MakeRoomView(kTSA0B, kSouth):
+ GameState.setTSA0BZoomedIn(false);
+ setCurrentActivation(kActivateTSA0BZoomedOut);
+ break;
+ case MakeRoomView(kTSA16, kNorth):
+ switch (GameState.getTSAState()) {
+ case kRobotsAtCommandCenter:
+ if (!_privateFlags.getFlag(kTSAPrivateSeenRobotWarningFlag)) {
+ g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/TSA/XT11WB", false, kWarningInterruption);
+ _privateFlags.setFlag(kTSAPrivateSeenRobotWarningFlag, true);
+ }
+ break;
+ case kRobotsAtFrontDoor:
+ setCurrentAlternate(kAltTSARobotsAtFrontDoor);
+ break;
+ case kRobotsAtReadyRoom:
+ setCurrentAlternate(kAltTSARobotsAtReadyRoom);
+ break;
+ }
+ break;
+ case MakeRoomView(kTSA22Red, kEast):
+ if (!_vm->playerHasItemID(kJourneymanKey))
+ setCurrentActivation(kActivationDoesntHaveKey);
+ break;
+ case MakeRoomView(kTSA22Red, kNorth):
+ case MakeRoomView(kTSA22Red, kSouth):
+ if (_privateFlags.getFlag(kTSAPrivateKeyVaultOpenFlag)) {
+ playSpotSoundSync(kTSAVaultCloseIn, kTSAVaultCloseOut);
+ _privateFlags.setFlag(kTSAPrivateKeyVaultOpenFlag, false);
+ }
+
+ setCurrentActivation(kActivateHotSpotAlways);
+ break;
+ case MakeRoomView(kTSA23Red, kWest):
+ if (!_vm->playerHasItemID(kPegasusBiochip))
+ setCurrentActivation(kActivationDoesntHaveChips);
+ break;
+ case MakeRoomView(kTSA23Red, kNorth):
+ case MakeRoomView(kTSA23Red, kSouth):
+ if (_privateFlags.getFlag(kTSAPrivateChipVaultOpenFlag)) {
+ playSpotSoundSync(kTSAVaultCloseIn, kTSAVaultCloseOut);
+ _privateFlags.setFlag(kTSAPrivateChipVaultOpenFlag, false);
+ }
+
+ setCurrentActivation(kActivateHotSpotAlways);
+ break;
+ }
+
+ // Make sure the TBP monitor is forced neutral.
+ GameState.setT0BMonitorMode(kMonitorNeutral);
+}
+
+void FullTSA::closeDoorOffScreen(const RoomID room, const DirectionConstant) {
+ switch (room) {
+ case kTSA00:
+ case kTSA01:
+ if (GameState.getCurrentRoom() == kTSA01 || GameState.getCurrentRoom() == kTSA02)
+ playSpotSoundSync(kTSAGTDoorCloseIn, kTSAGTDoorCloseOut);
+ break;
+ case kTSA02:
+ case kTSA03:
+ playSpotSoundSync(kTSAEntryDoorCloseIn, kTSAEntryDoorCloseOut);
+ break;
+ case kTSA14:
+ case kTSA15:
+ case kTSA16:
+ case kTSA21Cyan:
+ case kTSA21Red:
+ playSpotSoundSync(kTSAInsideDoorCloseIn, kTSAInsideDoorCloseOut);
+ break;
+ case kTSA34:
+ case kTSA37:
+ playSpotSoundSync(kTSAPegasusDoorCloseIn, kTSAPegasusDoorCloseOut);
+ break;
+ }
+}
+
+void FullTSA::receiveNotification(Notification *notification, const NotificationFlags flags) {
+ ExtraID lastExtra = _lastExtra;
+
+ if ((flags & kExtraCompletedFlag) != 0) {
+ switch (lastExtra) {
+ case kTSA0BEastTurnLeft:
+ // Need to check this here because turnTo will call _navMovie.stop,
+ // so it has to happen before Neighborhood::receiveNotification,
+ // which may end up starting another sequence...
+ turnTo(kNorth);
+ break;
+ }
+ }
+
+ Neighborhood::receiveNotification(notification, flags);
+
+ InventoryItem *item;
+
+ if ((flags & kExtraCompletedFlag) != 0) {
+ // Only allow input if we're not in the middle of series of queue requests.
+ if (actionQueueEmpty())
+ _interruptionFilter = kFilterAllInput;
+
+ switch (lastExtra) {
+ case kTSAGTCardSwipe:
+ item = (InventoryItem *)_vm->getAllItems().findItemByID(kKeyCard);
+ _vm->addItemToInventory(item);
+ setCurrentActivation(kActivateTSAReadyToTransport);
+ break;
+ case kTSAGTGoToCaldoria:
+ _vm->jumpToNewEnvironment(kCaldoriaID, kCaldoria44, kEast);
+
+ if (GameState.allTimeZonesFinished())
+ GameState.setScoringWentAfterSinclair(true);
+ break;
+ case kTSAGTGoToTokyo:
+ case kTSAGTGoToBeach:
+ if (GameState.allTimeZonesFinished())
+ die(kDeathSinclairShotDelegate);
+ else
+ die(kDeathUncreatedInTSA);
+ break;
+ case kTSA02NorthZoomOut:
+ openDoor();
+ break;
+
+ // Hall of suspects.
+ case kTSA04NorthRobotGreeting:
+ GameState.setTSASeenRobotGreeting(true);
+ restoreStriding(kTSA03, kNorth, kNoAlternateID);
+ break;
+ case kTSA03JimenezZoomIn:
+ GameState.setScoringSawBust1(true);
+ break;
+ case kTSA03CrenshawZoomIn:
+ GameState.setScoringSawBust2(true);
+ break;
+ case kTSA04MatsumotoZoomIn:
+ GameState.setScoringSawBust3(true);
+ break;
+ case kTSA04CastilleZoomIn:
+ GameState.setScoringSawBust4(true);
+ break;
+ case kTSA05SinclairZoomIn:
+ GameState.setScoringSawBust5(true);
+ break;
+ case kTSA05WhiteZoomIn:
+ GameState.setScoringSawBust6(true);
+ break;
+
+ // Command center
+ // Historical comparison...
+ case kTSA0BEastZoomIn:
+ GameState.setTSA0BZoomedIn(true);
+ setCurrentActivation(kActivateTSA0BZoomedIn);
+ GameState.setT0BMonitorMode(GameState.getT0BMonitorMode() & ~kPlayingAnyMask);
+
+ switch (GameState.getTSAState()) {
+ case kTSAPlayerInstalledHistoricalLog:
+ case kTSABossSawHistoricalLog:
+ case kRobotsAtCommandCenter:
+ case kRobotsAtFrontDoor:
+ case kRobotsAtReadyRoom:
+ startUpComparisonMonitor();
+ break;
+ }
+ break;
+ case kTSA0BEastZoomOut:
+ GameState.setTSA0BZoomedIn(false);
+ setCurrentActivation(kActivateTSA0BZoomedOut);
+
+ switch (GameState.getTSAState()) {
+ case kTSABossSawHistoricalLog:
+ // Prevent current view from activating.
+ break;
+ default:
+ activateCurrentView(GameState.getCurrentRoom(), GameState.getCurrentDirection(),
+ kSpotOnTurnMask);
+ break;
+ }
+ break;
+ case kTSA0BComparisonStartup:
+ if ((flags & kActionRequestCompletedFlag) != 0) {
+ _privateFlags.setFlag(kTSAPrivateLogReaderOpenFlag, false);
+ GameState.setTSAState(kTSAPlayerInstalledHistoricalLog);
+ turnTo(kEast);
+ }
+
+ startUpComparisonMonitor();
+ break;
+ case kTSA0BNoradAltered:
+ case kTSA0BMarsAltered:
+ case kTSA0BCaldoriaAltered:
+ case kTSA0BWSCAltered:
+ case kTSA0BNoradUnaltered:
+ case kTSA0BMarsUnaltered:
+ case kTSA0BCaldoriaUnaltered:
+ case kTSA0BWSCUnaltered:
+ initializeComparisonMonitor(kMonitorNeutral, 0);
+ break;
+
+ // Center monitor.
+ case kTSA0BNorthZoomIn:
+ GameState.setTSA0BZoomedIn(true);
+ setCurrentActivation(kActivateTSA0BZoomedIn);
+ GameState.setT0BMonitorMode(GameState.getT0BMonitorMode() & ~kPlayingAnyMask);
+
+ switch (GameState.getTSAState()) {
+ case kTSAPlayerNeedsHistoricalLog:
+ startExtraSequence(kTSA0BShowRip1, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kTSABossSawHistoricalLog:
+ case kTSAPlayerInstalledHistoricalLog:
+ if ((GameState.getTSASeenNoradNormal() || GameState.getTSASeenNoradAltered()) &&
+ (GameState.getTSASeenMarsNormal() || GameState.getTSASeenMarsAltered()) &&
+ (GameState.getTSASeenCaldoriaNormal() || GameState.getTSASeenCaldoriaAltered()) &&
+ (GameState.getTSASeenWSCNormal() || GameState.getTSASeenWSCAltered())) {
+ GameState.setTSAState(kTSABossSawHistoricalLog);
+ startRobotGame();
+ }
+ break;
+ case kRobotsAtCommandCenter:
+ case kRobotsAtFrontDoor:
+ case kRobotsAtReadyRoom:
+ startExtraSequence(kTSA0BShowGuardRobots, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ }
+ break;
+ case kTSA0BNorthZoomOut:
+ GameState.setTSA0BZoomedIn(false);
+ setCurrentActivation(kActivateTSA0BZoomedOut);
+ break;
+ case kTSA0BShowRip1:
+ GameState.setTSAState(kTSAPlayerNeedsHistoricalLog);
+ GameState.setTSACommandCenterLocked(false);
+
+ if ((flags & kActionRequestCompletedFlag) != 0)
+ turnTo(kNorth);
+
+ _ripTimer.show();
+ break;
+ case kTSA0BNorthHistLogOpen:
+ setCurrentActivation(kActivationLogReaderOpen);
+ _privateFlags.setFlag(kTSAPrivateLogReaderOpenFlag, true);
+ break;
+ case kTSA0BRobotsToCommandCenter:
+ GameState.setTSAState(kRobotsAtCommandCenter);
+ // Fall through
+ case kTSA0BShowGuardRobots:
+ startUpRobotMonitor();
+ // Fall through
+ case kTSA0BRobotsFromCommandCenterToReadyRoom:
+ case kTSA0BRobotsFromReadyRoomToCommandCenter:
+ case kTSA0BRobotsFromCommandCenterToFrontDoor:
+ case kTSA0BRobotsFromFrontDoorToCommandCenter:
+ case kTSA0BRobotsFromFrontDoorToReadyRoom:
+ case kTSA0BRobotsFromReadyRoomToFrontDoor:
+ _sprite2.setCurrentFrameIndex(kRedirectionSecuredSprite);
+ _sprite2.show();
+ break;
+
+ // TBP monitor.
+ case kTSA0BWestZoomIn:
+ GameState.setTSA0BZoomedIn(true);
+ setCurrentActivation(kActivateTSA0BZoomedIn);
+
+ if (GameState.getTSAState() == kTSAPlayerNotArrived) {
+ turnTo(kWest);
+ GameState.setTSACommandCenterLocked(true);
+ GameState.setTSAState(kTSAPlayerForcedReview);
+ }
+
+ initializeTBPMonitor(kMonitorNeutral, 0);
+ break;
+ case kTSA0BWestZoomOut:
+ GameState.setTSA0BZoomedIn(false);
+ setCurrentActivation(kActivateTSA0BZoomedOut);
+ GameState.setT0BMonitorMode(kMonitorNeutral);
+
+ switch (GameState.getTSAState()) {
+ case kTSAPlayerDetectedRip:
+ // Keep the current view from activating.
+ break;
+ default:
+ activateCurrentView(GameState.getCurrentRoom(), GameState.getCurrentDirection(),
+ kSpotOnTurnMask);
+ break;
+ }
+ break;
+ case kTSA0BTBPTheory:
+ case kTSA0BTBPBackground:
+ case kTSA0BTBPProcedure:
+ initializeTBPMonitor(kMonitorNeutral, 0);
+ break;
+
+ // Ready room
+ case kTSA22RedEastZoomInSequence:
+ _privateFlags.setFlag(kTSAPrivateKeyVaultOpenFlag, true);
+ setCurrentActivation(kActivationKeyVaultOpen);
+ break;
+ case kTSA23RedWestVaultZoomInSequence:
+ _privateFlags.setFlag(kTSAPrivateChipVaultOpenFlag, true);
+ setCurrentActivation(kActivationChipVaultOpen);
+ break;
+ case kTSA25NorthPutOnSuit:
+ GameState.setTSABiosuitOn(true);
+ GameState.setScoringGotBiosuit(true);
+ // Fall through...
+ case kTSA25NorthAlreadyHaveSuit:
+ requestExtraSequence(kTSA25NorthDescending1, 0, kFilterNoInput);
+ requestExtraSequence(kTSA25NorthDescending2, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kTSA25NorthDescending2:
+ arriveAt(kTSA26, kNorth);
+ break;
+
+ // Pegasus.
+ case kTSA37HorseToAI1:
+ case kTSA37AI2ToPrehistoric:
+ setCurrentActivation(kActivationJumpToPrehistoric);
+ GameState.setTSAState(kPlayerOnWayToPrehistoric);
+ break;
+ case kTSA37PegasusDepart:
+ _vm->setLastEnergyValue(kFullEnergy);
+
+ switch (GameState.getTSAState()) {
+ case kPlayerOnWayToPrehistoric:
+ _vm->jumpToNewEnvironment(kPrehistoricID, kPrehistoric02, kSouth);
+ GameState.setPrehistoricSeenTimeStream(false);
+ GameState.setPrehistoricSeenFlyer1(false);
+ GameState.setPrehistoricSeenFlyer2(false);
+ GameState.setPrehistoricSeenBridgeZoom(false);
+ GameState.setPrehistoricBreakerThrown(false);
+ GameState.setScoringGoToPrehistoric(true);
+ GameState.setTSAState(kPlayerWentToPrehistoric);
+ break;
+ case kPlayerOnWayToNorad:
+ _vm->jumpToNewEnvironment(kNoradAlphaID, kNorad01, kSouth);
+ GameState.setNoradSeenTimeStream(false);
+ GameState.setNoradGassed(true);
+ GameState.setNoradFillingStationOn(false);
+ GameState.setNoradN22MessagePlayed(false);
+ GameState.setNoradPlayedGlobeGame(false);
+ GameState.setNoradBeatRobotWithClaw(false);
+ GameState.setNoradBeatRobotWithDoor(false);
+ GameState.setNoradRetScanGood(false);
+ GameState.setNoradWaitingForLaser(false);
+ GameState.setNoradSubRoomPressure(9);
+ GameState.setNoradSubPrepState(kSubNotPrepped);
+ break;
+ case kPlayerOnWayToMars:
+ _vm->jumpToNewEnvironment(kMarsID, kMars0A, kNorth);
+ GameState.setMarsSeenTimeStream(false);
+ GameState.setMarsHeardUpperPodMessage(false);
+ GameState.setMarsRobotThrownPlayer(false);
+ GameState.setMarsHeardCheckInMessage(false);
+ GameState.setMarsPodAtUpperPlatform(false);
+ GameState.setMarsSeenThermalScan(false);
+ GameState.setMarsArrivedBelow(false);
+ GameState.setMarsSeenRobotAtReactor(false);
+ GameState.setMarsAvoidedReactorRobot(false);
+ GameState.setMarsLockFrozen(false);
+ GameState.setMarsLockBroken(false);
+ GameState.setMarsSecurityDown(false);
+ GameState.setMarsAirlockOpen(false);
+ GameState.setMarsReadyForShuttleTransport(false);
+ GameState.setMarsFinishedCanyonChase(false);
+ GameState.setMarsThreadedMaze(false);
+ break;
+ case kPlayerOnWayToWSC:
+ _vm->jumpToNewEnvironment(kWSCID, kWSC01, kWest);
+ GameState.setWSCSeenTimeStream(false);
+ GameState.setWSCPoisoned(false);
+ GameState.setWSCAnsweredAboutDart(false);
+ GameState.setWSCRemovedDart(false);
+ GameState.setWSCAnalyzerOn(false);
+ GameState.setWSCDartInAnalyzer(false);
+ GameState.setWSCAnalyzedDart(false);
+ GameState.setWSCPickedUpAntidote(false);
+ GameState.setWSCSawMorph(false);
+ GameState.setWSCDesignedAntidote(false);
+ GameState.setWSCOfficeMessagesOpen(false);
+ GameState.setWSCSeenNerd(false);
+ GameState.setWSCHeardPage1(false);
+ GameState.setWSCHeardPage2(false);
+ GameState.setWSCHeardCheckIn(false);
+ GameState.setWSCDidPlasmaDodge(false);
+ GameState.setWSCSeenSinclairLecture(false);
+ GameState.setWSCBeenAtWSC93(false);
+ GameState.setWSCCatwalkDark(false);
+ GameState.setWSCRobotDead(false);
+ GameState.setWSCRobotGone(false);
+ break;
+ };
+ break;
+ case kTSA37TimeJumpToPegasus:
+ if (g_energyMonitor)
+ g_energyMonitor->stopEnergyDraining();
+
+ switch (GameState.getTSAState()) {
+ case kPlayerWentToPrehistoric:
+ arriveFromPrehistoric();
+ break;
+ case kPlayerOnWayToNorad:
+ arriveFromNorad();
+ break;
+ case kPlayerOnWayToMars:
+ arriveFromMars();
+ break;
+ case kPlayerOnWayToWSC:
+ arriveFromWSC();
+ break;
+ default:
+ break;
+ }
+ break;
+ case kTSA37DownloadToOpMemReview:
+ switch (GameState.getTSAState()) {
+ case kPlayerOnWayToNorad:
+ g_opticalChip->playOpMemMovie(kPoseidonSpotID);
+ break;
+ case kPlayerOnWayToMars:
+ g_opticalChip->playOpMemMovie(kAriesSpotID);
+ break;
+ case kPlayerOnWayToWSC:
+ g_opticalChip->playOpMemMovie(kMercurySpotID);
+ break;
+ }
+
+ if (GameState.allTimeZonesFinished()) {
+ requestExtraSequence(kTSA37OpMemReviewToAllClear, 0, kFilterNoInput);
+ requestExtraSequence(kTSA37AllClearToCongratulations, 0, kFilterNoInput);
+ requestExtraSequence(kTSA37Congratulations, 0, kFilterNoInput);
+ requestExtraSequence(kTSA37CongratulationsToExit, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ requestExtraSequence(kTSA37OpMemReviewToMainMenu, kExtraCompletedFlag, kFilterNoInput);
+ }
+ break;
+ case kTSA37RecallToDownload:
+ case kTSA37ReviewRequiredToExit:
+ GameState.setTSAState(kTSAPlayerGotHistoricalLog);
+ initializePegasusButtons(kPegasusUnresolved);
+ break;
+ case kTSA37ZoomToMainMenu:
+ case kTSA37HorseToColonel2:
+ case kTSA37DownloadToMainMenu:
+ case kTSA37OpMemReviewToMainMenu:
+ case kTSA37AI4ToMainMenu:
+ GameState.setTSAState(kPlayerLockedInPegasus);
+ showMainJumpMenu();
+ makeContinuePoint();
+ break;
+ case kTSA37JumpToNoradMenu:
+ setCurrentActivation(kActivationJumpToNorad);
+ break;
+ case kTSA37JumpToMarsMenu:
+ setCurrentActivation(kActivationJumpToMars);
+ break;
+ case kTSA37JumpToWSCMenu:
+ setCurrentActivation(kActivationJumpToWSC);
+ break;
+ case kTSA37CancelNorad:
+ case kTSA37CancelMars:
+ case kTSA37CancelWSC:
+ showMainJumpMenu();
+ break;
+ case kTSA37CongratulationsToExit:
+ GameState.setTSAState(kPlayerFinishedWithTSA);
+ initializePegasusButtons(true);
+ break;
+ }
+ }
+
+ g_AIArea->checkMiddleArea();
+}
+
+void FullTSA::arriveFromPrehistoric() {
+ if (_vm->playerHasItemID(kHistoricalLog)) {
+ GameState.setScoringFinishedPrehistoric();
+ requestExtraSequence(kTSA37RecallToDownload, 0, kFilterNoInput);
+ requestExtraSequence(kTSA37DownloadToColonel1, 0, kFilterNoInput);
+ requestExtraSequence(kTSA37Colonel1, 0, kFilterNoInput);
+ requestExtraSequence(kTSA37Colonel1ToReviewRequired, 0, kFilterNoInput);
+ requestExtraSequence(kTSA37ReviewRequiredToExit, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ // Make sure rip timer is going...
+ startExtraSequence(kTSA37DownloadToMainMenu, kExtraCompletedFlag, kFilterNoInput);
+ }
+}
+
+void FullTSA::arriveFromNorad() {
+ requestExtraSequence(kTSA37RecallToDownload, 0, kFilterNoInput);
+
+ if (GameState.getNoradFinished() && !GameState.getScoringFinishedNorad()) {
+ GameState.setScoringFinishedNorad();
+ requestExtraSequence(kTSA37DownloadToOpMemReview, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ requestExtraSequence(kTSA37DownloadToMainMenu, kExtraCompletedFlag, kFilterNoInput);
+ }
+}
+
+void FullTSA::arriveFromMars() {
+ requestExtraSequence(kTSA37RecallToDownload, 0, kFilterNoInput);
+
+ if (GameState.getMarsFinished() && !GameState.getScoringFinishedMars()) {
+ GameState.setScoringFinishedMars();
+ requestExtraSequence(kTSA37DownloadToOpMemReview, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ requestExtraSequence(kTSA37DownloadToMainMenu, kExtraCompletedFlag, kFilterNoInput);
+ }
+}
+
+void FullTSA::arriveFromWSC() {
+ requestExtraSequence(kTSA37RecallToDownload, 0, kFilterNoInput);
+
+ if (GameState.getWSCFinished() && !GameState.getScoringFinishedWSC()) {
+ GameState.setScoringFinishedWSC();
+ requestExtraSequence(kTSA37DownloadToOpMemReview, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ requestExtraSequence(kTSA37DownloadToMainMenu, kExtraCompletedFlag, kFilterNoInput);
+ }
+}
+
+void FullTSA::initializePegasusButtons(bool resolved) {
+ if (resolved) {
+ _sprite1.addPICTResourceFrame(kResolvedPICTID, false, 0, 0);
+ _sprite1.moveElementTo(kResolvedLeft, kResolvedTop);
+ } else {
+ _sprite1.addPICTResourceFrame(kUnresolvedPICTID, false, 0, 0);
+ _sprite1.moveElementTo(kUnresolvedLeft, kUnresolvedTop);
+ }
+
+ _sprite1.setCurrentFrameIndex(0);
+ _sprite1.show();
+
+ _sprite2.addPICTResourceFrame(kExitPICTID, false, kExitLeft - kExitHilitedLeft, kExitTop - kExitHilitedTop);
+ _sprite2.addPICTResourceFrame(kExitHilitedPICTID, false, 0, 0);
+ _sprite2.moveElementTo(kExitHilitedLeft, kExitHilitedTop);
+ setCurrentActivation(kActivationReadyToExit);
+ _sprite2.setCurrentFrameIndex(0);
+ _sprite2.show();
+}
+
+Hotspot *FullTSA::getItemScreenSpot(Item *item, DisplayElement *element) {
+ switch (item->getObjectID()) {
+ case kJourneymanKey:
+ return _vm->getAllHotspots().findHotspotByID(kTSA22EastKeySpotID);
+ break;
+ case kPegasusBiochip:
+ return _vm->getAllHotspots().findHotspotByID(kTSA23WestChipsSpotID);
+ break;
+ }
+
+ return Neighborhood::getItemScreenSpot(item, element);
+}
+
+void FullTSA::dropItemIntoRoom(Item *item, Hotspot *dropSpot) {
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+
+ switch (item->getObjectID()) {
+ case kKeyCard:
+ if (dropSpot->getObjectID() == kTSAGTCardDropSpotID)
+ startExtraSequence(kTSAGTCardSwipe, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kHistoricalLog:
+ if (dropSpot->getObjectID() == kTSA0BNorthHistLogSpotID) {
+ requestExtraSequence(kTSA0BNorthHistLogCloseWithLog, 0, kFilterNoInput);
+ requestExtraSequence(kTSA0BNorthTurnRight, 0, kFilterNoInput);
+ requestExtraSequence(kTSA0BEastZoomIn, kExtraCompletedFlag, kFilterNoInput);
+ requestExtraSequence(kTSA0BComparisonStartup, kExtraCompletedFlag, kFilterNoInput);
+ GameState.setScoringPutLogInReader(true);
+ }
+ break;
+ }
+}
+
+uint FullTSA::getHistoricalLogIndex() {
+ uint index;
+
+ if (GameState.getTSASeenNoradNormal() && GameState.getTSASeenNoradAltered())
+ index = 8;
+ else
+ index = 0;
+
+ if (GameState.getTSASeenMarsNormal() && GameState.getTSASeenMarsAltered())
+ index += 4;
+
+ if (GameState.getTSASeenCaldoriaNormal() && GameState.getTSASeenCaldoriaAltered())
+ index += 2;
+
+ if (GameState.getTSASeenWSCNormal() && GameState.getTSASeenWSCAltered())
+ index += 1;
+
+ return index;
+}
+
+void FullTSA::handleInput(const Input &input, const Hotspot *cursorSpot) {
+ switch (MakeRoomView(GameState.getCurrentRoom(), GameState.getCurrentDirection())) {
+ case MakeRoomView(kTSA0B, kEast):
+ if (GameState.getTSA0BZoomedIn() && !_navMovie.isRunning() && GameState.getT0BMonitorMode() == kMonitorNeutral) {
+ switch (GameState.getTSAState()) {
+ case kTSAPlayerInstalledHistoricalLog:
+ case kTSABossSawHistoricalLog:
+ case kRobotsAtCommandCenter:
+ case kRobotsAtFrontDoor:
+ case kRobotsAtReadyRoom:
+ if (cursorSpot) {
+ switch (cursorSpot->getObjectID()) {
+ case kTSA0BEastCompareNoradSpotID:
+ _sprite1.setCurrentFrameIndex(0);
+ _sprite2.setCurrentFrameIndex(0);
+ _sprite1.show();
+ _sprite2.show();
+ break;
+ case kTSA0BEastCompareMarsSpotID:
+ _sprite1.setCurrentFrameIndex(1);
+ _sprite2.setCurrentFrameIndex(1);
+ _sprite1.show();
+ _sprite2.show();
+ break;
+ case kTSA0BEastCompareCaldoriaSpotID:
+ _sprite1.setCurrentFrameIndex(2);
+ _sprite2.setCurrentFrameIndex(2);
+ _sprite1.show();
+ _sprite2.show();
+ break;
+ case kTSA0BEastCompareWSCSpotID:
+ _sprite1.setCurrentFrameIndex(3);
+ _sprite2.setCurrentFrameIndex(3);
+ _sprite1.show();
+ _sprite2.show();
+ break;
+ default:
+ _sprite1.hide();
+ _sprite2.hide();
+ break;
+ }
+ } else {
+ _sprite1.hide();
+ _sprite2.hide();
+ }
+ break;
+ }
+ }
+ break;
+ case MakeRoomView(kTSA0B, kNorth):
+ if (GameState.getTSA0BZoomedIn() && !_navMovie.isRunning()) {
+ switch (GameState.getTSAState()) {
+ case kRobotsAtCommandCenter:
+ case kRobotsAtFrontDoor:
+ case kRobotsAtReadyRoom:
+ if (cursorSpot) {
+ switch (cursorSpot->getObjectID()) {
+ case kTSA0BNorthRobotsToCommandCenterSpotID:
+ _sprite1.setCurrentFrameIndex(kRedirectionCCRolloverSprite);
+ _sprite1.show();
+ break;
+ case kTSA0BNorthRobotsToReadyRoomSpotID:
+ _sprite1.setCurrentFrameIndex(kRedirectionRRRolloverSprite);
+ _sprite1.show();
+ break;
+ case kTSA0BNorthRobotsToFrontDoorSpotID:
+ _sprite1.setCurrentFrameIndex(kRedirectionFDRolloverSprite);
+ _sprite1.show();
+ break;
+ default:
+ _sprite1.hide();
+ break;
+ }
+ } else {
+ _sprite1.hide();
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ Neighborhood::handleInput(input, cursorSpot);
+}
+
+void FullTSA::releaseSprites() {
+ _sprite1.hide();
+ _sprite2.hide();
+ _sprite3.hide();
+ _sprite1.discardFrames();
+ _sprite2.discardFrames();
+ _sprite3.discardFrames();
+}
+
+bool FullTSA::canSolve() {
+ return GameState.getCurrentRoomAndView() == MakeRoomView(kTSA0B, kNorth) &&
+ GameState.getTSA0BZoomedIn() &&
+ (GameState.getTSAState() == kRobotsAtCommandCenter ||
+ GameState.getTSAState() == kRobotsAtFrontDoor ||
+ GameState.getTSAState() == kRobotsAtReadyRoom);
+}
+
+void FullTSA::doSolve() {
+ // REROUTING ROBOTS
+
+ _sprite1.setCurrentFrameIndex(kRedirectionFDDoorSprite);
+ _sprite1.show();
+ _vm->delayShell(1, 2);
+ _sprite1.hide();
+
+ switch (GameState.getTSAState()) {
+ case kRobotsAtCommandCenter:
+ GameState.setTSAState(kRobotsAtFrontDoor);
+ _sprite2.setCurrentFrameIndex(kRedirectionNewTargetSprite);
+ startExtraSequence(kTSA0BRobotsFromCommandCenterToFrontDoor, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kRobotsAtFrontDoor:
+ // Nothing
+ break;
+ case kRobotsAtReadyRoom:
+ GameState.setTSAState(kRobotsAtFrontDoor);
+ _sprite2.setCurrentFrameIndex(kRedirectionNewTargetSprite);
+ startExtraSequence(kTSA0BRobotsFromReadyRoomToFrontDoor, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ }
+}
+
+void FullTSA::updateCursor(const Common::Point where, const Hotspot *cursorSpot) {
+ if (cursorSpot) {
+ switch (cursorSpot->getObjectID()) {
+ case kTSA0BEastMonitorSpotID:
+ case kTSA0BNorthMonitorSpotID:
+ case kTSA0BWestMonitorSpotID:
+ case kTSA22EastMonitorSpotID:
+ case kTSA23WestMonitorSpotID:
+ _vm->_cursor->setCurrentFrameIndex(1);
+ return;
+ case kTSA0BEastMonitorOutSpotID:
+ case kTSA0BNorthMonitorOutSpotID:
+ case kTSA0BWestMonitorOutSpotID:
+ _vm->_cursor->setCurrentFrameIndex(2);
+ return;
+ }
+ }
+
+ Neighborhood::updateCursor(where, cursorSpot);
+}
+
+Common::String FullTSA::getNavMovieName() {
+ return "Images/TSA/Full TSA.movie";
+}
+
+Common::String FullTSA::getSoundSpotsName() {
+ return "Sounds/TSA/TSA Spots";
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/tsa/fulltsa.h b/engines/pegasus/neighborhood/tsa/fulltsa.h
new file mode 100644
index 0000000000..a646d57e6c
--- /dev/null
+++ b/engines/pegasus/neighborhood/tsa/fulltsa.h
@@ -0,0 +1,159 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_TSA_FULLTSA_H
+#define PEGASUS_NEIGHBORHOOD_TSA_FULLTSA_H
+
+#include "pegasus/neighborhood/neighborhood.h"
+
+namespace Pegasus {
+
+class RipTimer : public IdlerAnimation {
+public:
+ RipTimer(const DisplayElementID id) : IdlerAnimation(id) {}
+ virtual ~RipTimer() {}
+
+ void initImage();
+ void releaseImage();
+
+ void draw(const Common::Rect &);
+
+protected:
+ void timeChanged(const TimeValue);
+
+ CoordType _middle;
+ Surface _timerImage;
+};
+
+// Room IDs.
+
+static const RoomID kTSA00 = 0;
+static const RoomID kTSA22Red = 28;
+static const RoomID kTSA37 = 42;
+
+class FullTSA : public Neighborhood {
+public:
+ FullTSA(InputHandler *, PegasusEngine *);
+ virtual ~FullTSA() {}
+
+ virtual void init();
+
+ void start();
+
+ virtual uint16 getDateResID() const;
+
+ void flushGameState();
+
+ void checkContinuePoint(const RoomID, const DirectionConstant);
+
+ bool canSolve();
+ void doSolve();
+
+ void updateCursor(const Common::Point, const Hotspot *);
+
+protected:
+ enum {
+ kTSAPrivateLogReaderOpenFlag,
+ kTSAPrivateKeyVaultOpenFlag,
+ kTSAPrivateChipVaultOpenFlag,
+ kTSAPrivatePlayingLeftComparisonFlag,
+ kTSAPrivatePlayingRightComparisonFlag,
+ kTSAPrivateSeenRobotWarningFlag,
+ kNumTSAPrivateFlags
+ };
+
+ Common::String getBriefingMovie();
+ Common::String getEnvScanMovie();
+ uint getNumHints();
+ Common::String getHintMovie(uint);
+ void loadAmbientLoops();
+ virtual void clickInHotspot(const Input &, const Hotspot *);
+
+ virtual int16 getStaticCompassAngle(const RoomID, const DirectionConstant);
+ void activateOneHotspot(HotspotInfoTable::Entry &, Hotspot *spot);
+ virtual void activateHotspots();
+ void getExitCompassMove(const ExitTable::Entry &, FaderMoveSpec &);
+ void dropItemIntoRoom(Item *, Hotspot *);
+ void downButton(const Input &);
+ void startDoorOpenMovie(const TimeValue, const TimeValue);
+ TimeValue getViewTime(const RoomID, const DirectionConstant);
+ void findSpotEntry(const RoomID, const DirectionConstant, SpotFlags, SpotTable::Entry &);
+ void turnTo(const DirectionConstant);
+ CanMoveForwardReason canMoveForward(ExitTable::Entry &);
+ CanOpenDoorReason canOpenDoor(DoorTable::Entry &);
+ void bumpIntoWall();
+ void initializeTBPMonitor(const int, const ExtraID);
+ void playTBPMonitor();
+ void getExtraCompassMove(const ExtraTable::Entry &, FaderMoveSpec &);
+ Hotspot *getItemScreenSpot(Item *, DisplayElement *);
+ void openDoor();
+ void turnRight();
+ void turnLeft();
+ void closeDoorOffScreen(const RoomID, const DirectionConstant);
+ void playExtraMovie(const ExtraTable::Entry &, const NotificationFlags, const InputBits interruptionInput);
+ void handleInput(const Input &, const Hotspot *);
+ void arriveAtTSA25Red();
+ void startUpComparisonMonitor();
+ void shutDownComparisonMonitor();
+ void initializeComparisonMonitor(const int, const ExtraID);
+ void playLeftComparison();
+ void playRightComparison();
+ void startRobotGame();
+ void setOffRipAlarm();
+ uint getHistoricalLogIndex();
+ void startUpRobotMonitor();
+ void shutDownRobotMonitor();
+ void pickedUpItem(Item *item);
+ void arriveFromPrehistoric();
+
+ void arriveFromNorad();
+ void arriveFromMars();
+ void arriveFromWSC();
+
+ InputBits getInputFilter();
+ void arriveAt(const RoomID, const DirectionConstant);
+ void initializePegasusButtons(bool);
+ void releaseSprites();
+ void showMainJumpMenu();
+ void arriveAtTSA37();
+ void receiveNotification(Notification *, const NotificationFlags);
+ void checkRobotLocations(const RoomID, const DirectionConstant);
+ void getExtraEntry(const uint32, ExtraTable::Entry &);
+
+ Sprite _sprite1, _sprite2, _sprite3;
+ FuseFunction _utilityFuse;
+ RipTimer _ripTimer;
+
+ FlagsArray<byte, kNumTSAPrivateFlags> _privateFlags;
+
+ Common::String getNavMovieName();
+ Common::String getSoundSpotsName();
+
+ void dieUncreatedInTSA();
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/tsa/tinytsa.cpp b/engines/pegasus/neighborhood/tsa/tinytsa.cpp
new file mode 100644
index 0000000000..4f109620c1
--- /dev/null
+++ b/engines/pegasus/neighborhood/tsa/tinytsa.cpp
@@ -0,0 +1,453 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/energymonitor.h"
+#include "pegasus/gamestate.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/biochips/aichip.h"
+#include "pegasus/items/biochips/opticalchip.h"
+#include "pegasus/neighborhood/mars/constants.h"
+#include "pegasus/neighborhood/norad/constants.h"
+#include "pegasus/neighborhood/tsa/tinytsa.h"
+#include "pegasus/neighborhood/wsc/wsc.h"
+
+namespace Pegasus {
+
+static const int16 kCompassShift = 30;
+
+static const TimeScale kTinyTSAMovieScale = 600;
+static const TimeScale kTinyTSAFramesPerSecond = 15;
+static const TimeScale kTinyTSAFrameDuration = 40;
+
+// Alternate IDs.
+static const AlternateID kAltTinyTSANormal = 0;
+
+// Hot Spot Activation IDs.
+static const HotSpotActivationID kActivationTinyTSAJumpToNorad = 1;
+static const HotSpotActivationID kActivationTinyTSAJumpToMars = 2;
+static const HotSpotActivationID kActivationTinyTSAJumpToWSC = 3;
+static const HotSpotActivationID kActivationTinyTSAReadyForJumpMenu = 4;
+static const HotSpotActivationID kActivationTinyTSAMainJumpMenu = 5;
+
+// Hot Spot IDs.
+static const HotSpotID kTinyTSA37NorthJumpToNoradSpotID = 5000;
+static const HotSpotID kTinyTSA37NorthCancelNoradSpotID = 5001;
+static const HotSpotID kTinyTSA37NorthJumpToMarsSpotID = 5002;
+static const HotSpotID kTinyTSA37NorthCancelMarsSpotID = 5003;
+static const HotSpotID kTinyTSA37NorthJumpToWSCSpotID = 5004;
+static const HotSpotID kTinyTSA37NorthCancelWSCSpotID = 5005;
+static const HotSpotID kTinyTSA37NorthJumpMenuSpotID = 5006;
+static const HotSpotID kTinyTSA37NorthNoradMenuSpotID = 5007;
+static const HotSpotID kTinyTSA37NorthMarsMenuSpotID = 5008;
+static const HotSpotID kTinyTSA37NorthWSCMenuSpotID = 5009;
+
+// Extra sequence IDs.
+static const ExtraID kTinyTSA37PegasusDepart = 0;
+static const ExtraID kTinyTSA37TimeJumpToPegasus = 1;
+static const ExtraID kTinyTSA37RecallToDownload = 2;
+static const ExtraID kTinyTSA37ExitHilited = 3;
+static const ExtraID kTinyTSA37ExitToHorse = 4;
+static const ExtraID kTinyTSA37JumpMenu000 = 5;
+static const ExtraID kTinyTSA37JumpMenu001 = 6;
+static const ExtraID kTinyTSA37JumpMenu010 = 7;
+static const ExtraID kTinyTSA37JumpMenu011 = 8;
+static const ExtraID kTinyTSA37JumpMenu100 = 9;
+static const ExtraID kTinyTSA37JumpMenu101 = 10;
+static const ExtraID kTinyTSA37JumpMenu110 = 11;
+static const ExtraID kTinyTSA37JumpMenu111 = 12;
+static const ExtraID kTinyTSA37JumpToWSCMenu = 13;
+static const ExtraID kTinyTSA37CancelWSC = 14;
+static const ExtraID kTinyTSA37JumpToWSC = 15;
+static const ExtraID kTinyTSA37WSCToAI5 = 16;
+static const ExtraID kTinyTSA37PegasusAI5 = 17;
+static const ExtraID kTinyTSA37AI5ToWSC = 18;
+static const ExtraID kTinyTSA37WSCToDepart = 19;
+static const ExtraID kTinyTSA37JumpToMarsMenu = 20;
+static const ExtraID kTinyTSA37CancelMars = 21;
+static const ExtraID kTinyTSA37JumpToMars = 22;
+static const ExtraID kTinyTSA37MarsToAI6 = 23;
+static const ExtraID kTinyTSA37PegasusAI6 = 24;
+static const ExtraID kTinyTSA37AI6ToMars = 25;
+static const ExtraID kTinyTSA37MarsToDepart = 26;
+static const ExtraID kTinyTSA37JumpToNoradMenu = 27;
+static const ExtraID kTinyTSA37CancelNorad = 28;
+static const ExtraID kTinyTSA37JumpToNorad = 29;
+static const ExtraID kTinyTSA37NoradToAI7 = 30;
+static const ExtraID kTinyTSA37PegasusAI7 = 31;
+static const ExtraID kTinyTSA37AI7ToNorad = 32;
+static const ExtraID kTinyTSA37NoradToDepart = 33;
+static const ExtraID kTinyTSA37EnvironmentalScan = 34;
+static const ExtraID kTinyTSA37DownloadToMainMenu = 35;
+static const ExtraID kTinyTSA37DownloadToOpMemReview = 36;
+static const ExtraID kTinyTSA37OpMemReviewToMainMenu = 37;
+
+TinyTSA::TinyTSA(InputHandler *nextHandler, PegasusEngine *owner) : Neighborhood(nextHandler, owner, "Tiny TSA", kTinyTSAID) {
+}
+
+void TinyTSA::start() {
+ g_energyMonitor->stopEnergyDraining();
+ Neighborhood::start();
+}
+
+Common::String TinyTSA::getBriefingMovie() {
+ Common::String movieName = Neighborhood::getBriefingMovie();
+
+ if (movieName.empty()) {
+ switch (getCurrentActivation()) {
+ case kActivationTinyTSAJumpToNorad:
+ g_AIChip->showBriefingClicked();
+ startExtraSequenceSync(kTinyTSA37PegasusAI7, kHintInterruption);
+ startExtraSequenceSync(kTinyTSA37AI7ToNorad, kFilterNoInput);
+ g_AIChip->clearClicked();
+ movieName = "";
+ break;
+ case kActivationTinyTSAJumpToMars:
+ g_AIChip->showBriefingClicked();
+ startExtraSequenceSync(kTinyTSA37PegasusAI6, kHintInterruption);
+ startExtraSequenceSync(kTinyTSA37AI6ToMars, kFilterNoInput);
+ g_AIChip->clearClicked();
+ movieName = "";
+ break;
+ case kActivationTinyTSAJumpToWSC:
+ g_AIChip->showBriefingClicked();
+ startExtraSequenceSync(kTinyTSA37PegasusAI5, kHintInterruption);
+ startExtraSequenceSync(kTinyTSA37AI5ToWSC, kFilterNoInput);
+ g_AIChip->clearClicked();
+ movieName = "";
+ break;
+ default:
+ movieName = "Images/AI/TSA/XT04";
+ break;
+ }
+ }
+
+ return movieName;
+}
+
+Common::String TinyTSA::getEnvScanMovie() {
+ Common::String movieName = Neighborhood::getEnvScanMovie();
+
+ if (movieName.empty()) {
+ g_AIChip->showEnvScanClicked();
+ startExtraSequenceSync(kTinyTSA37EnvironmentalScan, kHintInterruption);
+
+ switch (getCurrentActivation()) {
+ case kActivationTinyTSAJumpToNorad:
+ startExtraSequenceSync(kTinyTSA37AI7ToNorad, kFilterNoInput);
+ showExtraView(kTinyTSA37JumpToNoradMenu);
+ break;
+ case kActivationTinyTSAJumpToMars:
+ startExtraSequenceSync(kTinyTSA37AI6ToMars, kFilterNoInput);
+ showExtraView(kTinyTSA37JumpToMarsMenu);
+ break;
+ case kActivationTinyTSAJumpToWSC:
+ startExtraSequenceSync(kTinyTSA37AI5ToWSC, kFilterNoInput);
+ showExtraView(kTinyTSA37JumpToWSCMenu);
+ break;
+ default:
+ showMainJumpMenu();
+ break;
+ }
+
+ g_AIChip->clearClicked();
+ }
+
+ return movieName;
+}
+
+void TinyTSA::loadAmbientLoops() {
+ loadLoopSound1("Sounds/TSA/T01NAE.NEW.22K.AIFF");
+}
+
+int16 TinyTSA::getStaticCompassAngle(const RoomID room, const DirectionConstant dir) {
+ return Neighborhood::getStaticCompassAngle(room, dir) - kCompassShift;
+}
+
+uint16 TinyTSA::getDateResID() const {
+ return kDate2318ID;
+}
+
+InputBits TinyTSA::getInputFilter() {
+ // Can't move forward...
+ return Neighborhood::getInputFilter() & ~(kFilterUpButton | kFilterUpAuto);
+}
+
+void TinyTSA::clickInHotspot(const Input &input, const Hotspot *clickedSpot) {
+ if (clickedSpot) {
+ switch (clickedSpot->getObjectID()) {
+ case kTinyTSA37NorthJumpMenuSpotID:
+ // This hotspot isn't accessable from Tiny TSA
+ warning("jump menu spot");
+ return;
+ case kTinyTSA37NorthJumpToNoradSpotID:
+ GameState.setTSAState(kPlayerOnWayToNorad);
+ requestExtraSequence(kTinyTSA37JumpToNorad, 0, kFilterNoInput);
+ if (!GameState.getBeenToNorad()) {
+ requestExtraSequence(kTinyTSA37NoradToAI7, 0, kFilterNoInput);
+ requestExtraSequence(kTinyTSA37PegasusAI7, 0, kFilterNoInput);
+ requestExtraSequence(kTinyTSA37AI7ToNorad, 0, kFilterNoInput);
+ GameState.setBeenToNorad(true);
+ }
+
+ requestExtraSequence(kTinyTSA37NoradToDepart, 0, kFilterNoInput);
+ requestExtraSequence(kTinyTSA37PegasusDepart, kExtraCompletedFlag, kFilterNoInput);
+ return;
+ case kTinyTSA37NorthJumpToMarsSpotID:
+ GameState.setTSAState(kPlayerOnWayToMars);
+ requestExtraSequence(kTinyTSA37JumpToMars, 0, kFilterNoInput);
+ if (!GameState.getBeenToMars()) {
+ requestExtraSequence(kTinyTSA37MarsToAI6, 0, kFilterNoInput);
+ requestExtraSequence(kTinyTSA37PegasusAI6, 0, kFilterNoInput);
+ requestExtraSequence(kTinyTSA37AI6ToMars, 0, kFilterNoInput);
+ GameState.setBeenToMars(true);
+ }
+
+ requestExtraSequence(kTinyTSA37MarsToDepart, 0, kFilterNoInput);
+ requestExtraSequence(kTinyTSA37PegasusDepart, kExtraCompletedFlag, kFilterNoInput);
+ return;
+ case kTinyTSA37NorthJumpToWSCSpotID:
+ GameState.setTSAState(kPlayerOnWayToWSC);
+ requestExtraSequence(kTinyTSA37JumpToWSC, 0, kFilterNoInput);
+ if (!GameState.getBeenToWSC()) {
+ requestExtraSequence(kTinyTSA37WSCToAI5, 0, kFilterNoInput);
+ requestExtraSequence(kTinyTSA37PegasusAI5, 0, kFilterNoInput);
+ requestExtraSequence(kTinyTSA37AI5ToWSC, 0, kFilterNoInput);
+ GameState.setBeenToWSC(true);
+ }
+
+ requestExtraSequence(kTinyTSA37WSCToDepart, 0, kFilterNoInput);
+ requestExtraSequence(kTinyTSA37PegasusDepart, kExtraCompletedFlag, kFilterNoInput);
+ return;
+ }
+ }
+
+ Neighborhood::clickInHotspot(input, clickedSpot);
+}
+
+void TinyTSA::showMainJumpMenu() {
+ ExtraID jumpMenuView = kTinyTSA37JumpMenu000;
+
+ if (GameState.getNoradFinished())
+ jumpMenuView += 4;
+ if (GameState.getMarsFinished())
+ jumpMenuView += 2;
+ if (GameState.getWSCFinished())
+ jumpMenuView += 1;
+
+ showExtraView(jumpMenuView);
+ setCurrentActivation(kActivationTinyTSAMainJumpMenu);
+}
+
+void TinyTSA::checkContinuePoint(const RoomID, const DirectionConstant) {
+ makeContinuePoint();
+}
+
+void TinyTSA::arriveAt(const RoomID room, const DirectionConstant direction) {
+ Neighborhood::arriveAt(room, direction);
+
+ switch (GameState.getTSAState()) {
+ case kPlayerOnWayToNorad:
+ case kPlayerOnWayToMars:
+ case kPlayerOnWayToWSC:
+ startExtraSequence(kTinyTSA37TimeJumpToPegasus, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kPlayerLockedInPegasus:
+ showMainJumpMenu();
+ break;
+ }
+}
+
+void TinyTSA::receiveNotification(Notification *notification, const NotificationFlags flags) {
+ ExtraID lastExtra = _lastExtra;
+
+ Neighborhood::receiveNotification(notification, flags);
+
+ if ((flags & kExtraCompletedFlag) != 0) {
+ // Only allow input if we're not in the middle of series of queue requests.
+ if (actionQueueEmpty())
+ _interruptionFilter = kFilterAllInput;
+
+ switch (lastExtra) {
+ case kTinyTSA37PegasusDepart:
+ _vm->setLastEnergyValue(kFullEnergy);
+
+ switch (GameState.getTSAState()) {
+ case kPlayerOnWayToNorad:
+ _vm->jumpToNewEnvironment(kNoradAlphaID, kNorad01, kSouth);
+ GameState.setNoradSeenTimeStream(false);
+ GameState.setNoradGassed(true);
+ GameState.setNoradFillingStationOn(false);
+ GameState.setNoradN22MessagePlayed(false);
+ GameState.setNoradPlayedGlobeGame(false);
+ GameState.setNoradBeatRobotWithClaw(false);
+ GameState.setNoradBeatRobotWithDoor(false);
+ GameState.setNoradRetScanGood(false);
+ GameState.setNoradWaitingForLaser(false);
+ GameState.setNoradSubRoomPressure(9);
+ GameState.setNoradSubPrepState(kSubNotPrepped);
+ break;
+ case kPlayerOnWayToMars:
+ _vm->jumpToNewEnvironment(kMarsID, kMars0A, kNorth);
+ GameState.setMarsSeenTimeStream(false);
+ GameState.setMarsHeardUpperPodMessage(false);
+ GameState.setMarsRobotThrownPlayer(false);
+ GameState.setMarsHeardCheckInMessage(false);
+ GameState.setMarsPodAtUpperPlatform(false);
+ GameState.setMarsSeenThermalScan(false);
+ GameState.setMarsArrivedBelow(false);
+ GameState.setMarsSeenRobotAtReactor(false);
+ GameState.setMarsAvoidedReactorRobot(false);
+ GameState.setMarsLockFrozen(false);
+ GameState.setMarsLockBroken(false);
+ GameState.setMarsSecurityDown(false);
+ GameState.setMarsAirlockOpen(false);
+ GameState.setMarsReadyForShuttleTransport(false);
+ GameState.setMarsFinishedCanyonChase(false);
+ GameState.setMarsThreadedMaze(false);
+ break;
+ case kPlayerOnWayToWSC:
+ _vm->jumpToNewEnvironment(kWSCID, kWSC01, kWest);
+ GameState.setWSCSeenTimeStream(false);
+ GameState.setWSCPoisoned(false);
+ GameState.setWSCAnsweredAboutDart(false);
+ GameState.setWSCDartInAnalyzer(false);
+ GameState.setWSCRemovedDart(false);
+ GameState.setWSCAnalyzerOn(false);
+ GameState.setWSCAnalyzedDart(false);
+ GameState.setWSCPickedUpAntidote(false);
+ GameState.setWSCSawMorph(false);
+ GameState.setWSCDesignedAntidote(false);
+ GameState.setWSCOfficeMessagesOpen(false);
+ GameState.setWSCSeenNerd(false);
+ GameState.setWSCHeardPage1(false);
+ GameState.setWSCHeardPage2(false);
+ GameState.setWSCHeardCheckIn(false);
+ GameState.setWSCDidPlasmaDodge(false);
+ GameState.setWSCSeenSinclairLecture(false);
+ GameState.setWSCBeenAtWSC93(false);
+ GameState.setWSCCatwalkDark(false);
+ GameState.setWSCRobotDead(false);
+ GameState.setWSCRobotGone(false);
+ break;
+ };
+ break;
+ case kTinyTSA37TimeJumpToPegasus:
+ if (g_energyMonitor)
+ g_energyMonitor->stopEnergyDraining();
+
+ switch (GameState.getTSAState()) {
+ case kPlayerOnWayToNorad:
+ arriveFromNorad();
+ break;
+ case kPlayerOnWayToMars:
+ arriveFromMars();
+ break;
+ case kPlayerOnWayToWSC:
+ arriveFromWSC();
+ break;
+ default:
+ break;
+ }
+ break;
+ case kTinyTSA37DownloadToOpMemReview:
+ switch (GameState.getTSAState()) {
+ case kPlayerOnWayToNorad:
+ g_opticalChip->playOpMemMovie(kPoseidonSpotID);
+ break;
+ case kPlayerOnWayToMars:
+ g_opticalChip->playOpMemMovie(kAriesSpotID);
+ break;
+ case kPlayerOnWayToWSC:
+ g_opticalChip->playOpMemMovie(kMercurySpotID);
+ break;
+ }
+
+ requestExtraSequence(kTinyTSA37OpMemReviewToMainMenu, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kTinyTSA37DownloadToMainMenu:
+ case kTinyTSA37OpMemReviewToMainMenu:
+ GameState.setTSAState(kPlayerLockedInPegasus);
+ showMainJumpMenu();
+ makeContinuePoint();
+ break;
+ case kTinyTSA37JumpToNoradMenu:
+ setCurrentActivation(kActivationTinyTSAJumpToNorad);
+ break;
+ case kTinyTSA37JumpToMarsMenu:
+ setCurrentActivation(kActivationTinyTSAJumpToMars);
+ break;
+ case kTinyTSA37JumpToWSCMenu:
+ setCurrentActivation(kActivationTinyTSAJumpToWSC);
+ break;
+ case kTinyTSA37CancelNorad:
+ case kTinyTSA37CancelMars:
+ case kTinyTSA37CancelWSC:
+ showMainJumpMenu();
+ break;
+ }
+ }
+
+ g_AIArea->checkMiddleArea();
+}
+
+void TinyTSA::arriveFromNorad() {
+ requestExtraSequence(kTinyTSA37RecallToDownload, 0, kFilterNoInput);
+
+ if (GameState.getNoradFinished() && !GameState.getScoringFinishedNorad()) {
+ GameState.setScoringFinishedNorad();
+ requestExtraSequence(kTinyTSA37DownloadToOpMemReview, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ requestExtraSequence(kTinyTSA37DownloadToMainMenu, kExtraCompletedFlag, kFilterNoInput);
+ }
+}
+
+void TinyTSA::arriveFromMars() {
+ requestExtraSequence(kTinyTSA37RecallToDownload, 0, kFilterNoInput);
+
+ if (GameState.getMarsFinished() && !GameState.getScoringFinishedMars()) {
+ GameState.setScoringFinishedMars();
+ requestExtraSequence(kTinyTSA37DownloadToOpMemReview, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ requestExtraSequence(kTinyTSA37DownloadToMainMenu, kExtraCompletedFlag, kFilterNoInput);
+ }
+}
+
+void TinyTSA::arriveFromWSC() {
+ requestExtraSequence(kTinyTSA37RecallToDownload, 0, kFilterNoInput);
+
+ if (GameState.getWSCFinished() && !GameState.getScoringFinishedWSC()) {
+ GameState.setScoringFinishedWSC();
+ requestExtraSequence(kTinyTSA37DownloadToOpMemReview, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ requestExtraSequence(kTinyTSA37DownloadToMainMenu, kExtraCompletedFlag, kFilterNoInput);
+ }
+}
+
+Common::String TinyTSA::getNavMovieName() {
+ return "Images/TSA/Tiny TSA.movie";
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/tsa/tinytsa.h b/engines/pegasus/neighborhood/tsa/tinytsa.h
new file mode 100644
index 0000000000..2dc234675d
--- /dev/null
+++ b/engines/pegasus/neighborhood/tsa/tinytsa.h
@@ -0,0 +1,71 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_TSA_TINYTSA_H
+#define PEGASUS_NEIGHBORHOOD_TSA_TINYTSA_H
+
+#include "pegasus/neighborhood/neighborhood.h"
+
+namespace Pegasus {
+
+// Room IDs.
+
+static const RoomID kTinyTSA37 = 0;
+
+class TinyTSA : public Neighborhood {
+public:
+ TinyTSA(InputHandler *, PegasusEngine *);
+ virtual ~TinyTSA() {}
+
+ virtual uint16 getDateResID() const;
+
+ void start();
+
+ void checkContinuePoint(const RoomID, const DirectionConstant);
+
+protected:
+ Common::String getBriefingMovie();
+ Common::String getEnvScanMovie();
+ void loadAmbientLoops();
+ virtual void clickInHotspot(const Input &, const Hotspot *);
+
+ virtual int16 getStaticCompassAngle(const RoomID, const DirectionConstant);
+
+ void arriveFromNorad();
+ void arriveFromMars();
+ void arriveFromWSC();
+
+ InputBits getInputFilter();
+ void arriveAt(const RoomID, const DirectionConstant);
+ void showMainJumpMenu();
+ void receiveNotification(Notification *, const NotificationFlags);
+
+ Common::String getNavMovieName();
+ Common::String getSoundSpotsName() { return ""; }
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/turn.cpp b/engines/pegasus/neighborhood/turn.cpp
new file mode 100644
index 0000000000..1157796f55
--- /dev/null
+++ b/engines/pegasus/neighborhood/turn.cpp
@@ -0,0 +1,63 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/debug.h"
+#include "common/stream.h"
+#include "common/textconsole.h"
+
+#include "pegasus/neighborhood/turn.h"
+
+namespace Pegasus {
+
+void TurnTable::loadFromStream(Common::SeekableReadStream *stream) {
+ uint32 count = stream->readUint32BE();
+ _entries.resize(count);
+
+ for (uint32 i = 0; i < count; i++) {
+ _entries[i].room = stream->readUint16BE();
+ _entries[i].direction = stream->readByte();
+ _entries[i].turnDirection = stream->readByte();
+ _entries[i].altCode = stream->readByte();
+ stream->readByte(); // alignment
+ _entries[i].endDirection = stream->readByte();
+ stream->readByte(); // alignment
+ debug(0, "Turn[%d]: %d %d %d %d %d", i, _entries[i].room, _entries[i].direction,
+ _entries[i].turnDirection, _entries[i].altCode, _entries[i].endDirection);
+ }
+}
+
+void TurnTable::clear() {
+ _entries.clear();
+}
+
+TurnTable::Entry TurnTable::findEntry(RoomID room, DirectionConstant direction, TurnDirection turnDirection, AlternateID altCode) {
+ for (uint32 i = 0; i < _entries.size(); i++)
+ if (_entries[i].room == room && _entries[i].direction == direction && _entries[i].turnDirection == turnDirection && _entries[i].altCode == altCode)
+ return _entries[i];
+
+ return Entry();
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/turn.h b/engines/pegasus/neighborhood/turn.h
new file mode 100644
index 0000000000..329b03eddb
--- /dev/null
+++ b/engines/pegasus/neighborhood/turn.h
@@ -0,0 +1,69 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_TURN_H
+#define PEGASUS_NEIGHBORHOOD_TURN_H
+
+#include "common/array.h"
+#include "common/endian.h"
+
+#include "pegasus/constants.h"
+
+namespace Common {
+ class SeekableReadStream;
+}
+
+namespace Pegasus {
+
+class TurnTable {
+public:
+ TurnTable() {}
+ ~TurnTable() {}
+
+ static uint32 getResTag() { return MKTAG('T', 'u', 'r', 'n'); }
+
+ void loadFromStream(Common::SeekableReadStream *stream);
+ void clear();
+
+ struct Entry {
+ Entry() { endDirection = kNoDirection; }
+ bool isEmpty() { return endDirection == kNoDirection; }
+
+ RoomID room;
+ DirectionConstant direction;
+ TurnDirection turnDirection;
+ AlternateID altCode;
+ DirectionConstant endDirection;
+ };
+
+ Entry findEntry(RoomID room, DirectionConstant direction, TurnDirection turnDirection, AlternateID altCode);
+
+private:
+ Common::Array<Entry> _entries;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/view.cpp b/engines/pegasus/neighborhood/view.cpp
new file mode 100644
index 0000000000..4e46f5374e
--- /dev/null
+++ b/engines/pegasus/neighborhood/view.cpp
@@ -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.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/debug.h"
+#include "common/stream.h"
+#include "common/textconsole.h"
+
+#include "pegasus/neighborhood/view.h"
+
+namespace Pegasus {
+
+void ViewTable::loadFromStream(Common::SeekableReadStream *stream) {
+ uint32 count = stream->readUint32BE();
+ _entries.resize(count);
+
+ for (uint32 i = 0; i < count; i++) {
+ _entries[i].room = stream->readUint16BE();
+ _entries[i].direction = stream->readByte();
+ _entries[i].altCode = stream->readByte();
+ _entries[i].time = stream->readUint32BE();
+ debug(0, "View[%d]: %d %d %d %d", i, _entries[i].room, _entries[i].direction,
+ _entries[i].altCode, _entries[i].time);
+ }
+}
+
+void ViewTable::clear() {
+ _entries.clear();
+}
+
+ViewTable::Entry ViewTable::findEntry(RoomID room, DirectionConstant direction, AlternateID altCode) {
+ for (uint32 i = 0; i < _entries.size(); i++)
+ if (_entries[i].room == room && _entries[i].direction == direction && _entries[i].altCode == altCode)
+ return _entries[i];
+
+ return Entry();
+}
+
+} // End of namespace pegasus
diff --git a/engines/pegasus/neighborhood/view.h b/engines/pegasus/neighborhood/view.h
new file mode 100644
index 0000000000..3397508b61
--- /dev/null
+++ b/engines/pegasus/neighborhood/view.h
@@ -0,0 +1,68 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_VIEW_H
+#define PEGASUS_NEIGHBORHOOD_VIEW_H
+
+#include "common/array.h"
+#include "common/endian.h"
+
+#include "pegasus/constants.h"
+
+namespace Common {
+ class SeekableReadStream;
+}
+
+namespace Pegasus {
+
+class ViewTable {
+public:
+ ViewTable() {}
+ ~ViewTable() {}
+
+ static uint32 getResTag() { return MKTAG('V', 'i', 'e', 'w'); }
+
+ void loadFromStream(Common::SeekableReadStream *stream);
+ void clear();
+
+ struct Entry {
+ Entry() { time = 0xffffffff; }
+ bool isEmpty() { return time == 0xffffffff; }
+
+ RoomID room;
+ DirectionConstant direction;
+ AlternateID altCode;
+ TimeValue time;
+ };
+
+ Entry findEntry(RoomID room, DirectionConstant direction, AlternateID altCode);
+
+private:
+ Common::Array<Entry> _entries;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/wsc/moleculebin.cpp b/engines/pegasus/neighborhood/wsc/moleculebin.cpp
new file mode 100644
index 0000000000..210c0ad313
--- /dev/null
+++ b/engines/pegasus/neighborhood/wsc/moleculebin.cpp
@@ -0,0 +1,127 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/graphics.h"
+#include "pegasus/neighborhood/wsc/moleculebin.h"
+#include "pegasus/neighborhood/wsc/wsc.h"
+
+namespace Pegasus {
+
+static const CoordType kMoleculeBinWidth = 138;
+static const CoordType kMoleculeBinHeight = 128;
+
+static const CoordType kMoleculeWidth = 66;
+static const CoordType kMoleculeHeight = 40;
+
+static const CoordType kMoleculeBinLeft = kNavAreaLeft + 286;
+static const CoordType kMoleculeBinTop = kNavAreaLeft + 96;
+
+// Layouts:
+
+MoleculeBin::MoleculeBin() : DisplayElement(kNoDisplayElement) {
+ _highlightColor = g_system->getScreenFormat().RGBToColor(0xff, 0xff, 102);
+ _selectedMolecule = -1;
+}
+
+void MoleculeBin::initMoleculeBin() {
+ if (!isDisplaying()) {
+ for (int i = 0; i < 6; i++)
+ _binLayout[i] = i;
+
+ resetBin();
+ _binImages.getImageFromPICTFile("Images/World Science Center/Molecules");
+ setDisplayOrder(kWSCMoleculeBinOrder);
+ setBounds(kMoleculeBinLeft, kMoleculeBinTop, kMoleculeBinLeft + kMoleculeBinWidth,
+ kMoleculeBinTop + kMoleculeBinHeight);
+ startDisplaying();
+ show();
+ }
+}
+
+void MoleculeBin::cleanUpMoleculeBin() {
+ if (isDisplaying()) {
+ stopDisplaying();
+ _binImages.deallocateSurface();
+ }
+}
+
+void MoleculeBin::setBinLayout(const uint32 *layout) {
+ for (int i = 0; i < 6; i++)
+ _binLayout[i] = layout[i];
+}
+
+void MoleculeBin::highlightMolecule(const uint32 whichMolecule) {
+ if (!_moleculeFlags.getFlag(whichMolecule)) {
+ _moleculeFlags.setFlag(whichMolecule, true);
+ triggerRedraw();
+ }
+}
+
+bool MoleculeBin::isMoleculeHighlighted(uint32 whichMolecule) {
+ return _moleculeFlags.getFlag(whichMolecule);
+}
+
+void MoleculeBin::selectMolecule(const int whichMolecule) {
+ if (_selectedMolecule != whichMolecule) {
+ _selectedMolecule = whichMolecule;
+ triggerRedraw();
+ }
+}
+
+void MoleculeBin::resetBin() {
+ _moleculeFlags.clearAllFlags();
+ _selectedMolecule = -1;
+ triggerRedraw();
+}
+
+void MoleculeBin::draw(const Common::Rect &) {
+ Common::Rect r1(0, 0, kMoleculeWidth, kMoleculeHeight);
+ Common::Rect r2 = r1;
+
+ for (int i = 0; i < 6; i++) {
+ r1.moveTo(i * (kMoleculeWidth * 2), 0);
+
+ if (_moleculeFlags.getFlag(_binLayout[i]))
+ r1.translate(kMoleculeWidth, 0);
+
+ r2.moveTo((_binLayout[i] & 1) * (kMoleculeWidth + 2) + _bounds.left + 2,
+ (_binLayout[i] >> 1) * (kMoleculeHeight + 2) + _bounds.top + 2);
+
+ _binImages.copyToCurrentPort(r1, r2);
+ }
+
+ if (_selectedMolecule >= 0) {
+ r2.moveTo((_selectedMolecule & 1) * (kMoleculeWidth + 2) + _bounds.left + 2,
+ (_selectedMolecule >> 1) * (kMoleculeHeight + 2) + _bounds.top + 2);
+
+ Graphics::Surface *screen = ((PegasusEngine *)g_engine)->_gfx->getWorkArea();
+
+ screen->frameRect(r2, _highlightColor);
+ r2.grow(1);
+ screen->frameRect(r2, _highlightColor);
+ }
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/wsc/moleculebin.h b/engines/pegasus/neighborhood/wsc/moleculebin.h
new file mode 100644
index 0000000000..3de4b5ed2a
--- /dev/null
+++ b/engines/pegasus/neighborhood/wsc/moleculebin.h
@@ -0,0 +1,72 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_WSC_MOLECULEBIN_H
+#define PEGASUS_NEIGHBORHOOD_WSC_MOLECULEBIN_H
+
+#include "pegasus/elements.h"
+#include "pegasus/surface.h"
+#include "pegasus/util.h"
+
+namespace Pegasus {
+
+enum {
+ kMolecule1,
+ kMolecule2,
+ kMolecule3,
+ kMolecule4,
+ kMolecule5,
+ kMolecule6
+};
+
+class MoleculeBin : public DisplayElement {
+public:
+ MoleculeBin();
+ virtual ~MoleculeBin() {}
+
+ void initMoleculeBin();
+ void cleanUpMoleculeBin();
+
+ void setBinLayout(const uint32 *);
+
+ void highlightMolecule(const uint32 whichMolecule);
+ void selectMolecule(const int whichMolecule);
+ void resetBin();
+
+ bool isMoleculeHighlighted(uint32);
+
+protected:
+ void draw(const Common::Rect &);
+
+ Surface _binImages;
+ FlagsArray<byte, kMolecule6 + 1> _moleculeFlags;
+ int _selectedMolecule;
+ uint32 _binLayout[6];
+ uint32 _highlightColor;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/wsc/wsc.cpp b/engines/pegasus/neighborhood/wsc/wsc.cpp
new file mode 100644
index 0000000000..50b7774da4
--- /dev/null
+++ b/engines/pegasus/neighborhood/wsc/wsc.cpp
@@ -0,0 +1,2546 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/energymonitor.h"
+#include "pegasus/gamestate.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/biochips/opticalchip.h"
+#include "pegasus/items/biochips/shieldchip.h"
+#include "pegasus/neighborhood/wsc/wsc.h"
+
+namespace Pegasus {
+
+static const CanMoveForwardReason kCantMoveWatchingDiagnosis = kCantMoveLastReason + 1;
+
+static const CanTurnReason kCantTurnWatchingDiagnosis = kCantTurnLastReason + 1;
+static const CanTurnReason kCantTurnWatchingAnalysis = kCantTurnWatchingDiagnosis + 1;
+static const CanTurnReason kCantTurnInMoleculeGame = kCantTurnWatchingAnalysis + 1;
+
+static const TimeScale kMoleculesMovieScale = 600;
+static const TimeValue kMoleculeLoopTime = 4 * kMoleculesMovieScale;
+static const TimeValue kMoleculeFailTime = 2 * kMoleculesMovieScale;
+
+enum {
+ kMoleculeLoop0Time = 0,
+ kMoleculeFail0Time = kMoleculeLoop0Time + kMoleculeLoopTime,
+ kMoleculeLoop1Time = kMoleculeFail0Time + kMoleculeFailTime,
+ kMoleculeFail1Time = kMoleculeLoop1Time + kMoleculeLoopTime,
+ kMoleculeLoop2Time = kMoleculeFail1Time + kMoleculeFailTime,
+ kMoleculeFail2Time = kMoleculeLoop2Time + kMoleculeLoopTime,
+ kMoleculeLoop3Time = kMoleculeFail2Time + kMoleculeFailTime,
+ kMoleculeFail3Time = kMoleculeLoop3Time + kMoleculeLoopTime,
+ kMoleculeLoop4Time = kMoleculeFail3Time + kMoleculeFailTime,
+ kMoleculeFail4Time = kMoleculeLoop4Time + kMoleculeLoopTime,
+ kMoleculeLoop5Time = kMoleculeFail4Time + kMoleculeFailTime,
+ kMoleculeFail5Time = kMoleculeLoop5Time + kMoleculeLoopTime,
+ kMoleculeLoop6Time = kMoleculeFail5Time + kMoleculeFailTime
+};
+
+static const TimeValue s_moleculeLoopTimes[] = {
+ kMoleculeLoop0Time,
+ kMoleculeLoop1Time,
+ kMoleculeLoop2Time,
+ kMoleculeLoop3Time,
+ kMoleculeLoop4Time,
+ kMoleculeLoop5Time,
+ kMoleculeLoop6Time
+};
+
+static const TimeValue s_moleculeFailTimes[] = {
+ kMoleculeFail0Time,
+ kMoleculeFail1Time,
+ kMoleculeFail2Time,
+ kMoleculeFail3Time,
+ kMoleculeFail4Time,
+ kMoleculeFail5Time
+};
+
+static const int16 kAuditoriumAngleOffset = 5;
+
+static const int kPlasmaEnergyWithShield = kMaxJMPEnergy * 10 / 100;
+static const int kPlasmaEnergyNoShield = kMaxJMPEnergy * 20 / 100;
+
+static const int kTimerEventPlasmaHit = 0;
+static const int kTimerEventPlayerGawkingAtRobot = 1;
+static const int kTimerEventPlayerGawkingAtRobot2 = 2;
+
+static const TimeValue kWSCMolecule1In = 0;
+static const TimeValue kWSCMolecule1Out = 937;
+
+static const TimeValue kWSCMolecule2In = 937;
+static const TimeValue kWSCMolecule2Out = 1864;
+
+static const TimeValue kWSCMolecule3In = 1864;
+static const TimeValue kWSCMolecule3Out = 2790;
+
+static const TimeValue kWSCClick1In = 2790;
+static const TimeValue kWSCClick1Out = 2890;
+
+static const TimeValue kWSCClick2In = 2890;
+static const TimeValue kWSCClick2Out = 3059;
+
+static const TimeValue kWSCClick3In = 3059;
+static const TimeValue kWSCClick3Out = 3156;
+
+static const TimeValue kWSCFlashlightClickIn = 3156;
+static const TimeValue kWSCFlashlightClickOut = 3211;
+
+static const TimeValue kWSCBumpIntoWallIn = 3211;
+static const TimeValue kWSCBumpIntoWallOut = 3514;
+
+static const TimeValue kWSCCantTransportIn = 3514;
+static const TimeValue kWSCCantTransportOut = 7791;
+
+static const TimeValue kHernandezNotHomeIn = 7791;
+static const TimeValue kHernandezNotHomeOut = 10199;
+
+static const TimeValue kWashingtonNotHomeIn = 10199;
+static const TimeValue kWashingtonNotHomeOut = 12649;
+
+static const TimeValue kSullivanNotHomeIn = 12649;
+static const TimeValue kSullivanNotHomeOut = 15031;
+
+static const TimeValue kNakamuraNotHomeIn = 15031;
+static const TimeValue kNakamuraNotHomeOut = 17545;
+
+static const TimeValue kGrailisNotHomeIn = 17545;
+static const TimeValue kGrailisNotHomeOut = 19937;
+
+static const TimeValue kTheriaultNotHomeIn = 19937;
+static const TimeValue kTheriaultNotHomeOut = 22395;
+
+static const TimeValue kGlennerNotHomeIn = 22395;
+static const TimeValue kGlennerNotHomeOut = 24770;
+
+static const TimeValue kSinclairNotHomeIn = 24770;
+static const TimeValue kSinclairNotHomeOut = 27328;
+
+static const TimeValue kWSCLabClosedIn = 27328;
+static const TimeValue kWSCLabClosedOut = 28904;
+
+static const TimeValue kSlidingDoorCloseIn = 28904;
+static const TimeValue kSlidingDoorCloseOut = 29295;
+
+static const TimeValue kSlimyDoorCloseIn = 29295;
+static const TimeValue kSlimyDoorCloseOut = 29788;
+
+static const TimeValue kPaging1In = 29788;
+static const TimeValue kPaging1Out = 32501;
+
+static const TimeValue kPaging2In = 32501;
+static const TimeValue kPaging2Out = 34892;
+
+static const TimeValue kCheckInIn = 34892;
+static const TimeValue kCheckInOut = 37789;
+
+static const TimeValue kDrinkAntidoteIn = 37789;
+static const TimeValue kDrinkAntidoteOut = 39725;
+
+static const TimeScale kWSCMovieScale = 600;
+static const TimeScale kWSCFramesPerSecond = 15;
+static const TimeScale kWSCFrameDuration = 40;
+
+// Alternate IDs.
+static const AlternateID kAltWSCNormal = 0;
+static const AlternateID kAltWSCTookMachineGun = 1;
+static const AlternateID kAltWSCW0ZDoorOpen = 2;
+static const AlternateID kAltWSCPeopleAtW19North = 3;
+
+// Room IDs.
+static const RoomID kWSC02 = 1;
+static const RoomID kWSC03 = 4;
+static const RoomID kWSC04 = 5;
+static const RoomID kWSC06 = 6;
+static const RoomID kWSC07 = 7;
+static const RoomID kWSC08 = 8;
+static const RoomID kWSC09 = 9;
+static const RoomID kWSC10 = 10;
+static const RoomID kWSC11 = 11;
+static const RoomID kWSC13 = 12;
+static const RoomID kWSC14 = 13;
+static const RoomID kWSC15 = 14;
+static const RoomID kWSC16 = 15;
+static const RoomID kWSC17 = 16;
+static const RoomID kWSC18 = 17;
+static const RoomID kWSC19 = 18;
+static const RoomID kWSC20 = 19;
+static const RoomID kWSC21 = 20;
+static const RoomID kWSC22 = 21;
+static const RoomID kWSC23 = 22;
+static const RoomID kWSC24 = 23;
+static const RoomID kWSC25 = 24;
+static const RoomID kWSC26 = 25;
+static const RoomID kWSC27 = 26;
+static const RoomID kWSC28 = 27;
+static const RoomID kWSC29 = 28;
+static const RoomID kWSC31 = 29;
+static const RoomID kWSC32 = 30;
+static const RoomID kWSC33 = 31;
+static const RoomID kWSC34 = 32;
+static const RoomID kWSC35 = 33;
+static const RoomID kWSC36 = 34;
+static const RoomID kWSC37 = 35;
+static const RoomID kWSC38 = 36;
+static const RoomID kWSC39 = 37;
+static const RoomID kWSC40 = 38;
+static const RoomID kWSC41 = 39;
+static const RoomID kWSC42 = 40;
+static const RoomID kWSC43 = 41;
+static const RoomID kWSC44 = 42;
+static const RoomID kWSC45 = 43;
+static const RoomID kWSC46 = 44;
+static const RoomID kWSC47 = 45;
+static const RoomID kWSC48 = 46;
+static const RoomID kWSC49 = 47;
+static const RoomID kWSC50 = 48;
+static const RoomID kWSC52 = 49;
+static const RoomID kWSC53 = 50;
+static const RoomID kWSC54 = 51;
+static const RoomID kWSC55 = 52;
+static const RoomID kWSC56 = 53;
+static const RoomID kWSC57 = 54;
+static const RoomID kWSC58 = 55;
+static const RoomID kWSC60 = 56;
+static const RoomID kWSC60East = 57;
+static const RoomID kWSC60North = 58;
+static const RoomID kWSC61 = 59;
+static const RoomID kWSC61South = 60;
+static const RoomID kWSC61West = 61;
+static const RoomID kWSC63 = 63;
+static const RoomID kWSC64 = 64;
+static const RoomID kWSC65 = 65;
+static const RoomID kWSC65Screen = 66;
+static const RoomID kWSC66 = 67;
+static const RoomID kWSC67 = 68;
+static const RoomID kWSC68 = 69;
+static const RoomID kWSC69 = 70;
+static const RoomID kWSC70 = 71;
+static const RoomID kWSC71 = 72;
+static const RoomID kWSC72 = 73;
+static const RoomID kWSC73 = 74;
+static const RoomID kWSC74 = 75;
+static const RoomID kWSC75 = 76;
+static const RoomID kWSC0Z = 77;
+static const RoomID kWSC76 = 78;
+static const RoomID kWSC77 = 79;
+static const RoomID kWSC78 = 80;
+static const RoomID kWSC79 = 81;
+static const RoomID kWSC80 = 82;
+static const RoomID kWSC81 = 83;
+static const RoomID kWSC82 = 84;
+static const RoomID kWSC83 = 85;
+static const RoomID kWSC84 = 86;
+static const RoomID kWSC85 = 87;
+static const RoomID kWSC86 = 88;
+static const RoomID kWSC87 = 89;
+static const RoomID kWSC88 = 90;
+static const RoomID kWSC89 = 91;
+static const RoomID kWSC90 = 92;
+static const RoomID kWSC91 = 93;
+static const RoomID kWSC92 = 94;
+static const RoomID kWSC93 = 95;
+static const RoomID kWSC94 = 96;
+static const RoomID kWSC95 = 97;
+static const RoomID kWSC96 = 98;
+static const RoomID kWSC97 = 99;
+static const RoomID kWSC98 = 100;
+static const RoomID kWSCDeathRoom = 101;
+
+// Hot Spot Activation IDs.
+static const HotSpotActivationID kActivationZoomedInToAnalyzer = 1;
+static const HotSpotActivationID kActivationShotByRobot = 2;
+static const HotSpotActivationID kActivationWarnedAboutPoison = 3;
+static const HotSpotActivationID kActivationMorphScreenOff = 4;
+static const HotSpotActivationID kActivationReadyForMorph = 5;
+static const HotSpotActivationID kActivationMorphLooping = 6;
+static const HotSpotActivationID kActivationMorphInterrupted = 7;
+static const HotSpotActivationID kActivationW03NorthOff = 8;
+static const HotSpotActivationID kActivationW03NorthReadyForInstructions = 9;
+static const HotSpotActivationID kActivationW03NorthSawInstructions = 10;
+static const HotSpotActivationID kActivationW03NorthInGame = 11;
+static const HotSpotActivationID kActivationReadyForSynthesis = 12;
+static const HotSpotActivationID kActivationSynthesizerLooping = 13;
+static const HotSpotActivationID kActivationReadyForMap = 14;
+static const HotSpotActivationID kActivationSinclairOfficeLocked = 15;
+static const HotSpotActivationID kActivationW58SouthDoorLocked = 16;
+static const HotSpotActivationID kActivationW61SouthOff = 17;
+static const HotSpotActivationID kActivationW61SouthOn = 18;
+static const HotSpotActivationID kActivationW61MessagesOff = 19;
+static const HotSpotActivationID kActivationW61MessagesOn = 20;
+static const HotSpotActivationID kActivationWSCRobotHeadOpen = 21;
+static const HotSpotActivationID kActivationRobotTurning = 22;
+static const HotSpotActivationID kActivationRobotDead = 23;
+static const HotSpotActivationID kActivationRobotGone = 24;
+
+// Hot Spot IDs.
+static const HotSpotID kWSCDropDartSpotID = 5000;
+static const HotSpotID kWSCTurnOnAnalyzerSpotID = 5001;
+static const HotSpotID kWSCAnalyzerScreenSpotID = 5002;
+static const HotSpotID kWSCSpinRobotSpotID = 5003;
+static const HotSpotID kWSC01YesSpotID = 5004;
+static const HotSpotID kWSC01NoSpotID = 5005;
+static const HotSpotID kWSC01AcknowledgeWarningSpotID = 5006;
+static const HotSpotID kWSC02SouthMorphSpotID = 5007;
+static const HotSpotID kWSC02SouthMessagesSpotID = 5008;
+static const HotSpotID kWSC02SouthMorphOutSpotID = 5009;
+static const HotSpotID kWSC02ActivateMorphScreenSpotID = 5010;
+static const HotSpotID kWSC02SouthStartMorphSpotID = 5011;
+static const HotSpotID kWSC02SouthInterruptMorphSpotID = 5012;
+static const HotSpotID kWSC02SouthMorphFinishedSpotID = 5013;
+static const HotSpotID kWSC02SouthTakeArgonSpotID = 5014;
+static const HotSpotID kWSC02SouthMessagesOutSpotID = 5015;
+static const HotSpotID kWSC02SouthTakeNitrogenSpotID = 5016;
+static const HotSpotID kWSC02SouthPlayMessagesSpotID = 5017;
+static const HotSpotID kWSC03NorthActivateScreenSpotID = 5018;
+static const HotSpotID kWSC03NorthBuildMoleculeSpotID = 5019;
+static const HotSpotID kWSC03NorthProceedSpotID = 5020;
+static const HotSpotID kWSC03NorthMolecule1SpotID = 5021;
+static const HotSpotID kWSC03NorthMolecule2SpotID = 5022;
+static const HotSpotID kWSC03NorthMolecule3SpotID = 5023;
+static const HotSpotID kWSC03NorthMolecule4SpotID = 5024;
+static const HotSpotID kWSC03NorthMolecule5SpotID = 5025;
+static const HotSpotID kWSC03NorthMolecule6SpotID = 5026;
+static const HotSpotID kWSC03SouthActivateSynthesizerSpotID = 5027;
+static const HotSpotID kWSC03SouthPickUpAntidoteSpotID = 5028;
+static const HotSpotID kWSC07SouthMapSpotID = 5029;
+static const HotSpotID kW42EastUnlockDoorSpotID = 5030;
+static const HotSpotID kW56NorthMapSpotID = 5031;
+static const HotSpotID kW58SouthPryDoorSpotID = 5032;
+static const HotSpotID kWSC60EastSpotID = 5033;
+static const HotSpotID kWSC60NorthSpotID = 5034;
+static const HotSpotID kWSC60EastOutSpotID = 5035;
+static const HotSpotID kWSC60NorthOutSpotID = 5036;
+static const HotSpotID kWSC61EastSpotID = 5037;
+static const HotSpotID kWSC61SouthSpotID = 5038;
+static const HotSpotID kW61SouthMachineGunSpotID = 5039;
+static const HotSpotID kW61SouthDropMachineGunSpotID = 5040;
+static const HotSpotID kWSC61WestSpotID = 5041;
+static const HotSpotID kWSC61SouthOutSpotID = 5042;
+static const HotSpotID kW61SouthActivateSpotID = 5043;
+static const HotSpotID kW61SmartAlloysSpotID = 5044;
+static const HotSpotID kW61MorphingSpotID = 5045;
+static const HotSpotID kW61TimeBendingSpotID = 5046;
+static const HotSpotID kWSC61WestOutSpotID = 5047;
+static const HotSpotID kW61TurnOnMessagesSpotID = 5048;
+static const HotSpotID kW61WhiteMessageSpotID = 5049;
+static const HotSpotID kW61WalchekMessageSpotID = 5050;
+static const HotSpotID kWSC65SouthScreenSpotID = 5051;
+static const HotSpotID kWSC65SouthScreenOutSpotID = 5052;
+static const HotSpotID kW98RetinalChipSpotID = 5053;
+static const HotSpotID kW98MapChipSpotID = 5054;
+static const HotSpotID kW98OpticalChipSpotID = 5055;
+static const HotSpotID kW98DropArgonSpotID = 5056;
+static const HotSpotID kW98GrabCableSpotID = 5057;
+static const HotSpotID kW98OpenRobotSpotID = 5058;
+static const HotSpotID kW98StunGunSpotID = 5059;
+
+// Extra sequence IDs.
+static const ExtraID kWSCArrivalFromTSA = 0;
+static const ExtraID kWSCShotByRobot = 1;
+static const ExtraID kWSCDartScan1 = 2;
+static const ExtraID kWSCDartScan2 = 3;
+static const ExtraID kWSCDartScanNo = 4;
+static const ExtraID kWSCDartScan3 = 5;
+static const ExtraID kWSCAnalyzerPowerUp = 6;
+static const ExtraID kWSCAnalyzerPowerUpWithDart = 7;
+static const ExtraID kWSCDropDartIntoAnalyzer = 8;
+static const ExtraID kWSCAnalyzeDart = 9;
+static const ExtraID kWSCZoomOutFromAnalyzer = 10;
+static const ExtraID kWSCSpinRobot = 11;
+static const ExtraID kWSC02MorphZoomNoArgon = 12;
+static const ExtraID kWSC02MessagesZoomNoNitrogen = 13;
+static const ExtraID kWSC02ZoomOutNoArgon = 14;
+static const ExtraID kWSC02TurnOnMorphScreen = 15;
+static const ExtraID kWSC02DropToMorphExperiment = 16;
+static const ExtraID kWSC02MorphLoop = 17;
+static const ExtraID kWSC02MorphInterruption = 18;
+static const ExtraID kWSC02MorphFinished = 19;
+static const ExtraID kWSC02TurnOffMorphScreen = 20;
+static const ExtraID kWSC02SouthViewNoArgon = 21;
+static const ExtraID kMessagesMovedToOffice = 22;
+static const ExtraID kMessagesOff = 23;
+static const ExtraID kMessagesZoomOutNoNitrogen = 24;
+static const ExtraID kMessagesMovedToOfficeNoNitrogen = 25;
+static const ExtraID kMessagesOffNoNitrogen = 26;
+static const ExtraID kMessagesViewNoNitrogen = 27;
+static const ExtraID kMessagesViewMachineOnNoNitrogen = 28;
+static const ExtraID kW03NorthActivate = 29;
+static const ExtraID kW03NorthGetData = 30;
+static const ExtraID kW03NorthInstructions = 31;
+static const ExtraID kW03NorthPrepMolecule1 = 32;
+static const ExtraID kW03NorthPrepMolecule2 = 33;
+static const ExtraID kW03NorthPrepMolecule3 = 34;
+static const ExtraID kW03NorthFinishSynthesis = 35;
+static const ExtraID kW03SouthCreateAntidote = 36;
+static const ExtraID kW03SouthAntidoteLoop = 37;
+static const ExtraID kW03SouthDeactivate = 38;
+static const ExtraID kW03SouthViewNoAntidote = 39;
+static const ExtraID kWSC07SouthMap = 40;
+static const ExtraID kW17WestPeopleCrossing = 41;
+static const ExtraID kW17WestPeopleCrossingView = 42;
+static const ExtraID kW21SouthPeopleCrossing = 43;
+static const ExtraID kW24SouthPeopleCrossing = 44;
+static const ExtraID kW34EastPeopleCrossing = 45;
+static const ExtraID kW36WestPeopleCrossing = 46;
+static const ExtraID kW38NorthPeopleCrossing = 47;
+static const ExtraID kW46SouthPeopleCrossing = 48;
+static const ExtraID kW49NorthPeopleCrossing = 49;
+static const ExtraID kW49NorthPeopleCrossingView = 50;
+static const ExtraID kWSC56SouthMap = 51;
+static const ExtraID kNerdAtTheDoor1 = 52;
+static const ExtraID kNerdAtTheDoor2 = 53;
+static const ExtraID kW61SouthZoomInNoGun = 54;
+static const ExtraID kW61Brochure = 55;
+static const ExtraID kW61SouthScreenOnWithGun = 56;
+static const ExtraID kW61SouthScreenOffWithGun = 57;
+static const ExtraID kW61SouthSmartAlloysWithGun = 58;
+static const ExtraID kW61SouthMorphingWithGun = 59;
+static const ExtraID kW61SouthTimeBendingWithGun = 60;
+static const ExtraID kW61SouthZoomOutNoGun = 61;
+static const ExtraID kW61SouthScreenOnNoGun = 62;
+static const ExtraID kW61SouthScreenOffNoGun = 63;
+static const ExtraID kW61SouthSmartAlloysNoGun = 64;
+static const ExtraID kW61SouthMorphingNoGun = 65;
+static const ExtraID kW61SouthTimeBendingNoGun = 66;
+static const ExtraID kW61MessagesOn = 67;
+static const ExtraID kW61MessagesOff = 68;
+static const ExtraID kW61WhiteMessage = 69;
+static const ExtraID kW61WalchekMessage = 70;
+static const ExtraID kW61WalchekEasterEgg1 = 71;
+static const ExtraID kW62SouthPlasmaRobotAppears = 72;
+static const ExtraID kW62ZoomToRobot = 73;
+static const ExtraID kW62ZoomOutFromRobot = 74;
+static const ExtraID kW62PlasmaDodgeSurvive = 75;
+static const ExtraID kW62PlasmaDodgeDie = 76;
+static const ExtraID kW65SouthSinclairLecture = 77;
+static const ExtraID kW73WestPeopleCrossing = 78;
+static const ExtraID kW73WestPeopleCrossingView = 79;
+static const ExtraID kW0ZSpottedByWomen = 80;
+static const ExtraID kW95RobotShoots = 81;
+static const ExtraID kW98MorphsToRobot = 82;
+static const ExtraID kW98RobotShoots = 83;
+static const ExtraID kW98RobotShocked = 84;
+static const ExtraID kW98RobotGassed = 85;
+static const ExtraID kW98RobotHeadOpensDark = 86;
+static const ExtraID kW98RobotHead000Dark = 87;
+static const ExtraID kW98RobotHead001Dark = 88;
+static const ExtraID kW98RobotHead010Dark = 89;
+static const ExtraID kW98RobotHead011Dark = 90;
+static const ExtraID kW98RobotHead100Dark = 91;
+static const ExtraID kW98RobotHead101Dark = 92;
+static const ExtraID kW98RobotHead110Dark = 93;
+static const ExtraID kW98RobotHead111Dark = 94;
+static const ExtraID kW98RobotHeadClosesDark = 95;
+static const ExtraID kW98WestViewWithGunDark = 96;
+static const ExtraID kW98WestViewNoGunDark = 97;
+static const ExtraID kW98RobotHeadOpensLight = 98;
+static const ExtraID kW98RobotHead000Light = 99;
+static const ExtraID kW98RobotHead001Light = 100;
+static const ExtraID kW98RobotHead010Light = 101;
+static const ExtraID kW98RobotHead011Light = 102;
+static const ExtraID kW98RobotHead100Light = 103;
+static const ExtraID kW98RobotHead101Light = 104;
+static const ExtraID kW98RobotHead110Light = 105;
+static const ExtraID kW98RobotHead111Light = 106;
+static const ExtraID kW98RobotHeadClosesLight = 107;
+static const ExtraID kW98WestViewWithGunLight = 108;
+static const ExtraID kW98WestViewNoGunLight = 109;
+
+static const CoordType kMoleculesMovieLeft = kNavAreaLeft + 112;
+static const CoordType kMoleculesMovieTop = kNavAreaTop + 40;
+
+WSC::WSC(InputHandler *nextHandler, PegasusEngine *owner) : Neighborhood(nextHandler, owner, "WSC", kWSCID),
+ _moleculesMovie(kNoDisplayElement) {
+ setIsItemTaken(kArgonCanister);
+ setIsItemTaken(kSinclairKey);
+ setIsItemTaken(kNitrogenCanister);
+ setIsItemTaken(kPoisonDart);
+ setIsItemTaken(kAntidote);
+ setIsItemTaken(kMachineGun);
+ setIsItemTaken(kStunGun);
+
+ GameState.setTakenItemID(kArgonPickup, GameState.isTakenItemID(kArgonCanister) &&
+ GameState.isTakenItemID(kSinclairKey));
+}
+
+uint16 WSC::getDateResID() const {
+ return kDate2310ID;
+}
+
+void WSC::init() {
+ Neighborhood::init();
+
+ _cachedZoomSpot = 0;
+ _argonSprite = 0;
+
+ // HACK: Fix the drag item for picking up the Sinclair Key Card
+ HotspotInfoTable::Entry *entry = findHotspotEntry(kWSC02SouthTakeArgonSpotID);
+ entry->hotspotItem = kArgonPickup;
+}
+
+void WSC::flushGameState() {
+ g_energyMonitor->saveCurrentEnergyValue();
+}
+
+void WSC::start() {
+ if (g_energyMonitor) {
+ g_energyMonitor->stopEnergyDraining();
+ g_energyMonitor->restoreLastEnergyValue();
+ _vm->resetEnergyDeathReason();
+ g_energyMonitor->startEnergyDraining();
+ }
+
+ if (!GameState.getWSCDidPlasmaDodge())
+ forceStridingStop(kWSC58, kSouth, kAltWSCNormal);
+
+ Neighborhood::start();
+}
+
+class PryDoorMessage : public AIPlayMessageAction {
+public:
+ PryDoorMessage() : AIPlayMessageAction("Images/AI/WSC/XW59SD3", false) {}
+
+protected:
+ virtual void performAIAction(AIRule *);
+};
+
+void PryDoorMessage::performAIAction(AIRule *rule) {
+ if (((PegasusEngine *)g_engine)->playerHasItemID(kShieldBiochip)
+ && ((PegasusEngine *)g_engine)->getCurrentBiochip()->getObjectID() != kShieldBiochip)
+ AIPlayMessageAction::performAIAction(rule);
+}
+
+void WSC::setUpAIRules() {
+ Neighborhood::setUpAIRules();
+
+ if (g_AIArea) {
+ AIPlayMessageAction *messageAction = new AIPlayMessageAction("Images/AI/WSC/XW1WB1", false);
+ AILastExtraCondition *extraCondition = new AILastExtraCondition(kWSCDartScan1);
+ AIRule *rule = new AIRule(extraCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Globals/XGLOB5A", false);
+ AILocationCondition *locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kWSC06, kNorth));
+ rule = new AIRule(locCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Globals/XGLOB5A", false);
+ locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kWSC10, kWest));
+ rule = new AIRule(locCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Globals/XGLOB5A", false);
+ locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kWSC28, kWest));
+ rule = new AIRule(locCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Globals/XGLOB5A", false);
+ locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kWSC49, kWest));
+ rule = new AIRule(locCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Globals/XGLOB5A", false);
+ locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kWSC65, kSouth));
+ rule = new AIRule(locCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Globals/XGLOB5A", false);
+ locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kWSC73, kSouth));
+ rule = new AIRule(locCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Globals/XGLOB5A", false);
+ locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kWSC79, kWest));
+ rule = new AIRule(locCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/WSC/XW59SD1", false);
+ locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kWSC58, kSouth));
+ rule = new AIRule(locCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ PryDoorMessage *pryDoorMessage = new PryDoorMessage();
+ AIDoorOpenedCondition *doorCondition = new AIDoorOpenedCondition(MakeRoomView(kWSC58, kSouth));
+ rule = new AIRule(doorCondition, pryDoorMessage);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/WSC/XW61E", false);
+ AIHasItemCondition *itemCondition = new AIHasItemCondition(kMachineGun);
+ rule = new AIRule(itemCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+
+ messageAction = new AIPlayMessageAction("Images/AI/Globals/XGLOB1E", false);
+ locCondition = new AILocationCondition(1);
+ locCondition->addLocation(MakeRoomView(kWSC95, kWest));
+ rule = new AIRule(locCondition, messageAction);
+ g_AIArea->addAIRule(rule);
+ }
+}
+
+Common::String WSC::getBriefingMovie() {
+ return "Images/AI/WSC/XWO";
+}
+
+Common::String WSC::getEnvScanMovie() {
+ RoomID room = GameState.getCurrentRoom();
+
+ if (room >= kWSC01 && room <= kWSC04)
+ return "Images/AI/WSC/XWE1";
+ else if (room >= kWSC06 && room <= kWSC58)
+ return "Images/AI/WSC/XWE2";
+ else if (room >= kWSC60 && room <= kWSC61West)
+ return "Images/AI/WSC/XWE3";
+ else if (room >= kWSC64 && room <= kWSC98)
+ return "Images/AI/WSC/XWE4";
+
+ return "Images/AI/WSC/XWE5";
+}
+
+uint WSC::getNumHints() {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kWSC10, kWest):
+ case MakeRoomView(kWSC28, kWest):
+ case MakeRoomView(kWSC49, kWest):
+ case MakeRoomView(kWSC65, kSouth):
+ case MakeRoomView(kWSC75, kSouth):
+ case MakeRoomView(kWSC79, kWest):
+ return 2;
+ case MakeRoomView(kWSC02, kSouth):
+ if (_vm->getEnergyDeathReason() == kDeathDidntStopPoison &&
+ !_privateFlags.getFlag(kWSCPrivateInMoleculeGameFlag) &&
+ !GameState.getWSCDesignedAntidote())
+ return 3;
+ else if (!GameState.getScoringGotNitrogenCanister() ||
+ !GameState.getScoringGotSinclairKey())
+ return 1;
+ break;
+ case MakeRoomView(kWSC03, kNorth):
+ // WORKAROUND: The original game is missing the first two hint movies and
+ // just plays nothing in its stead. We'll just return that we have one
+ // hint available.
+ if (inSynthesizerGame())
+ return 1;
+
+ // fall through
+ case MakeRoomView(kWSC01, kNorth):
+ case MakeRoomView(kWSC01, kSouth):
+ case MakeRoomView(kWSC01, kEast):
+ case MakeRoomView(kWSC01, kWest):
+ case MakeRoomView(kWSC02, kNorth):
+ case MakeRoomView(kWSC02, kEast):
+ case MakeRoomView(kWSC02, kWest):
+ case MakeRoomView(kWSC02Morph, kNorth):
+ case MakeRoomView(kWSC02Morph, kEast):
+ case MakeRoomView(kWSC02Morph, kWest):
+ case MakeRoomView(kWSC02Messages, kNorth):
+ case MakeRoomView(kWSC02Messages, kEast):
+ case MakeRoomView(kWSC02Messages, kWest):
+ case MakeRoomView(kWSC03, kSouth):
+ case MakeRoomView(kWSC03, kEast):
+ case MakeRoomView(kWSC03, kWest):
+ case MakeRoomView(kWSC04, kNorth):
+ case MakeRoomView(kWSC04, kSouth):
+ case MakeRoomView(kWSC04, kEast):
+ case MakeRoomView(kWSC04, kWest):
+ if (_vm->getEnergyDeathReason() == kDeathDidntStopPoison &&
+ !_privateFlags.getFlag(kWSCPrivateInMoleculeGameFlag) &&
+ !GameState.getWSCDesignedAntidote())
+ return 3;
+ break;
+ case MakeRoomView(kWSC02Messages, kSouth):
+ if (_vm->getEnergyDeathReason() == kDeathDidntStopPoison &&
+ !_privateFlags.getFlag(kWSCPrivateInMoleculeGameFlag) &&
+ !GameState.getWSCDesignedAntidote())
+ return 3;
+ else if (!GameState.getScoringGotNitrogenCanister())
+ return 1;
+ break;
+ case MakeRoomView(kWSC02Morph, kSouth):
+ if (_vm->getEnergyDeathReason() == kDeathDidntStopPoison &&
+ !_privateFlags.getFlag(kWSCPrivateInMoleculeGameFlag) &&
+ !GameState.getWSCDesignedAntidote())
+ return 3;
+ else if (!GameState.getScoringGotSinclairKey())
+ return 1;
+ break;
+ case MakeRoomView(kWSC42, kEast):
+ if (!GameState.isCurrentDoorOpen())
+ return 1;
+ break;
+ case MakeRoomView(kWSC58, kSouth):
+ if (GameState.isCurrentDoorOpen()) {
+ if (GameState.getWSCDidPlasmaDodge())
+ return 0;
+ else
+ return 1;
+ } else if (_vm->playerHasItemID(kCrowbar))
+ return 2;
+
+ return 3;
+ case MakeRoomView(kWSC61, kEast):
+ if (!GameState.getScoringSawBrochure())
+ return 1;
+ break;
+ case MakeRoomView(kWSC61, kSouth):
+ if (!GameState.getScoringSawSinclairEntry1() ||
+ !GameState.getScoringSawSinclairEntry2() ||
+ !GameState.getScoringSawSinclairEntry3())
+ return 1;
+ break;
+ case MakeRoomView(kWSC98, kWest):
+ if (getCurrentActivation() == kActivationRobotTurning)
+ return 1;
+ break;
+ }
+
+ return 0;
+}
+
+Common::String WSC::getHintMovie(uint hintNum) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kWSC10, kWest):
+ case MakeRoomView(kWSC28, kWest):
+ case MakeRoomView(kWSC49, kWest):
+ case MakeRoomView(kWSC65, kSouth):
+ case MakeRoomView(kWSC75, kSouth):
+ case MakeRoomView(kWSC79, kWest):
+ if (hintNum == 1)
+ return "Images/AI/Globals/XGLOB5B";
+
+ return "Images/AI/Globals/XGLOB5C";
+ case MakeRoomView(kWSC02, kSouth):
+ if (_vm->getEnergyDeathReason() == kDeathDidntStopPoison &&
+ !_privateFlags.getFlag(kWSCPrivateInMoleculeGameFlag) &&
+ !GameState.getWSCDesignedAntidote())
+ return Common::String::format("Images/AI/WSC/XWPH%d", hintNum);
+
+ return "Images/AI/Globals/XGLOB1C";
+ case MakeRoomView(kWSC61, kEast):
+ case MakeRoomView(kWSC61, kSouth):
+ return "Images/AI/Globals/XGLOB1C";
+ case MakeRoomView(kWSC42, kEast):
+ if (_vm->playerHasItemID(kSinclairKey))
+ return "Images/AI/Globals/XGLOB1A";
+
+ return "Images/AI/Globals/XGLOB2C";
+ case MakeRoomView(kWSC58, kSouth):
+ switch (hintNum) {
+ case 1:
+ if (GameState.isCurrentDoorOpen()) {
+ // Only get here if we haven't done the plasma dodge game...
+ if (_vm->playerHasItemID(kShieldBiochip))
+ return "Images/AI/Globals/XGLOB1A";
+ else
+ return "Images/AI/Globals/XGLOB3F";
+ } else if (_vm->playerHasItemID(kCrowbar)) {
+ return "Images/AI/Globals/XGLOB1A";
+ }
+
+ return "Images/AI/Globals/XGLOB1B";
+ case 2:
+ // Only get here if the door is still locked...
+ if (_vm->playerHasItemID(kCrowbar))
+ return "Images/AI/WSC/XW59SD2";
+
+ return "Images/AI/Globals/XGLOB2D";
+ case 3:
+ // Only get here if the door is still locked and we don't have the
+ // crowbar...
+ return "Images/AI/WSC/XW59SD2";
+ }
+ break;
+ case MakeRoomView(kWSC03, kNorth):
+ // WORKAROUND: The original game is missing the first two hint movies and
+ // just plays nothing in its stead. We just make it the first hint.
+ if (inSynthesizerGame())
+ return "Images/AI/WSC/XW03NH3";
+
+ // fall through
+ case MakeRoomView(kWSC01, kNorth):
+ case MakeRoomView(kWSC01, kSouth):
+ case MakeRoomView(kWSC01, kEast):
+ case MakeRoomView(kWSC01, kWest):
+ case MakeRoomView(kWSC02, kNorth):
+ case MakeRoomView(kWSC02, kEast):
+ case MakeRoomView(kWSC02, kWest):
+ case MakeRoomView(kWSC02Morph, kNorth):
+ case MakeRoomView(kWSC02Morph, kEast):
+ case MakeRoomView(kWSC02Morph, kWest):
+ case MakeRoomView(kWSC02Messages, kNorth):
+ case MakeRoomView(kWSC02Messages, kEast):
+ case MakeRoomView(kWSC02Messages, kWest):
+ case MakeRoomView(kWSC03, kSouth):
+ case MakeRoomView(kWSC03, kEast):
+ case MakeRoomView(kWSC03, kWest):
+ case MakeRoomView(kWSC04, kNorth):
+ case MakeRoomView(kWSC04, kSouth):
+ case MakeRoomView(kWSC04, kEast):
+ case MakeRoomView(kWSC04, kWest):
+ // analyzer hint
+ return Common::String::format("Images/AI/WSC/XWPH%d", hintNum);
+ case MakeRoomView(kWSC02Messages, kSouth):
+ case MakeRoomView(kWSC02Morph, kSouth):
+ if (_vm->getEnergyDeathReason() == kDeathDidntStopPoison &&
+ !_privateFlags.getFlag(kWSCPrivateInMoleculeGameFlag) &&
+ !GameState.getWSCDesignedAntidote())
+ // analyzer hint
+ return Common::String::format("Images/AI/WSC/XWPH%d", hintNum);
+
+ return "Images/AI/Globals/XGLOB1C";
+ case MakeRoomView(kWSC98, kWest):
+ return "Images/AI/WSC/XW98WH2";
+ }
+
+ return "";
+}
+
+void WSC::prepareForAIHint(const Common::String &movieName) {
+ if (movieName == "Images/AI/WSC/XW98WH2" && isEventTimerRunning())
+ pauseTimer();
+}
+
+void WSC::cleanUpAfterAIHint(const Common::String &movieName) {
+ if (movieName == "Images/AI/WSC/XW98WH2" && isEventTimerRunning())
+ resumeTimer();
+}
+
+bool WSC::okayToJump() {
+ if (GameState.getWSCPoisoned()) {
+ die(kDeathDidntStopPoison);
+ return false;
+ }
+
+ bool result = Neighborhood::okayToJump();
+ if (!result)
+ playSpotSoundSync(kWSCCantTransportIn, kWSCCantTransportOut);
+
+ return result;
+}
+
+TimeValue WSC::getViewTime(const RoomID room, const DirectionConstant direction) {
+ ExtraID viewExtra = 0xffffffff;
+ ExtraTable::Entry extra;
+
+ switch (MakeRoomView(room, direction)) {
+ case MakeRoomView(kWSC01, kWest):
+ if (!GameState.getWSCSeenTimeStream()) {
+ getExtraEntry(kWSCArrivalFromTSA, extra);
+ return extra.movieStart;
+ } else if (GameState.getWSCPoisoned() && !GameState.getWSCAnsweredAboutDart()) {
+ viewExtra = kWSCDartScan1;
+ }
+ break;
+ case MakeRoomView(kWSC02Morph, kSouth):
+ if (GameState.isTakenItemID(kArgonPickup) || GameState.isTakenItemID(kArgonCanister))
+ viewExtra = kWSC02SouthViewNoArgon;
+ break;
+ case MakeRoomView(kWSC02Messages, kSouth):
+ if (GameState.isTakenItemID(kNitrogenCanister)) {
+ if (_privateFlags.getFlag(kWSCPrivateLabMessagesOpenFlag))
+ viewExtra = kMessagesViewMachineOnNoNitrogen;
+ else
+ viewExtra = kMessagesViewNoNitrogen;
+ }
+ break;
+ case MakeRoomView(kWSC03, kSouth):
+ if (_privateFlags.getFlag(kWSCDraggingAntidoteFlag))
+ viewExtra = kW03SouthViewNoAntidote;
+ break;
+ case MakeRoomView(kWSC17, kWest):
+ if (_privateFlags.getFlag(kWSCPrivateNeedPeopleAt17WestFlag))
+ viewExtra = kW17WestPeopleCrossingView;
+ break;
+ case MakeRoomView(kWSC49, kNorth):
+ if (_privateFlags.getFlag(kWSCPrivateNeedPeopleAt49NorthFlag))
+ viewExtra = kW49NorthPeopleCrossingView;
+ break;
+ case MakeRoomView(kWSC73, kWest):
+ if (_privateFlags.getFlag(kWSCPrivateNeedPeopleAt73WestFlag))
+ viewExtra = kW73WestPeopleCrossingView;
+ break;
+ case MakeRoomView(kWSC98, kWest):
+ if (GameState.getWSCRobotDead()) {
+ if (GameState.getWSCRobotGone()) {
+ if (GameState.isTakenItemID(kStunGun)) {
+ if (GameState.getWSCCatwalkDark())
+ viewExtra = kW98WestViewNoGunDark;
+ else
+ viewExtra = kW98WestViewNoGunLight;
+ } else {
+ if (GameState.getWSCCatwalkDark())
+ viewExtra = kW98WestViewWithGunDark;
+ else
+ viewExtra = kW98WestViewWithGunLight;
+ }
+ } else if (_privateFlags.getFlag(kWSCPrivateRobotHeadOpenFlag)) {
+ if (GameState.getWSCCatwalkDark())
+ viewExtra = kW98RobotHead111Dark;
+ else
+ viewExtra = kW98RobotHead111Light;
+
+ if (_privateFlags.getFlag(kWSCPrivateGotRetScanChipFlag))
+ viewExtra -= 1;
+ if (_privateFlags.getFlag(kWSCPrivateGotMapChipFlag))
+ viewExtra -= 2;
+ if (_privateFlags.getFlag(kWSCPrivateGotOpticalChipFlag))
+ viewExtra -= 4;
+ } else if (GameState.getWSCRobotDead()) {
+ // Should only happen on loading a saved game, so it can take its time.
+ if (GameState.getWSCCatwalkDark())
+ viewExtra = kW98RobotShocked;
+ else
+ viewExtra = kW98RobotGassed;
+ }
+ }
+ break;
+ }
+
+ if (viewExtra != 0xffffffff) {
+ getExtraEntry(viewExtra, extra);
+ return extra.movieEnd - 1;
+ }
+
+ return Neighborhood::getViewTime(room, direction);
+}
+
+void WSC::findSpotEntry(const RoomID room, const DirectionConstant direction, SpotFlags flags, SpotTable::Entry &spotEntry) {
+ switch (MakeRoomView(room, direction)) {
+ case MakeRoomView(kWSC58, kSouth):
+ case MakeRoomView(kWSC79, kWest):
+ if ((flags & kSpotOnTurnMask) != 0) {
+ spotEntry.clear();
+ return;
+ }
+ break;
+ }
+
+ Neighborhood::findSpotEntry(room, direction, flags, spotEntry);
+}
+
+void WSC::getZoomEntry(const HotSpotID id, ZoomTable::Entry &zoomEntry) {
+ Neighborhood::getZoomEntry(id, zoomEntry);
+
+ ExtraTable::Entry extra;
+ ExtraID zoomExtra = 0xffffffff;
+
+ switch (id) {
+ case kWSC02SouthMessagesSpotID:
+ if (GameState.isTakenItemID(kNitrogenCanister))
+ zoomExtra = kWSC02MessagesZoomNoNitrogen;
+ break;
+ case kWSC02SouthMessagesOutSpotID:
+ if (GameState.isTakenItemID(kNitrogenCanister))
+ zoomExtra = kMessagesZoomOutNoNitrogen;
+ break;
+ case kWSC02SouthMorphSpotID:
+ if (GameState.isTakenItemID(kArgonCanister))
+ zoomExtra = kWSC02MorphZoomNoArgon;
+ break;
+ case kWSC02SouthMorphOutSpotID:
+ if (GameState.isTakenItemID(kArgonCanister))
+ zoomExtra = kWSC02ZoomOutNoArgon;
+ break;
+ case kWSC61SouthSpotID:
+ if (GameState.isTakenItemID(kMachineGun))
+ zoomExtra = kW61SouthZoomInNoGun;
+ break;
+ case kWSC61SouthOutSpotID:
+ if (GameState.isTakenItemID(kMachineGun))
+ zoomExtra = kW61SouthZoomOutNoGun;
+ break;
+ }
+
+ if (zoomExtra != 0xffffffff) {
+ getExtraEntry(zoomExtra, extra);
+ zoomEntry.movieStart = extra.movieStart;
+ zoomEntry.movieEnd = extra.movieEnd;
+ }
+}
+
+void WSC::getExtraEntry(const uint32 id, ExtraTable::Entry &extraEntry) {
+ switch (id) {
+ case kWSCZoomOutFromAnalyzer:
+ Neighborhood::getExtraEntry(kWSCZoomOutFromAnalyzer, extraEntry);
+ extraEntry.movieEnd = extraEntry.movieStart + 14 * kWSCFrameDuration;
+ break;
+ case kW61WalchekMessage:
+ if (GameState.getEasterEgg())
+ Neighborhood::getExtraEntry(kW61WalchekEasterEgg1, extraEntry);
+ else
+ Neighborhood::getExtraEntry(id, extraEntry);
+ break;
+ case kW61SouthScreenOnWithGun:
+ if (GameState.isTakenItemID(kMachineGun))
+ Neighborhood::getExtraEntry(id, extraEntry);
+ else
+ Neighborhood::getExtraEntry(kW61SouthScreenOnNoGun, extraEntry);
+ break;
+ case kW61SouthSmartAlloysWithGun:
+ if (GameState.isTakenItemID(kMachineGun))
+ Neighborhood::getExtraEntry(id, extraEntry);
+ else
+ Neighborhood::getExtraEntry(kW61SouthSmartAlloysNoGun, extraEntry);
+ break;
+ case kW61SouthMorphingWithGun:
+ if (GameState.isTakenItemID(kMachineGun))
+ Neighborhood::getExtraEntry(id, extraEntry);
+ else
+ Neighborhood::getExtraEntry(kW61SouthMorphingNoGun, extraEntry);
+ break;
+ case kW61SouthTimeBendingWithGun:
+ if (GameState.isTakenItemID(kMachineGun))
+ Neighborhood::getExtraEntry(id, extraEntry);
+ else
+ Neighborhood::getExtraEntry(kW61SouthTimeBendingNoGun, extraEntry);
+ break;
+ case kW98RobotHeadOpensLight:
+ if (GameState.getWSCCatwalkDark())
+ Neighborhood::getExtraEntry(kW98RobotHeadOpensDark, extraEntry);
+ else
+ Neighborhood::getExtraEntry(id, extraEntry);
+ break;
+ default:
+ Neighborhood::getExtraEntry(id, extraEntry);
+ break;
+ }
+}
+
+CanMoveForwardReason WSC::canMoveForward(ExitTable::Entry &entry) {
+ if (GameState.getCurrentRoomAndView() == MakeRoomView(kWSC01, kWest) &&
+ getCurrentActivation() != kActivateHotSpotAlways)
+ return kCantMoveWatchingDiagnosis;
+
+ return Neighborhood::canMoveForward(entry);
+}
+
+// Also add cases here for compound analyzer...
+CanTurnReason WSC::canTurn(TurnDirection turnDirection, DirectionConstant &nextDir) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kWSC01, kWest):
+ if (getCurrentActivation() != kActivateHotSpotAlways)
+ return kCantTurnWatchingDiagnosis;
+ break;
+ case MakeRoomView(kWSC01, kEast):
+ if (getCurrentActivation() != kActivateHotSpotAlways)
+ return kCantTurnWatchingAnalysis;
+ break;
+ case MakeRoomView(kWSC03, kNorth):
+ if (_privateFlags.getFlag(kWSCPrivateInMoleculeGameFlag))
+ return kCantTurnInMoleculeGame;
+ break;
+ }
+
+ return Neighborhood::canTurn(turnDirection, nextDir);
+}
+
+CanOpenDoorReason WSC::canOpenDoor(DoorTable::Entry &entry) {
+ switch (GameState.getCurrentRoom()) {
+ case kWSC42:
+ if (!_privateFlags.getFlag(kWSCPrivateSinclairOfficeOpenFlag))
+ return kCantOpenLocked;
+ break;
+ case kWSC58:
+ if (!_privateFlags.getFlag(kWSCPrivate58SouthOpenFlag))
+ return kCantOpenLocked;
+ break;
+ }
+
+ return Neighborhood::canOpenDoor(entry);
+}
+
+void WSC::bumpIntoWall() {
+ requestSpotSound(kWSCBumpIntoWallIn, kWSCBumpIntoWallOut, kFilterAllInput, 0);
+ Neighborhood::bumpIntoWall();
+}
+
+void WSC::closeDoorOffScreen(const RoomID room, const DirectionConstant) {
+ Item *keyCard;
+
+ switch (room) {
+ case kWSC58:
+ case kWSC62:
+ case kWSC63:
+ case kWSC64:
+ case kWSC85:
+ case kWSC86:
+ case kWSC88:
+ case kWSC89:
+ playSpotSoundSync(kSlidingDoorCloseIn, kSlidingDoorCloseOut);
+ break;
+ case kWSC81:
+ case kWSC82:
+ case kWSC92:
+ case kWSC93:
+ keyCard = _vm->getAllItems().findItemByID(kKeyCard);
+ if (keyCard->getItemState() == kFlashlightOn && (GameState.getCurrentRoom() == kWSC81 ||
+ GameState.getCurrentRoom() == kWSC93)) {
+ keyCard->setItemState(kFlashlightOff);
+ playSpotSoundSync(kWSCFlashlightClickIn, kWSCFlashlightClickOut);
+ } else if (keyCard->getItemState() == kFlashlightOff && (GameState.getCurrentRoom() == kWSC82 ||
+ GameState.getCurrentRoom() == kWSC92)) {
+ keyCard->setItemState(kFlashlightOn);
+ playSpotSoundSync(kWSCFlashlightClickIn, kWSCFlashlightClickOut);
+ }
+
+ playSpotSoundSync(kSlimyDoorCloseIn, kSlimyDoorCloseOut);
+ break;
+ default:
+ playSpotSoundSync(kSlimyDoorCloseIn, kSlimyDoorCloseOut);
+ break;
+ }
+}
+
+void WSC::cantMoveThatWay(CanMoveForwardReason reason) {
+ if (reason != kCantMoveWatchingDiagnosis)
+ Neighborhood::cantMoveThatWay(reason);
+}
+
+void WSC::cantOpenDoor(CanOpenDoorReason reason) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kWSC22, kWest):
+ playSpotSoundSync(kNakamuraNotHomeIn, kNakamuraNotHomeOut);
+ break;
+ case MakeRoomView(kWSC23, kEast):
+ playSpotSoundSync(kHernandezNotHomeIn, kHernandezNotHomeOut);
+ break;
+ case MakeRoomView(kWSC26, kWest):
+ playSpotSoundSync(kGrailisNotHomeIn, kGrailisNotHomeOut);
+ break;
+ case MakeRoomView(kWSC27, kEast):
+ playSpotSoundSync(kWashingtonNotHomeIn, kWashingtonNotHomeOut);
+ break;
+ case MakeRoomView(kWSC32, kWest):
+ playSpotSoundSync(kTheriaultNotHomeIn, kTheriaultNotHomeOut);
+ break;
+ case MakeRoomView(kWSC33, kEast):
+ playSpotSoundSync(kSullivanNotHomeIn, kSullivanNotHomeOut);
+ break;
+ case MakeRoomView(kWSC41, kWest):
+ playSpotSoundSync(kGlennerNotHomeIn, kGlennerNotHomeOut);
+ break;
+ case MakeRoomView(kWSC42, kEast):
+ playSpotSoundSync(kSinclairNotHomeIn, kSinclairNotHomeOut);
+ break;
+ case MakeRoomView(kWSC15, kWest):
+ case MakeRoomView(kWSC25, kWest):
+ case MakeRoomView(kWSC33, kWest):
+ case MakeRoomView(kWSC41, kEast):
+ case MakeRoomView(kWSC46, kWest):
+ playSpotSoundSync(kWSCLabClosedIn, kWSCLabClosedOut);
+ break;
+ default:
+ Neighborhood::cantOpenDoor(reason);
+ break;
+ }
+}
+
+void WSC::doorOpened() {
+ Neighborhood::doorOpened();
+
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kWSC42, kEast):
+ _vm->addItemToInventory((InventoryItem *)_vm->getAllItems().findItemByID(kSinclairKey));
+ break;
+ case MakeRoomView(kWSC58, kSouth):
+ GameState.setScoringUsedCrowBarInWSC();
+ _vm->addItemToInventory((InventoryItem *)_vm->getAllItems().findItemByID(kCrowbar));
+ break;
+ case MakeRoomView(kWSC06, kNorth):
+ case MakeRoomView(kWSC79, kWest):
+ die(kDeathArrestedInWSC);
+ break;
+ case MakeRoomView(kWSC60, kWest):
+ if (_vm->itemInInventory(kMachineGun))
+ startExtraSequence(kNerdAtTheDoor2, kExtraCompletedFlag, kFilterNoInput);
+ else if (!GameState.getWSCSeenNerd())
+ startExtraSequence(kNerdAtTheDoor1, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case MakeRoomView(kWSC95, kWest):
+ GameState.setScoringOpenedCatwalk();
+ scheduleEvent(kGawkAtRobotTime, 1, kTimerEventPlayerGawkingAtRobot);
+ break;
+ }
+}
+
+void WSC::turnLeft() {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kWSC17, kNorth):
+ if (!_privateFlags.getFlag(kWSCPrivateSeenPeopleAt17WestFlag) && _vm->getRandomNumber(2) == 0)
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt17WestFlag, true);
+ break;
+ case MakeRoomView(kWSC49, kEast):
+ if (!_privateFlags.getFlag(kWSCPrivateSeenPeopleAt49NorthFlag) && _vm->getRandomNumber(2) == 0)
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt49NorthFlag, true);
+ break;
+ case MakeRoomView(kWSC73, kNorth):
+ if (!_privateFlags.getFlag(kWSCPrivateSeenPeopleAt73WestFlag) && _vm->getRandomNumber(2) == 0)
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt73WestFlag, true);
+ break;
+ case MakeRoomView(kWSC73, kWest):
+ if (!GameState.getWSCBeenAtWSC93())
+ setCurrentAlternate(kAltWSCW0ZDoorOpen);
+ break;
+ case MakeRoomView(kWSC95, kWest):
+ cancelEvent();
+ break;
+ }
+
+ Neighborhood::turnLeft();
+}
+
+void WSC::turnRight() {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kWSC17, kSouth):
+ if (!_privateFlags.getFlag(kWSCPrivateSeenPeopleAt17WestFlag) && _vm->getRandomNumber(2) == 0)
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt17WestFlag, true);
+ break;
+ case MakeRoomView(kWSC49, kWest):
+ if (!_privateFlags.getFlag(kWSCPrivateSeenPeopleAt49NorthFlag) && _vm->getRandomNumber(2) == 0)
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt49NorthFlag, true);
+ break;
+ case MakeRoomView(kWSC73, kSouth):
+ if (!_privateFlags.getFlag(kWSCPrivateSeenPeopleAt73WestFlag) && _vm->getRandomNumber(2) == 0)
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt73WestFlag, true);
+ break;
+ case MakeRoomView(kWSC73, kEast):
+ if (!GameState.getWSCBeenAtWSC93())
+ setCurrentAlternate(kAltWSCW0ZDoorOpen);
+ break;
+ case MakeRoomView(kWSC95, kWest):
+ cancelEvent();
+ break;
+ }
+
+ Neighborhood::turnRight();
+}
+
+void WSC::moveForward() {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kWSC19, kNorth):
+ if (!_privateFlags.getFlag(kWSCPrivateSeenPeopleAt19NorthFlag))
+ setCurrentAlternate(kAltWSCPeopleAtW19North);
+ break;
+ case MakeRoomView(kWSC95, kWest):
+ cancelEvent();
+ break;
+ }
+
+ Neighborhood::moveForward();
+}
+
+void WSC::zoomTo(const Hotspot *hotspot) {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kWSC02Messages, kSouth):
+ if (_privateFlags.getFlag(kWSCPrivateLabMessagesOpenFlag)) {
+ _cachedZoomSpot = hotspot;
+ if (GameState.isTakenItemID(kNitrogenCanister))
+ startExtraSequence(kMessagesOffNoNitrogen, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kMessagesOff, kExtraCompletedFlag, kFilterNoInput);
+ return;
+ }
+ break;
+ case MakeRoomView(kWSC61West, kWest):
+ if (GameState.getWSCOfficeMessagesOpen()) {
+ _cachedZoomSpot = hotspot;
+ startExtraSequence(kW61MessagesOff, kExtraCompletedFlag, kFilterNoInput);
+ return;
+ }
+ break;
+ case MakeRoomView(kWSC61South, kSouth):
+ if (_privateFlags.getFlag(kWSCPrivateOfficeLogOpenFlag)) {
+ _cachedZoomSpot = hotspot;
+ if (GameState.isTakenItemID(kMachineGun))
+ startExtraSequence(kW61SouthScreenOffNoGun, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kW61SouthScreenOffWithGun, kExtraCompletedFlag, kFilterNoInput);
+ return;
+ }
+ break;
+ }
+
+ Neighborhood::zoomTo(hotspot);
+}
+
+void WSC::startExtraSequence(const ExtraID extraID, const NotificationFlags flags, const InputBits interruptionFilter) {
+ if (extraID == kW61Brochure)
+ loadLoopSound1("");
+
+ Neighborhood::startExtraSequence(extraID, flags, interruptionFilter);
+}
+
+int16 WSC::getStaticCompassAngle(const RoomID room, const DirectionConstant dir) {
+ int16 angle = Neighborhood::getStaticCompassAngle(room, dir);
+
+ switch (room) {
+ case kWSC02Messages:
+ angle -= 50;
+ break;
+ case kWSC02Morph:
+ angle += 5;
+ break;
+ case kWSC60East:
+ angle -= 10;
+ break;
+ case kWSC66:
+ angle -= kAuditoriumAngleOffset;
+ break;
+ case kWSC67:
+ angle += kAuditoriumAngleOffset;
+ break;
+ case kWSC68:
+ angle -= kAuditoriumAngleOffset * 2;
+ break;
+ case kWSC69:
+ angle += kAuditoriumAngleOffset * 2;
+ break;
+ case kWSC70:
+ angle -= kAuditoriumAngleOffset * 3;
+ break;
+ case kWSC71:
+ angle += kAuditoriumAngleOffset * 3;
+ break;
+ case kWSC72:
+ if (dir == kEast || dir == kWest)
+ angle -= kAuditoriumAngleOffset * 4;
+ break;
+ case kWSC73:
+ if (dir == kEast || dir == kWest)
+ angle += kAuditoriumAngleOffset * 4;
+ break;
+ }
+
+ return angle;
+}
+
+void WSC::getExitCompassMove(const ExitTable::Entry &exitEntry, FaderMoveSpec &compassMove) {
+ Neighborhood::getExitCompassMove(exitEntry, compassMove);
+
+ if (exitEntry.room == kWSC65 && exitEntry.direction == kSouth) {
+ compassMove.insertFaderKnot(exitEntry.movieStart + 100 * kWSCFrameDuration, 180);
+ compassMove.insertFaderKnot(exitEntry.movieStart + 108 * kWSCFrameDuration, 150);
+ compassMove.insertFaderKnot(exitEntry.movieEnd, 150);
+ }
+}
+
+void WSC::getExtraCompassMove(const ExtraTable::Entry &entry, FaderMoveSpec &compassMove) {
+ switch (entry.extra) {
+ case kW61Brochure:
+ compassMove.insertFaderKnot(entry.movieStart + 15 * kWSCFrameDuration, 85);
+ compassMove.insertFaderKnot(entry.movieEnd - 15 * kWSCFrameDuration, 85);
+ compassMove.insertFaderKnot(entry.movieEnd, 90);
+ break;
+ default:
+ Neighborhood::getExtraCompassMove(entry, compassMove);
+ break;
+ }
+}
+
+void WSC::loadAmbientLoops() {
+ RoomID room = GameState.getCurrentRoom();
+
+ if (room >= kWSC01 && room <= kWSC04) {
+ if (GameState.getWSCSeenTimeStream())
+ loadLoopSound1("Sounds/World Science Center/WLabLoop.22K.AIFF", 0x100 / 2);
+ } else if ((room >= kWSC06 && room <= kWSC58) || (room >= kWSC62 && room <= kWSC63))
+ loadLoopSound1("Sounds/World Science Center/Organic Walls.22K.AIFF", 0x100 / 2);
+ else if (room >= kWSC82 && room <= kWSC92)
+ loadLoopSound1("Sounds/World Science Center/Creature Feature.22K.AIFF");
+ else if ((room >= kWSC60 && room <= kWSC61West) || (room >= kWSC64 && room <= kWSC81) ||
+ (room >= kWSC93 && room <= kWSC97))
+ loadLoopSound1("Sounds/World Science Center/The Other Side.22K.AIFF", 0x100 / 12);
+ else if (room == kWSC98)
+ loadLoopSound1("Sounds/World Science Center/WCatLoop.22K.AIFF");
+}
+
+void WSC::checkContinuePoint(const RoomID room, const DirectionConstant direction) {
+ switch (MakeRoomView(room, direction)) {
+ case MakeRoomView(kWSC07, kNorth):
+ case MakeRoomView(kWSC11, kSouth):
+ case MakeRoomView(kWSC13, kSouth):
+ case MakeRoomView(kWSC13, kWest):
+ case MakeRoomView(kWSC16, kWest):
+ case MakeRoomView(kWSC17, kEast):
+ case MakeRoomView(kWSC19, kWest):
+ case MakeRoomView(kWSC28, kNorth):
+ case MakeRoomView(kWSC28, kSouth):
+ case MakeRoomView(kWSC28, kEast):
+ case MakeRoomView(kWSC28, kWest):
+ case MakeRoomView(kWSC29, kNorth):
+ case MakeRoomView(kWSC29, kSouth):
+ case MakeRoomView(kWSC29, kEast):
+ case MakeRoomView(kWSC29, kWest):
+ case MakeRoomView(kWSC40, kEast):
+ case MakeRoomView(kWSC42, kEast):
+ case MakeRoomView(kWSC49, kWest):
+ case MakeRoomView(kWSC49, kNorth):
+ case MakeRoomView(kWSC50, kNorth):
+ case MakeRoomView(kWSC55, kEast):
+ case MakeRoomView(kWSC65, kSouth):
+ case MakeRoomView(kWSC65, kEast):
+ case MakeRoomView(kWSC65, kWest):
+ case MakeRoomView(kWSC72, kEast):
+ case MakeRoomView(kWSC72, kSouth):
+ case MakeRoomView(kWSC73, kWest):
+ case MakeRoomView(kWSC73, kSouth):
+ case MakeRoomView(kWSC79, kWest):
+ case MakeRoomView(kWSC81, kEast):
+ case MakeRoomView(kWSC93, kNorth):
+ case MakeRoomView(kWSC95, kWest):
+ makeContinuePoint();
+ break;
+ case MakeRoomView(kWSC58, kSouth):
+ if (!GameState.getWSCDidPlasmaDodge())
+ makeContinuePoint();
+ break;
+ case MakeRoomView(kWSC60, kWest):
+ if (_vm->playerHasItemID(kMachineGun))
+ makeContinuePoint();
+ break;
+ }
+}
+
+void WSC::arriveAt(const RoomID room, const DirectionConstant dir) {
+ switch (MakeRoomView(room, dir)) {
+ case MakeRoomView(kWSC60, kNorth):
+ case MakeRoomView(kWSC60, kSouth):
+ case MakeRoomView(kWSC60, kEast):
+ case MakeRoomView(kWSC60, kWest):
+ case MakeRoomView(kWSC60East, kNorth):
+ case MakeRoomView(kWSC60East, kSouth):
+ case MakeRoomView(kWSC60East, kEast):
+ case MakeRoomView(kWSC60East, kWest):
+ case MakeRoomView(kWSC60North, kNorth):
+ case MakeRoomView(kWSC60North, kSouth):
+ case MakeRoomView(kWSC60North, kEast):
+ case MakeRoomView(kWSC60North, kWest):
+ case MakeRoomView(kWSC61, kNorth):
+ case MakeRoomView(kWSC61, kSouth):
+ case MakeRoomView(kWSC61, kEast):
+ case MakeRoomView(kWSC61, kWest):
+ case MakeRoomView(kWSC61South, kNorth):
+ case MakeRoomView(kWSC61South, kSouth):
+ case MakeRoomView(kWSC61South, kEast):
+ case MakeRoomView(kWSC61South, kWest):
+ case MakeRoomView(kWSC61West, kNorth):
+ case MakeRoomView(kWSC61West, kSouth):
+ case MakeRoomView(kWSC61West, kEast):
+ case MakeRoomView(kWSC61West, kWest):
+ if (GameState.isTakenItemID(kMachineGun))
+ setCurrentAlternate(kAltWSCTookMachineGun);
+ else
+ setCurrentAlternate(kAltWSCNormal);
+ break;
+ case MakeRoomView(kWSC73, kSouth):
+ case MakeRoomView(kWSC75, kNorth):
+ case MakeRoomView(kWSC75, kSouth):
+ case MakeRoomView(kWSC75, kEast):
+ case MakeRoomView(kWSC75, kWest):
+ if (!GameState.getWSCBeenAtWSC93())
+ setCurrentAlternate(kAltWSCW0ZDoorOpen);
+ break;
+ }
+
+ Neighborhood::arriveAt(room, dir);
+
+ switch (MakeRoomView(room, dir)) {
+ case MakeRoomView(kWSC01, kWest):
+ if (!GameState.getWSCSeenTimeStream()) {
+ requestExtraSequence(kWSCArrivalFromTSA, kExtraCompletedFlag, kFilterNoInput);
+ requestExtraSequence(kWSCShotByRobot, 0, kFilterNoInput);
+ requestExtraSequence(kWSCDartScan1, kExtraCompletedFlag, kFilterNoInput);
+ } else if (GameState.getWSCPoisoned() && !GameState.getWSCAnsweredAboutDart()) {
+ setCurrentActivation(kActivationShotByRobot);
+ }
+ break;
+ case MakeRoomView(kWSC01, kEast):
+ if (GameState.getWSCDartInAnalyzer())
+ requestExtraSequence(kWSCDropDartIntoAnalyzer, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case MakeRoomView(kWSC02Morph, kSouth):
+ setCurrentActivation(kActivationMorphScreenOff);
+ break;
+ case MakeRoomView(kWSC03, kNorth):
+ setCurrentActivation(kActivationW03NorthOff);
+ break;
+ case MakeRoomView(kWSC03, kSouth):
+ if (GameState.getWSCDesignedAntidote() && !GameState.getWSCPickedUpAntidote())
+ setCurrentActivation(kActivationReadyForSynthesis);
+ break;
+ case MakeRoomView(kWSC16, kNorth):
+ if (getCurrentAlternate() == kAltWSCPeopleAtW19North) {
+ setCurrentAlternate(kAltWSCNormal);
+ _privateFlags.setFlag(kWSCPrivateSeenPeopleAt19NorthFlag, true);
+ }
+ break;
+ case MakeRoomView(kWSC07, kSouth):
+ case MakeRoomView(kWSC56, kNorth):
+ setCurrentActivation(kActivationReadyForMap);
+ break;
+ case MakeRoomView(kWSC42, kWest):
+ setCurrentAlternate(kAltWSCNormal);
+ break;
+ case MakeRoomView(kWSC42, kEast):
+ _privateFlags.setFlag(kWSCPrivateSinclairOfficeOpenFlag, false);
+ setCurrentActivation(kActivationSinclairOfficeLocked);
+ break;
+ case MakeRoomView(kWSC58, kSouth):
+ setCurrentActivation(kActivationW58SouthDoorLocked);
+ _privateFlags.setFlag(kWSCPrivate58SouthOpenFlag, false);
+ break;
+ case MakeRoomView(kWSC60, kEast):
+ GameState.setScoringEnteredSinclairOffice();
+ break;
+ case MakeRoomView(kWSC61West, kWest):
+ setCurrentActivation(kActivationW61MessagesOff);
+ break;
+ case MakeRoomView(kWSC61South, kSouth):
+ setCurrentActivation(kActivationW61SouthOff);
+ break;
+ case MakeRoomView(kWSC62, kSouth):
+ if (!GameState.getWSCDidPlasmaDodge()) {
+ g_AIArea->lockAIOut();
+ loadLoopSound1("Sounds/World Science Center/Plasma Rock.22K.AIFF");
+ requestExtraSequence(kW62SouthPlasmaRobotAppears, 0, kFilterNoInput);
+ requestExtraSequence(kW62ZoomToRobot, 0, kFilterNoInput);
+ requestExtraSequence(kW62ZoomOutFromRobot, kExtraCompletedFlag, kFilterNoInput);
+ }
+ break;
+ case MakeRoomView(kWSC65Screen, kSouth):
+ if (!GameState.getWSCSeenSinclairLecture()) {
+ GameState.setWSCSeenSinclairLecture(true);
+ startExtraSequence(kW65SouthSinclairLecture, kExtraCompletedFlag, kFilterAllInput);
+ }
+ break;
+ case MakeRoomView(kWSC66, kWest):
+ case MakeRoomView(kWSC67, kEast):
+ if (!GameState.getWSCHeardPage2()) {
+ playSpotSoundSync(kPaging2In, kPaging2Out);
+ GameState.setWSCHeardPage2(true);
+ }
+ case MakeRoomView(kWSC10, kNorth):
+ case MakeRoomView(kWSC26, kSouth):
+ case MakeRoomView(kWSC72, kWest):
+ case MakeRoomView(kWSC83, kWest):
+ if (!GameState.getWSCHeardCheckIn()) {
+ playSpotSoundSync(kCheckInIn, kCheckInOut);
+ GameState.setWSCHeardCheckIn(true);
+ }
+ break;
+ case MakeRoomView(kWSC0Z, kSouth):
+ if (getCurrentAlternate() == kAltWSCW0ZDoorOpen)
+ turnLeft();
+ break;
+ case MakeRoomView(kWSC93, kEast):
+ GameState.setWSCBeenAtWSC93(true);
+ break;
+ case MakeRoomView(kWSC98, kWest):
+ if (!GameState.getWSCRobotDead()) {
+ scheduleEvent(kGawkAtRobotTime2, 1, kTimerEventPlayerGawkingAtRobot2);
+ setCurrentActivation(kActivationRobotTurning);
+ if (g_AIArea)
+ g_AIArea->checkMiddleArea();
+ } else if (!GameState.getWSCRobotGone()) {
+ setCurrentActivation(kActivationRobotDead);
+ } else {
+ if (GameState.getWSCCatwalkDark()) {
+ // Change the gun hot spot...
+ _vm->getAllHotspots().setHotspotRect(kW98StunGunSpotID, Common::Rect(181 + kNavAreaLeft,
+ 99 + kNavAreaTop,372 + kNavAreaLeft, 149 + kNavAreaTop));
+ }
+ setCurrentActivation(kActivationRobotGone);
+ }
+ break;
+ case MakeRoomView(kWSCDeathRoom, kNorth):
+ case MakeRoomView(kWSCDeathRoom, kSouth):
+ case MakeRoomView(kWSCDeathRoom, kEast):
+ case MakeRoomView(kWSCDeathRoom, kWest):
+ die(kDeathArrestedInWSC);
+ break;
+ }
+
+ checkPeopleCrossing();
+ setUpPoison();
+}
+
+void WSC::turnTo(const DirectionConstant direction) {
+ Neighborhood::turnTo(direction);
+
+ switch (MakeRoomView(GameState.getCurrentRoom(), direction)) {
+ case MakeRoomView(kWSC01, kNorth):
+ case MakeRoomView(kWSC01, kSouth):
+ GameState.setWSCAnalyzerOn(false);
+ break;
+ case MakeRoomView(kWSC03, kNorth):
+ setCurrentActivation(kActivationW03NorthOff);
+ break;
+ case MakeRoomView(kWSC03, kSouth):
+ if (GameState.getWSCDesignedAntidote() && !GameState.getWSCPickedUpAntidote())
+ setCurrentActivation(kActivationReadyForSynthesis);
+ break;
+ case MakeRoomView(kWSC07, kSouth):
+ case MakeRoomView(kWSC56, kNorth):
+ setCurrentActivation(kActivationReadyForMap);
+ break;
+ case MakeRoomView(kWSC18, kSouth):
+ case MakeRoomView(kWSC57, kEast):
+ case MakeRoomView(kWSC75, kEast):
+ case MakeRoomView(kWSC90, kSouth):
+ if (!GameState.getWSCHeardCheckIn()) {
+ playSpotSoundSync(kCheckInIn, kCheckInOut);
+ GameState.setWSCHeardCheckIn(true);
+ }
+ break;
+ case MakeRoomView(kWSC56, kSouth):
+ if (!GameState.getWSCHeardPage1()) {
+ playSpotSoundSync(kPaging1In, kPaging1Out);
+ GameState.setWSCHeardPage1(true);
+ }
+ // clone2727 says: This falls through?!??! WTF?
+ case MakeRoomView(kWSC42, kEast):
+ _privateFlags.setFlag(kWSCPrivateSinclairOfficeOpenFlag, false);
+ setCurrentActivation(kActivationSinclairOfficeLocked);
+ break;
+ case MakeRoomView(kWSC58, kSouth):
+ setCurrentActivation(kActivationW58SouthDoorLocked);
+ _privateFlags.setFlag(kWSCPrivate58SouthOpenFlag, false);
+ break;
+ case MakeRoomView(kWSC73, kWest):
+ setCurrentAlternate(kAltWSCNormal);
+ break;
+ case MakeRoomView(kWSC0Z, kEast):
+ if (getCurrentAlternate() == kAltWSCW0ZDoorOpen)
+ startExtraSequence(kW0ZSpottedByWomen, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ }
+
+ checkPeopleCrossing();
+}
+
+void WSC::receiveNotification(Notification *notification, const NotificationFlags flags) {
+ int32 currentEnergy;
+ Item *item;
+
+ if (flags & kExtraCompletedFlag) {
+ _interruptionFilter = kFilterAllInput;
+
+ switch (_lastExtra) {
+ case kWSCArrivalFromTSA:
+ GameState.setWSCSeenTimeStream(true);
+ loadAmbientLoops();
+ break;
+ case kWSCDartScan1:
+ setCurrentActivation(kActivationShotByRobot);
+ GameState.setWSCPoisoned(true);
+ setUpPoison();
+ makeContinuePoint();
+ break;
+ case kWSCDartScan2:
+ _vm->addItemToInventory((InventoryItem *)_vm->getAllItems().findItemByID(kPoisonDart));
+ GameState.setScoringRemovedDart();
+ GameState.setWSCRemovedDart(true);
+ setUpPoison();
+ g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/WSC/XW1WB2", false, kHintInterruption);
+ // Fall through...
+ case kWSCDartScanNo:
+ GameState.setWSCAnsweredAboutDart(true);
+ startExtraSequence(kWSCDartScan3, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kWSCDartScan3:
+ setCurrentActivation(kActivateHotSpotAlways);
+ break;
+ case kWSCAnalyzerPowerUp:
+ case kWSCAnalyzerPowerUpWithDart:
+ GameState.setWSCAnalyzerOn(true);
+ break;
+ case kWSCDropDartIntoAnalyzer:
+ setCurrentActivation(kActivationZoomedInToAnalyzer);
+ break;
+ case kWSCAnalyzeDart:
+ GameState.setWSCAnalyzedDart(true);
+ GameState.setScoringAnalyzedDart();
+ break;
+ case kWSCZoomOutFromAnalyzer:
+ setCurrentActivation(kActivateHotSpotAlways);
+ GameState.setWSCAnalyzerOn(false);
+ GameState.setWSCDartInAnalyzer(false);
+ updateViewFrame();
+ break;
+ case kMessagesMovedToOffice:
+ case kMessagesMovedToOfficeNoNitrogen:
+ _privateFlags.setFlag(kWSCPrivateLabMessagesOpenFlag, true);
+ GameState.setScoringPlayedWithMessages();
+ break;
+ case kMessagesOff:
+ case kMessagesOffNoNitrogen:
+ _privateFlags.setFlag(kWSCPrivateLabMessagesOpenFlag, false);
+ if (_cachedZoomSpot) {
+ zoomTo(_cachedZoomSpot);
+ _cachedZoomSpot = 0;
+ }
+ break;
+ case kWSC02TurnOnMorphScreen:
+ setCurrentActivation(kActivationReadyForMorph);
+ break;
+ case kWSC02DropToMorphExperiment:
+ loopExtraSequence(kWSC02MorphLoop, kExtraCompletedFlag);
+ setCurrentActivation(kActivationMorphLooping);
+ break;
+ case kWSC02MorphLoop:
+ if (_privateFlags.getFlag(kWSCPrivateInterruptedMorphFlag))
+ startExtraSequence(kWSC02MorphInterruption, kExtraCompletedFlag, kFilterNoInput);
+ else
+ scheduleNavCallBack(kExtraCompletedFlag);
+ break;
+ case kWSC02MorphInterruption:
+ setCurrentActivation(kActivationMorphInterrupted);
+ GameState.setScoringSawMorphExperiment();
+ break;
+ case kWSC02TurnOffMorphScreen:
+ setCurrentActivation(kActivationMorphScreenOff);
+ GameState.setWSCSawMorph(true);
+ break;
+ case kW03NorthActivate:
+ if (GameState.getWSCAnalyzedDart() && !GameState.getWSCDesignedAntidote())
+ startExtraSequence(kW03NorthGetData, kExtraCompletedFlag, kFilterNoInput);
+ else
+ setCurrentActivation(kActivateHotSpotAlways);
+ break;
+ case kW03NorthGetData:
+ setCurrentActivation(kActivationW03NorthReadyForInstructions);
+ break;
+ case kW03NorthInstructions:
+ setCurrentActivation(kActivationW03NorthSawInstructions);
+ break;
+ case kW03NorthPrepMolecule1:
+ setUpMoleculeGame();
+ break;
+ case kW03NorthPrepMolecule2:
+ case kW03NorthPrepMolecule3:
+ nextMoleculeGameLevel();
+ break;
+ case kW03NorthFinishSynthesis:
+ setCurrentActivation(kActivateHotSpotAlways);
+ _privateFlags.setFlag(kWSCPrivateInMoleculeGameFlag, false);
+ GameState.setWSCDesignedAntidote(true);
+ GameState.setScoringBuiltAntidote();
+ break;
+ case kW03SouthCreateAntidote:
+ setCurrentActivation(kActivationSynthesizerLooping);
+ loopExtraSequence(kW03SouthAntidoteLoop);
+ break;
+ case kW03SouthDeactivate:
+ setCurrentActivation(kActivateHotSpotAlways);
+ break;
+ case kWSC07SouthMap:
+ case kWSC56SouthMap:
+ setCurrentActivation(kActivateHotSpotAlways);
+ GameState.setScoringSawWSCDirectory();
+ break;
+ case kNerdAtTheDoor1:
+ GameState.setWSCSeenNerd(true);
+ break;
+ case kNerdAtTheDoor2:
+ die(kDeathArrestedInWSC);
+ break;
+ case kW61Brochure:
+ GameState.setScoringSawBrochure();
+ loadAmbientLoops();
+ break;
+ case kW61SouthSmartAlloysWithGun:
+ case kW61SouthSmartAlloysNoGun:
+ GameState.setScoringSawSinclairEntry1();
+ break;
+ case kW61SouthMorphingWithGun:
+ case kW61SouthMorphingNoGun:
+ GameState.setScoringSawSinclairEntry2();
+ break;
+ case kW61SouthTimeBendingWithGun:
+ case kW61SouthTimeBendingNoGun:
+ GameState.setScoringSawSinclairEntry3();
+ break;
+ case kW61MessagesOn:
+ GameState.setWSCOfficeMessagesOpen(true);
+ setCurrentActivation(kActivationW61MessagesOn);
+ break;
+ case kW61MessagesOff:
+ GameState.setWSCOfficeMessagesOpen(false);
+ setCurrentActivation(kActivationW61MessagesOff);
+ if (_cachedZoomSpot) {
+ zoomTo(_cachedZoomSpot);
+ _cachedZoomSpot = 0;
+ }
+ break;
+ case kW61SouthScreenOnWithGun:
+ case kW61SouthScreenOnNoGun:
+ _privateFlags.setFlag(kWSCPrivateOfficeLogOpenFlag, true);
+ setCurrentActivation(kActivationW61SouthOn);
+ break;
+ case kW61SouthScreenOffWithGun:
+ case kW61SouthScreenOffNoGun:
+ _privateFlags.setFlag(kWSCPrivateOfficeLogOpenFlag, false);
+ setCurrentActivation(kActivationW61SouthOff);
+ if (_cachedZoomSpot) {
+ zoomTo(_cachedZoomSpot);
+ _cachedZoomSpot = 0;
+ }
+ break;
+ case kW62ZoomOutFromRobot:
+ // Handle action queue before starting new movie sequences.
+ Neighborhood::receiveNotification(notification, flags);
+ _energyDrainRate = g_energyMonitor->getEnergyDrainRate();
+ g_energyMonitor->setEnergyDrainRate(0);
+ currentEnergy = g_energyMonitor->getCurrentEnergy();
+ _vm->setEnergyDeathReason(kDeathHitByPlasma);
+
+ if (GameState.getShieldOn())
+ currentEnergy -= kPlasmaEnergyWithShield;
+ else
+ currentEnergy -= kPlasmaEnergyNoShield;
+
+ if (currentEnergy <= 0)
+ startExtraSequence(kW62PlasmaDodgeDie, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kW62PlasmaDodgeSurvive, kExtraCompletedFlag, kFilterNoInput);
+
+ scheduleEvent(kPlasmaImpactTime, kOneTickPerSecond, kTimerEventPlasmaHit);
+ break;
+ case kW62PlasmaDodgeDie:
+ g_energyMonitor->setEnergyValue(0);
+ break;
+ case kW62PlasmaDodgeSurvive:
+ if (GameState.getShieldOn()) {
+ g_shield->setItemState(kShieldNormal);
+ g_energyMonitor->drainEnergy(kPlasmaEnergyWithShield);
+ } else {
+ g_energyMonitor->drainEnergy(kPlasmaEnergyNoShield);
+ }
+
+ g_energyMonitor->setEnergyDrainRate(_energyDrainRate);
+ g_AIArea->unlockAI();
+ GameState.setScoringFinishedPlasmaDodge();
+ GameState.setWSCDidPlasmaDodge(true);
+ restoreStriding(kWSC58, kSouth, kAltWSCNormal);
+ loadAmbientLoops();
+ break;
+ case kW0ZSpottedByWomen:
+ die(kDeathArrestedInWSC);
+ break;
+ case kW17WestPeopleCrossing:
+ _privateFlags.setFlag(kWSCPrivateSeenPeopleAt17WestFlag, true);
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt17WestFlag, false);
+ break;
+ case kW21SouthPeopleCrossing:
+ _privateFlags.setFlag(kWSCPrivateSeenPeopleAt21SouthFlag, true);
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt21SouthFlag, true);
+ break;
+ case kW24SouthPeopleCrossing:
+ _privateFlags.setFlag(kWSCPrivateSeenPeopleAt24SouthFlag, true);
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt24SouthFlag, true);
+ break;
+ case kW34EastPeopleCrossing:
+ _privateFlags.setFlag(kWSCPrivateSeenPeopleAt34EastFlag, true);
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt34EastFlag, true);
+ break;
+ case kW36WestPeopleCrossing:
+ _privateFlags.setFlag(kWSCPrivateSeenPeopleAt36WestFlag, true);
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt36WestFlag, true);
+ break;
+ case kW38NorthPeopleCrossing:
+ _privateFlags.setFlag(kWSCPrivateSeenPeopleAt38NorthFlag, true);
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt38NorthFlag, true);
+ break;
+ case kW46SouthPeopleCrossing:
+ _privateFlags.setFlag(kWSCPrivateSeenPeopleAt46SouthFlag, true);
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt46SouthFlag, true);
+ break;
+ case kW49NorthPeopleCrossing:
+ _privateFlags.setFlag(kWSCPrivateSeenPeopleAt49NorthFlag, true);
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt49NorthFlag, false);
+ break;
+ case kW73WestPeopleCrossing:
+ _privateFlags.setFlag(kWSCPrivateSeenPeopleAt73WestFlag, true);
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt73WestFlag, false);
+ break;
+ case kW95RobotShoots:
+ case kW98RobotShoots:
+ die(kDeathShotOnCatwalk);
+ break;
+ case kW98MorphsToRobot:
+ if (_argonSprite) {
+ delete _argonSprite; _argonSprite = 0;
+ startExtraSequence(kW98RobotGassed, kExtraCompletedFlag, kFilterNoInput);
+ } else if (_privateFlags.getFlag(kWSCPrivateClickedCatwalkCableFlag)) {
+ startExtraSequence(kW98RobotShocked, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ startExtraSequence(kW98RobotShoots, kExtraCompletedFlag, kFilterNoInput);
+ }
+ break;
+ case kW98RobotShocked:
+ GameState.setWSCCatwalkDark(true);
+ // Change the gun hot spot...
+ _vm->getAllHotspots().setHotspotRect(kW98StunGunSpotID, Common::Rect(181 + kNavAreaLeft, 99 + kNavAreaTop,
+ 372 + kNavAreaLeft, 149 + kNavAreaTop));
+ setCurrentActivation(kActivationRobotDead);
+ GameState.setWSCRobotDead(true);
+ GameState.setScoringStoppedWSCRobot();
+
+ // Video is not present
+ //g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/WSC/XN59WD", false, kWarningInterruption);
+ break;
+ case kW98RobotGassed:
+ item = (Item *)_vm->getAllItems().findItemByID(kArgonCanister);
+ _vm->addItemToInventory((InventoryItem *)item);
+ setCurrentActivation(kActivationRobotDead);
+ GameState.setWSCRobotDead(true);
+ GameState.setScoringStoppedWSCRobot();
+
+ // Video is not present
+ //g_AIArea->playAIMovie(kRightAreaSignature, "Images/AI/WSC/XN59WD", false, kWarningInterruption);
+ break;
+ case kW98RobotHeadOpensLight:
+ case kW98RobotHeadOpensDark:
+ setCurrentActivation(kActivationWSCRobotHeadOpen);
+ _privateFlags.setFlag(kWSCPrivateRobotHeadOpenFlag, true);
+ break;
+ case kW98RobotHeadClosesDark:
+ case kW98RobotHeadClosesLight:
+ setCurrentActivation(kActivationRobotGone);
+ _privateFlags.setFlag(kWSCPrivateRobotHeadOpenFlag, false);
+ GameState.setWSCRobotGone(true);
+ break;
+ }
+ }
+
+ Neighborhood::receiveNotification(notification, flags);
+ g_AIArea->checkMiddleArea();
+}
+
+void WSC::timerExpired(const uint32 event) {
+ switch (event) {
+ case kTimerEventPlasmaHit:
+ if (GameState.getShieldOn())
+ g_shield->setItemState(kShieldPlasma);
+ break;
+ case kTimerEventPlayerGawkingAtRobot:
+ startExtraSequence(kW95RobotShoots, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kTimerEventPlayerGawkingAtRobot2:
+ startExtraSequence(kW98MorphsToRobot, kExtraCompletedFlag, kFilterAllInput);
+ break;
+ }
+}
+
+void WSC::setUpMoleculeGame() {
+ _privateFlags.setFlag(kWSCPrivateInMoleculeGameFlag, true);
+ setCurrentActivation(kActivationW03NorthInGame);
+ initOneMovie(&_moleculesMovie, "Images/World Science Center/Molecules.movie",
+ kWSCMoleculesMovieOrder, kMoleculesMovieLeft, kMoleculesMovieTop, true);
+ _moleculesMovie.redrawMovieWorld();
+ _moleculeBin.initMoleculeBin();
+ _moleculeGameLevel = 0;
+ nextMoleculeGameLevel();
+}
+
+void WSC::nextMoleculeGameLevel() {
+ _moleculeGameLevel++;
+
+ for (byte i = 0; i < 6; ++i)
+ _levelArray[i] = i;
+
+ _vm->shuffleArray((int32 *)_levelArray, 6);
+ _moleculeBin.setBinLayout(_levelArray);
+ startMoleculeGameLevel();
+}
+
+void WSC::startMoleculeGameLevel() {
+ _moleculeBin.resetBin();
+ _numCorrect = 0;
+ _moleculesMovie.stop();
+ _moleculesMovie.setFlags(0);
+ _moleculesMovie.setSegment(s_moleculeLoopTimes[0], s_moleculeLoopTimes[0] + kMoleculeLoopTime);
+ _moleculesMovie.setTime(s_moleculeLoopTimes[0]);
+ _moleculesMovie.setFlags(kLoopTimeBase);
+ _moleculesMovie.show();
+
+ switch (_moleculeGameLevel) {
+ case 1:
+ playSpotSoundSync(kWSCMolecule1In, kWSCMolecule1Out);
+ break;
+ case 2:
+ playSpotSoundSync(kWSCMolecule2In, kWSCMolecule2Out);
+ break;
+ case 3:
+ playSpotSoundSync(kWSCMolecule3In, kWSCMolecule3Out);
+ break;
+ }
+
+ _moleculesMovie.start();
+}
+
+void WSC::moleculeGameClick(const HotSpotID id) {
+ uint32 molecule = id - kWSC03NorthMolecule1SpotID;
+
+ _moleculeBin.highlightMolecule(molecule);
+ _moleculeBin.selectMolecule(molecule);
+
+ if (molecule == _levelArray[_numCorrect]) {
+ playSpotSoundSync(kWSCClick2In, kWSCClick2Out);
+ _numCorrect++;
+ _moleculesMovie.stop();
+ _moleculesMovie.setFlags(0);
+
+ TimeValue time = _moleculesMovie.getTime();
+ _moleculesMovie.setSegment(s_moleculeLoopTimes[_numCorrect], s_moleculeLoopTimes[_numCorrect] + kMoleculeLoopTime);
+ _moleculesMovie.setTime(s_moleculeLoopTimes[_numCorrect] + time - s_moleculeLoopTimes[_numCorrect - 1]);
+
+ if (_numCorrect == 6) {
+ _moleculesMovie.start();
+
+ while (_moleculesMovie.isRunning()) {
+ _vm->checkCallBacks();
+ _vm->refreshDisplay();
+ _vm->_system->delayMillis(10);
+ }
+
+ _moleculesMovie.stop();
+ _moleculesMovie.hide();
+
+ switch (_moleculeGameLevel) {
+ case 1:
+ startExtraSequence(kW03NorthPrepMolecule2, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case 2:
+ startExtraSequence(kW03NorthPrepMolecule3, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case 3:
+ _moleculesMovie.releaseMovie();
+ _moleculeBin.cleanUpMoleculeBin();
+ requestExtraSequence(kW03NorthFinishSynthesis, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ }
+ } else {
+ _moleculesMovie.setFlags(kLoopTimeBase);
+ _moleculesMovie.start();
+ }
+ } else {
+ // FAIL
+ playSpotSoundSync(kWSCClick3In, kWSCClick3Out);
+
+ _moleculesMovie.stop();
+ _moleculesMovie.setFlags(0);
+ _moleculesMovie.start();
+
+ while (_moleculesMovie.isRunning()) {
+ _vm->checkCallBacks();
+ _vm->refreshDisplay();
+ _vm->_system->delayMillis(10);
+ }
+
+ _moleculesMovie.stop();
+ _moleculesMovie.setFlags(0);
+ _moleculesMovie.setSegment(s_moleculeFailTimes[_numCorrect], s_moleculeFailTimes[_numCorrect] + kMoleculeFailTime);
+ _moleculesMovie.setTime(s_moleculeFailTimes[_numCorrect]);
+ _moleculesMovie.start();
+
+
+ while (_moleculesMovie.isRunning()) {
+ _vm->checkCallBacks();
+ _vm->refreshDisplay();
+ _vm->_system->delayMillis(10);
+ }
+
+ _moleculesMovie.stop();
+ startMoleculeGameLevel();
+ }
+}
+
+void WSC::activateOneHotspot(HotspotInfoTable::Entry &entry, Hotspot *hotspot) {
+ Neighborhood::activateOneHotspot(entry, hotspot);
+
+ Item *argonCanister;
+
+ switch (hotspot->getObjectID()) {
+ case kWSCTurnOnAnalyzerSpotID:
+ if (GameState.getWSCAnalyzerOn())
+ hotspot->setInactive();
+ break;
+ case kWSC02SouthTakeArgonSpotID:
+ if (!GameState.getWSCSawMorph() || GameState.isTakenItemID(kArgonCanister))
+ hotspot->setInactive();
+ break;
+ case kWSC02ActivateMorphScreenSpotID:
+ if (GameState.getWSCSawMorph())
+ hotspot->setInactive();
+ break;
+ case kWSC03NorthMolecule1SpotID:
+ case kWSC03NorthMolecule2SpotID:
+ case kWSC03NorthMolecule3SpotID:
+ case kWSC03NorthMolecule4SpotID:
+ case kWSC03NorthMolecule5SpotID:
+ case kWSC03NorthMolecule6SpotID:
+ if (_moleculeBin.isMoleculeHighlighted(hotspot->getObjectID() - kWSC03NorthMolecule1SpotID))
+ hotspot->setInactive();
+ break;
+ case kWSC03SouthPickUpAntidoteSpotID:
+ if (getCurrentActivation() == kActivationSynthesizerLooping)
+ hotspot->setActive();
+ break;
+ case kW98DropArgonSpotID:
+ argonCanister = _vm->getAllItems().findItemByID(kArgonCanister);
+ if (argonCanister->getItemState() != kArgonFull)
+ hotspot->setInactive();
+ break;
+ }
+}
+
+void WSC::activateHotspots() {
+ Neighborhood::activateHotspots();
+
+ if (GameState.getCurrentRoomAndView() == MakeRoomView(kWSC98, kWest) && _privateFlags.getFlag(kWSCPrivateRobotHeadOpenFlag)) {
+ if (_privateFlags.getFlag(kWSCPrivateGotRetScanChipFlag))
+ _vm->getAllHotspots().deactivateOneHotspot(kW98RetinalChipSpotID);
+ else
+ _vm->getAllHotspots().activateOneHotspot(kW98RetinalChipSpotID);
+
+ if (_privateFlags.getFlag(kWSCPrivateGotMapChipFlag))
+ _vm->getAllHotspots().deactivateOneHotspot(kW98MapChipSpotID);
+ else
+ _vm->getAllHotspots().activateOneHotspot(kW98MapChipSpotID);
+
+ if (_privateFlags.getFlag(kWSCPrivateGotOpticalChipFlag))
+ _vm->getAllHotspots().deactivateOneHotspot(kW98OpticalChipSpotID);
+ else
+ _vm->getAllHotspots().activateOneHotspot(kW98OpticalChipSpotID);
+ }
+}
+
+void WSC::clickInHotspot(const Input &input, const Hotspot *clickedSpot) {
+ if (JMPPPInput::isEasterEggModifierInput(input))
+ GameState.setEasterEgg(true);
+
+ if (clickedSpot) {
+ switch (clickedSpot->getObjectID()) {
+ case kWSCAnalyzerScreenSpotID:
+ requestExtraSequence(kWSCAnalyzeDart, kExtraCompletedFlag, kFilterNoInput);
+ requestExtraSequence(kWSCZoomOutFromAnalyzer, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kWSC02SouthPlayMessagesSpotID:
+ if (GameState.isTakenItemID(kNitrogenCanister)) {
+ if (_lastExtra == (uint32)kMessagesMovedToOfficeNoNitrogen)
+ startExtraSequence(kMessagesOffNoNitrogen, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kMessagesMovedToOfficeNoNitrogen, kExtraCompletedFlag, kFilterNoInput);
+ } else {
+ if (_lastExtra == (uint32)kMessagesMovedToOffice)
+ startExtraSequence(kMessagesOff, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kMessagesMovedToOffice, kExtraCompletedFlag, kFilterNoInput);
+ }
+ break;
+ case kWSC02SouthInterruptMorphSpotID:
+ _privateFlags.setFlag(kWSCPrivateInterruptedMorphFlag, true);
+ break;
+ case kWSC02SouthMorphFinishedSpotID:
+ requestExtraSequence(kWSC02MorphFinished, 0, kFilterNoInput);
+ requestExtraSequence(kWSC02TurnOffMorphScreen, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case kWSC03NorthMolecule1SpotID:
+ case kWSC03NorthMolecule2SpotID:
+ case kWSC03NorthMolecule3SpotID:
+ case kWSC03NorthMolecule4SpotID:
+ case kWSC03NorthMolecule5SpotID:
+ case kWSC03NorthMolecule6SpotID:
+ moleculeGameClick(clickedSpot->getObjectID());
+ break;
+ case kW98GrabCableSpotID:
+ if (isEventTimerRunning()) {
+ cancelEvent();
+ startExtraSequence(kW98MorphsToRobot, kExtraCompletedFlag, kFilterAllInput);
+ }
+
+ _privateFlags.setFlag(kWSCPrivateClickedCatwalkCableFlag, true);
+ break;
+ default:
+ Neighborhood::clickInHotspot(input, clickedSpot);
+ break;
+ }
+ } else {
+ Neighborhood::clickInHotspot(input, clickedSpot);
+ }
+
+ GameState.setEasterEgg(false);
+}
+
+void WSC::dropItemIntoRoom(Item *item, Hotspot *dropSpot) {
+ CoordType h, v;
+
+ switch (item->getObjectID()) {
+ case kPoisonDart:
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ GameState.setWSCDartInAnalyzer(true);
+ if (dropSpot && dropSpot->getObjectID() == kWSCDropDartSpotID) {
+ if (!GameState.getWSCAnalyzerOn())
+ requestExtraSequence(kWSCAnalyzerPowerUpWithDart, kExtraCompletedFlag, kFilterNoInput);
+
+ requestExtraSequence(kWSCDropDartIntoAnalyzer, kExtraCompletedFlag, kFilterNoInput);
+ }
+ break;
+ case kAntidote:
+ _privateFlags.setFlag(kWSCDraggingAntidoteFlag, false);
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ loopExtraSequence(kW03SouthAntidoteLoop);
+ break;
+ case kSinclairKey:
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ _privateFlags.setFlag(kWSCPrivateSinclairOfficeOpenFlag, true);
+ openDoor();
+ break;
+ case kCrowbar:
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ _privateFlags.setFlag(kWSCPrivate58SouthOpenFlag, true);
+ openDoor();
+ break;
+ case kMachineGun:
+ setCurrentAlternate(kAltWSCNormal);
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ break;
+ case kArgonCanister:
+ item->setItemState(kArgonEmpty);
+ _argonSprite = item->getDragSprite(0);
+ _argonSprite->setCurrentFrameIndex(1);
+ _argonSprite->setDisplayOrder(kDragSpriteOrder);
+ dropSpot->getCenter(h, v);
+ _argonSprite->centerElementAt(h, v);
+ _argonSprite->startDisplaying();
+ _argonSprite->show();
+
+ if (isEventTimerRunning()) {
+ cancelEvent();
+ startExtraSequence(kW98MorphsToRobot, kExtraCompletedFlag, kFilterAllInput);
+ }
+ break;
+ case kRetinalScanBiochip:
+ _privateFlags.setFlag(kWSCPrivateGotRetScanChipFlag, false);
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ break;
+ case kMapBiochip:
+ _privateFlags.setFlag(kWSCPrivateGotMapChipFlag, false);
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ break;
+ case kOpticalBiochip:
+ _privateFlags.setFlag(kWSCPrivateGotOpticalChipFlag, false);
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ break;
+ default:
+ Neighborhood::dropItemIntoRoom(item, dropSpot);
+ break;
+ }
+}
+
+void WSC::takeItemFromRoom(Item *item) {
+ switch (item->getObjectID()) {
+ case kAntidote:
+ _privateFlags.setFlag(kWSCDraggingAntidoteFlag, true);
+ Neighborhood::takeItemFromRoom(item);
+ break;
+ case kMachineGun:
+ setCurrentAlternate(kAltWSCTookMachineGun);
+ Neighborhood::takeItemFromRoom(item);
+ break;
+ case kRetinalScanBiochip:
+ _privateFlags.setFlag(kWSCPrivateGotRetScanChipFlag, true);
+ Neighborhood::takeItemFromRoom(item);
+ break;
+ case kMapBiochip:
+ _privateFlags.setFlag(kWSCPrivateGotMapChipFlag, true);
+ Neighborhood::takeItemFromRoom(item);
+ break;
+ case kOpticalBiochip:
+ _privateFlags.setFlag(kWSCPrivateGotOpticalChipFlag, true);
+ Neighborhood::takeItemFromRoom(item);
+ break;
+ default:
+ Neighborhood::takeItemFromRoom(item);
+ break;
+ }
+}
+
+Hotspot *WSC::getItemScreenSpot(Item *item, DisplayElement *element) {
+ HotSpotID destSpotID;
+
+ switch (item->getObjectID()) {
+ case kNitrogenCanister:
+ destSpotID = kWSC02SouthTakeNitrogenSpotID;
+ break;
+ case kArgonPickup:
+ destSpotID = kWSC02SouthTakeArgonSpotID;
+ break;
+ case kAntidote:
+ destSpotID = kWSC03SouthPickUpAntidoteSpotID;
+ break;
+ case kMachineGun:
+ destSpotID = kW61SouthMachineGunSpotID;
+ break;
+ case kRetinalScanBiochip:
+ destSpotID = kW98RetinalChipSpotID;
+ break;
+ case kMapBiochip:
+ destSpotID = kW98MapChipSpotID;
+ break;
+ case kOpticalBiochip:
+ destSpotID = kW98OpticalChipSpotID;
+ break;
+ default:
+ destSpotID = kNoHotSpotID;
+ break;
+ }
+
+ if (destSpotID == kNoHotSpotID)
+ return Neighborhood::getItemScreenSpot(item, element);
+
+ return _vm->getAllHotspots().findHotspotByID(destSpotID);
+}
+
+void WSC::pickedUpItem(Item *item) {
+ switch (item->getObjectID()) {
+ case kAntidote:
+ if (!GameState.getWSCPickedUpAntidote()) {
+ GameState.setWSCPoisoned(false);
+ GameState.setWSCRemovedDart(false);
+ GameState.setWSCPickedUpAntidote(true);
+ _privateFlags.setFlag(kWSCDraggingAntidoteFlag, false);
+ playSpotSoundSync(kDrinkAntidoteIn, kDrinkAntidoteOut);
+ setUpPoison();
+ startExtraSequence(kW03SouthDeactivate, kExtraCompletedFlag, kFilterNoInput);
+ }
+ break;
+ case kArgonPickup:
+ _vm->removeItemFromInventory((InventoryItem *)item);
+ item = (Item *)_vm->getAllItems().findItemByID(kArgonCanister);
+ _vm->addItemToInventory((InventoryItem *)item);
+ item = (Item *)_vm->getAllItems().findItemByID(kSinclairKey);
+ _vm->addItemToInventory((InventoryItem *)item);
+ _vm->getAllHotspots().setHotspotRect(kWSC02SouthMorphOutSpotID,
+ Common::Rect(kNavAreaLeft, kNavAreaTop, 512 + kNavAreaLeft, 256 + kNavAreaTop));
+ break;
+ case kArgonCanister:
+ GameState.setScoringGotArgonCanister();
+ break;
+ case kSinclairKey:
+ GameState.setScoringGotSinclairKey();
+ break;
+ case kNitrogenCanister:
+ GameState.setScoringGotNitrogenCanister();
+ break;
+ case kRetinalScanBiochip:
+ if (_privateFlags.getFlag(kWSCPrivateGotMapChipFlag) && _privateFlags.getFlag(kWSCPrivateGotOpticalChipFlag)) {
+ if (GameState.getWSCCatwalkDark())
+ startExtraSequence(kW98RobotHeadClosesDark, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kW98RobotHeadClosesLight, kExtraCompletedFlag, kFilterNoInput);
+ }
+ break;
+ case kMapBiochip:
+ if (_privateFlags.getFlag(kWSCPrivateGotRetScanChipFlag) && _privateFlags.getFlag(kWSCPrivateGotOpticalChipFlag)) {
+ if (GameState.getWSCCatwalkDark())
+ startExtraSequence(kW98RobotHeadClosesDark, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kW98RobotHeadClosesLight, kExtraCompletedFlag, kFilterNoInput);
+ }
+ break;
+ case kOpticalBiochip:
+ g_opticalChip->addMercury();
+ GameState.setScoringGotWSCOpMemChip();
+ if (_privateFlags.getFlag(kWSCPrivateGotRetScanChipFlag) && _privateFlags.getFlag(kWSCPrivateGotMapChipFlag)) {
+ if (GameState.getWSCCatwalkDark())
+ startExtraSequence(kW98RobotHeadClosesDark, kExtraCompletedFlag, kFilterNoInput);
+ else
+ startExtraSequence(kW98RobotHeadClosesLight, kExtraCompletedFlag, kFilterNoInput);
+ }
+ break;
+ case kStunGun:
+ GameState.setWSCFinished(true);
+
+ if (!GameState.getWSCCatwalkDark())
+ GameState.setScoringWSCGandhi();
+
+ recallToTSASuccess();
+ break;
+ }
+}
+
+void WSC::checkPeopleCrossing() {
+ switch (GameState.getCurrentRoomAndView()) {
+ case MakeRoomView(kWSC17, kWest):
+ if (_privateFlags.getFlag(kWSCPrivateNeedPeopleAt17WestFlag))
+ startExtraSequence(kW17WestPeopleCrossing, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case MakeRoomView(kWSC21, kSouth):
+ if (_privateFlags.getFlag(kWSCPrivateNeedPeopleAt21SouthFlag))
+ startExtraSequence(kW21SouthPeopleCrossing, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case MakeRoomView(kWSC24, kSouth):
+ if (_privateFlags.getFlag(kWSCPrivateNeedPeopleAt24SouthFlag))
+ startExtraSequence(kW24SouthPeopleCrossing, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case MakeRoomView(kWSC34, kEast):
+ if (_privateFlags.getFlag(kWSCPrivateNeedPeopleAt34EastFlag))
+ startExtraSequence(kW34EastPeopleCrossing, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case MakeRoomView(kWSC36, kWest):
+ if (_privateFlags.getFlag(kWSCPrivateNeedPeopleAt36WestFlag))
+ startExtraSequence(kW36WestPeopleCrossing, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case MakeRoomView(kWSC38, kNorth):
+ if (_privateFlags.getFlag(kWSCPrivateNeedPeopleAt38NorthFlag))
+ startExtraSequence(kW38NorthPeopleCrossing, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case MakeRoomView(kWSC46, kSouth):
+ if (_privateFlags.getFlag(kWSCPrivateNeedPeopleAt46SouthFlag))
+ startExtraSequence(kW46SouthPeopleCrossing, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case MakeRoomView(kWSC49, kNorth):
+ if (_privateFlags.getFlag(kWSCPrivateNeedPeopleAt49NorthFlag))
+ startExtraSequence(kW49NorthPeopleCrossing, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ case MakeRoomView(kWSC73, kWest):
+ if (_privateFlags.getFlag(kWSCPrivateNeedPeopleAt73WestFlag))
+ startExtraSequence(kW73WestPeopleCrossing, kExtraCompletedFlag, kFilterNoInput);
+ break;
+ default:
+ if (!_privateFlags.getFlag(kWSCPrivateSeenPeopleAt21SouthFlag) && _vm->getRandomNumber(2) == 0) {
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt21SouthFlag, true);
+ forceStridingStop(kWSC18, kSouth, kAltWSCNormal);
+ } else {
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt21SouthFlag, false);
+ restoreStriding(kWSC18, kSouth, kAltWSCNormal);
+ }
+
+ if (!_privateFlags.getFlag(kWSCPrivateSeenPeopleAt19NorthFlag) && _vm->getRandomNumber(2) == 0) {
+ forceStridingStop(kWSC22, kNorth, kAltWSCNormal);
+ } else {
+ restoreStriding(kWSC22, kNorth, kAltWSCNormal);
+ }
+
+ if (!_privateFlags.getFlag(kWSCPrivateSeenPeopleAt24SouthFlag) && _vm->getRandomNumber(2) == 0) {
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt24SouthFlag, true);
+ forceStridingStop(kWSC22, kSouth, kAltWSCNormal);
+ } else {
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt24SouthFlag, false);
+ restoreStriding(kWSC22, kSouth, kAltWSCNormal);
+ }
+
+ if (!_privateFlags.getFlag(kWSCPrivateSeenPeopleAt34EastFlag) && _vm->getRandomNumber(2) == 0) {
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt34EastFlag, true);
+ forceStridingStop(kWSC28, kEast, kAltWSCNormal);
+ } else {
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt34EastFlag, false);
+ restoreStriding(kWSC28, kEast, kAltWSCNormal);
+ }
+
+ if (!_privateFlags.getFlag(kWSCPrivateSeenPeopleAt36WestFlag) && _vm->getRandomNumber(2) == 0) {
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt36WestFlag, true);
+ forceStridingStop(kWSC40, kWest, kAltWSCNormal);
+ } else {
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt36WestFlag, false);
+ restoreStriding(kWSC40, kWest, kAltWSCNormal);
+ }
+
+ if (!_privateFlags.getFlag(kWSCPrivateSeenPeopleAt38NorthFlag) && _vm->getRandomNumber(2) == 0) {
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt38NorthFlag, true);
+ forceStridingStop(kWSC42, kNorth, kAltWSCNormal);
+ } else {
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt38NorthFlag, false);
+ restoreStriding(kWSC42, kNorth, kAltWSCNormal);
+ }
+
+ if (!_privateFlags.getFlag(kWSCPrivateSeenPeopleAt46SouthFlag) && _vm->getRandomNumber(2) == 0) {
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt46SouthFlag, true);
+ forceStridingStop(kWSC44, kSouth, kAltWSCNormal);
+ } else {
+ _privateFlags.setFlag(kWSCPrivateNeedPeopleAt46SouthFlag, false);
+ restoreStriding(kWSC44, kSouth, kAltWSCNormal);
+ }
+ break;
+ }
+}
+
+void WSC::setUpPoison() {
+ if (GameState.getWSCPoisoned()) {
+ if (GameState.getWSCRemovedDart()) {
+ if (g_energyMonitor->getEnergyDrainRate() != kWSCPoisonEnergyDrainNoDart) {
+ g_energyMonitor->setEnergyDrainRate(kWSCPoisonEnergyDrainNoDart);
+ _vm->setEnergyDeathReason(kDeathDidntStopPoison);
+ }
+ } else {
+ if (g_energyMonitor->getEnergyDrainRate() != kWSCPoisonEnergyDrainWithDart) {
+ g_energyMonitor->setEnergyDrainRate(kWSCPoisonEnergyDrainWithDart);
+ _vm->setEnergyDeathReason(kDeathDidntStopPoison);
+ }
+ }
+ } else if (g_energyMonitor->getEnergyDrainRate() != kEnergyDrainNormal) {
+ g_energyMonitor->setEnergyDrainRate(kEnergyDrainNormal);
+ _vm->resetEnergyDeathReason();
+ }
+}
+
+bool WSC::inSynthesizerGame() {
+ return _moleculesMovie.isMovieValid();
+}
+
+bool WSC::canSolve() {
+ return (inSynthesizerGame() || (GameState.getCurrentRoom() == kWSC98 && !GameState.getWSCRobotDead()));
+}
+
+void WSC::doSolve() {
+ if (inSynthesizerGame()) {
+ _moleculesMovie.releaseMovie();
+ _moleculeBin.cleanUpMoleculeBin();
+ requestExtraSequence(kW03NorthFinishSynthesis, kExtraCompletedFlag, kFilterNoInput);
+ } else if (GameState.getCurrentRoom() == kWSC98 && !GameState.getWSCRobotDead()) {
+ cancelEvent();
+ startExtraSequence(kW98RobotShocked, kExtraCompletedFlag, kFilterNoInput);
+ }
+}
+
+Common::String WSC::getNavMovieName() {
+ return "Images/World Science Center/WSC.movie";
+}
+
+Common::String WSC::getSoundSpotsName() {
+ return "Sounds/World Science Center/WSC Spots";
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/wsc/wsc.h b/engines/pegasus/neighborhood/wsc/wsc.h
new file mode 100644
index 0000000000..d9634b3539
--- /dev/null
+++ b/engines/pegasus/neighborhood/wsc/wsc.h
@@ -0,0 +1,166 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_WSC_WSC_H
+#define PEGASUS_NEIGHBORHOOD_WSC_WSC_H
+
+#include "pegasus/neighborhood/neighborhood.h"
+#include "pegasus/neighborhood/wsc/moleculebin.h"
+
+namespace Pegasus {
+
+static const DisplayOrder kWSCMoleculeBinOrder = kMonitorLayer;
+static const DisplayOrder kWSCMoleculesMovieOrder = kWSCMoleculeBinOrder + 1;
+
+static const RoomID kWSC01 = 0;
+static const RoomID kWSC02Morph = 2;
+static const RoomID kWSC02Messages = 3;
+static const RoomID kWSC62 = 62;
+
+class WSC : public Neighborhood {
+public:
+ WSC(InputHandler *, PegasusEngine *);
+ virtual ~WSC() {}
+
+ void flushGameState();
+
+ virtual uint16 getDateResID() const;
+
+ bool okayToJump();
+
+ void checkContinuePoint(const RoomID, const DirectionConstant);
+
+ bool inSynthesizerGame();
+
+ bool canSolve();
+ void doSolve();
+
+ virtual void prepareForAIHint(const Common::String &);
+ virtual void cleanUpAfterAIHint(const Common::String &);
+
+ void init();
+ void start();
+
+protected:
+ enum {
+ kWSCDraggingAntidoteFlag,
+
+ kWSCPrivateLabMessagesOpenFlag,
+ kWSCPrivateInterruptedMorphFlag,
+ kWSCPrivateInMoleculeGameFlag,
+ kWSCPrivateSinclairOfficeOpenFlag,
+ kWSCPrivateOfficeLogOpenFlag,
+ kWSCPrivate58SouthOpenFlag,
+ kWSCPrivateClickedCatwalkCableFlag,
+ kWSCPrivateRobotHeadOpenFlag,
+
+ kWSCPrivateSeenPeopleAt17WestFlag,
+ kWSCPrivateSeenPeopleAt19NorthFlag,
+ kWSCPrivateSeenPeopleAt21SouthFlag,
+ kWSCPrivateSeenPeopleAt24SouthFlag,
+ kWSCPrivateSeenPeopleAt34EastFlag,
+ kWSCPrivateSeenPeopleAt36WestFlag,
+ kWSCPrivateSeenPeopleAt38NorthFlag,
+ kWSCPrivateSeenPeopleAt46SouthFlag,
+ kWSCPrivateSeenPeopleAt49NorthFlag,
+ kWSCPrivateSeenPeopleAt73WestFlag,
+
+ kWSCPrivateNeedPeopleAt17WestFlag,
+ kWSCPrivateNeedPeopleAt21SouthFlag,
+ kWSCPrivateNeedPeopleAt24SouthFlag,
+ kWSCPrivateNeedPeopleAt34EastFlag,
+ kWSCPrivateNeedPeopleAt36WestFlag,
+ kWSCPrivateNeedPeopleAt38NorthFlag,
+ kWSCPrivateNeedPeopleAt46SouthFlag,
+ kWSCPrivateNeedPeopleAt49NorthFlag,
+ kWSCPrivateNeedPeopleAt73WestFlag,
+
+ kWSCPrivateGotRetScanChipFlag,
+ kWSCPrivateGotMapChipFlag,
+ kWSCPrivateGotOpticalChipFlag,
+
+ kNumWSCPrivateFlags
+ };
+
+ void arriveAt(const RoomID, const DirectionConstant);
+ void turnTo(const DirectionConstant);
+ void receiveNotification(Notification *, const NotificationFlags);
+ void dropItemIntoRoom(Item *, Hotspot *);
+ void clickInHotspot(const Input &, const Hotspot *);
+ TimeValue getViewTime(const RoomID, const DirectionConstant);
+ void getZoomEntry(const HotSpotID, ZoomTable::Entry &);
+ CanMoveForwardReason canMoveForward(ExitTable::Entry &entry);
+ void cantMoveThatWay(CanMoveForwardReason reason);
+ CanTurnReason canTurn(TurnDirection turn, DirectionConstant &nextDir);
+ void zoomTo(const Hotspot *hotspot);
+ void activateOneHotspot(HotspotInfoTable::Entry &, Hotspot *);
+ void setUpMoleculeGame();
+ void nextMoleculeGameLevel();
+ void startMoleculeGameLevel();
+ void moleculeGameClick(const HotSpotID);
+ void loadAmbientLoops();
+ CanOpenDoorReason canOpenDoor(DoorTable::Entry &);
+ void cantOpenDoor(CanOpenDoorReason);
+ void pickedUpItem(Item *);
+ void doorOpened();
+ void startExtraSequence(const ExtraID, const NotificationFlags, const InputBits);
+ void getExtraEntry(const uint32, ExtraTable::Entry &);
+ void takeItemFromRoom(Item *item);
+ void checkPeopleCrossing();
+ void turnLeft();
+ void turnRight();
+ void moveForward();
+ Hotspot *getItemScreenSpot(Item *, DisplayElement *);
+ int16 getStaticCompassAngle(const RoomID, const DirectionConstant);
+ void getExitCompassMove(const ExitTable::Entry &exitEntry, FaderMoveSpec &compassMove);
+ void getExtraCompassMove(const ExtraTable::Entry &entry, FaderMoveSpec &compassMove);
+ void bumpIntoWall();
+ void activateHotspots();
+ void setUpAIRules();
+ Common::String getBriefingMovie();
+ Common::String getEnvScanMovie();
+ uint getNumHints();
+ Common::String getHintMovie(uint);
+ void closeDoorOffScreen(const RoomID, const DirectionConstant);
+ void setUpPoison();
+ void findSpotEntry(const RoomID, const DirectionConstant, SpotFlags, SpotTable::Entry &);
+ void timerExpired(const uint32);
+
+ Common::String getSoundSpotsName();
+ Common::String getNavMovieName();
+
+ FlagsArray<byte, kNumWSCPrivateFlags> _privateFlags;
+ const Hotspot *_cachedZoomSpot;
+ MoleculeBin _moleculeBin;
+ int32 _moleculeGameLevel, _numCorrect;
+ Movie _moleculesMovie;
+ uint32 _levelArray[6];
+ Common::Rational _energyDrainRate;
+ Sprite *_argonSprite;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/neighborhood/zoom.cpp b/engines/pegasus/neighborhood/zoom.cpp
new file mode 100644
index 0000000000..478ec6e493
--- /dev/null
+++ b/engines/pegasus/neighborhood/zoom.cpp
@@ -0,0 +1,74 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/debug.h"
+#include "common/stream.h"
+#include "common/textconsole.h"
+
+#include "pegasus/neighborhood/zoom.h"
+
+namespace Pegasus {
+
+void ZoomTable::loadFromStream(Common::SeekableReadStream *stream) {
+ uint32 count = stream->readUint32BE();
+ _entries.resize(count);
+
+ for (uint32 i = 0; i < count; i++) {
+ _entries[i].hotspot = stream->readUint16BE();
+ _entries[i].movieStart = stream->readUint32BE();
+ _entries[i].movieEnd = stream->readUint32BE();
+ _entries[i].room = stream->readUint16BE();
+ _entries[i].direction = stream->readByte();
+ debug(0, "Zoom[%d]: %d %d %d %d %d", i, _entries[i].hotspot, _entries[i].movieStart,
+ _entries[i].movieEnd, _entries[i].room, _entries[i].direction);
+ stream->readByte(); // alignment
+ }
+}
+
+void ZoomTable::clear() {
+ _entries.clear();
+}
+
+ZoomTable::Entry::Entry() {
+ clear();
+}
+
+void ZoomTable::Entry::clear() {
+ hotspot = kNoHotSpotID;
+ movieStart = 0xffffffff;
+ movieEnd = 0xffffffff;
+ room = kNoRoomID;
+ direction = kNoDirection;
+}
+
+ZoomTable::Entry ZoomTable::findEntry(HotSpotID hotspot) {
+ for (uint32 i = 0; i < _entries.size(); i++)
+ if (_entries[i].hotspot == hotspot)
+ return _entries[i];
+
+ return Entry();
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/zoom.h b/engines/pegasus/neighborhood/zoom.h
new file mode 100644
index 0000000000..8bcf8974f8
--- /dev/null
+++ b/engines/pegasus/neighborhood/zoom.h
@@ -0,0 +1,70 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NEIGHBORHOOD_ZOOM_H
+#define PEGASUS_NEIGHBORHOOD_ZOOM_H
+
+#include "common/array.h"
+#include "common/endian.h"
+
+#include "pegasus/constants.h"
+
+namespace Common {
+ class SeekableReadStream;
+}
+
+namespace Pegasus {
+
+class ZoomTable {
+public:
+ ZoomTable() {}
+ ~ZoomTable() {}
+
+ static uint32 getResTag() { return MKTAG('Z', 'o', 'o', 'm'); }
+
+ void loadFromStream(Common::SeekableReadStream *stream);
+ void clear();
+
+ struct Entry {
+ Entry();
+ void clear();
+ bool isEmpty() { return movieStart == 0xffffffff; }
+
+ HotSpotID hotspot;
+ TimeValue movieStart;
+ TimeValue movieEnd;
+ RoomID room;
+ DirectionConstant direction;
+ };
+
+ Entry findEntry(HotSpotID hotspot);
+
+private:
+ Common::Array<Entry> _entries;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/notification.cpp b/engines/pegasus/notification.cpp
new file mode 100644
index 0000000000..2d57fcc5e7
--- /dev/null
+++ b/engines/pegasus/notification.cpp
@@ -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.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/constants.h"
+#include "pegasus/notification.h"
+
+namespace Pegasus {
+
+typedef ReceiverList::iterator ReceiverIterator;
+
+Notification::Notification(const NotificationID id, NotificationManager *owner) : IDObject(id) {
+ _owner = owner;
+ _currentFlags = kNoNotificationFlags;
+ if (_owner)
+ _owner->addNotification(this);
+}
+
+Notification::~Notification() {
+ for (uint i = 0; i < _receivers.size(); i++)
+ _receivers[i].receiver->newNotification(NULL);
+
+ if (_owner)
+ _owner->removeNotification(this);
+}
+
+// Selectively set or clear notificiation bits.
+// Wherever mask is 0, leave existing bits untouched.
+// Wherever mask is 1, set bit equivalent to flags.
+void Notification::notifyMe(NotificationReceiver *receiver, NotificationFlags flags, NotificationFlags mask) {
+ for (uint i = 0; i < _receivers.size(); i++) {
+ if (_receivers[i].receiver == receiver) {
+ _receivers[i].mask = (_receivers[i].mask & ~mask) | (flags & mask);
+ receiver->newNotification(this);
+ return;
+ }
+ }
+
+ ReceiverEntry newEntry;
+ newEntry.receiver = receiver;
+ newEntry.mask = flags;
+ _receivers.push_back(newEntry);
+
+ receiver->newNotification(this);
+}
+
+void Notification::cancelNotification(NotificationReceiver *receiver) {
+ for (uint i = 0; i < _receivers.size(); i++) {
+ if (_receivers[i].receiver == receiver) {
+ _receivers.remove_at(i);
+ i--;
+ }
+ }
+}
+
+void Notification::setNotificationFlags(NotificationFlags flags, NotificationFlags mask) {
+ _currentFlags = (_currentFlags & ~mask) | flags;
+}
+
+void Notification::checkReceivers() {
+ NotificationFlags currentFlags = _currentFlags;
+ _currentFlags = kNoNotificationFlags;
+
+ for (uint i = 0; i < _receivers.size(); i++)
+ if (_receivers[i].mask & currentFlags)
+ _receivers[i].receiver->receiveNotification(this, currentFlags);
+}
+
+// Receiver entries are equal if their receivers are equal.
+
+int operator==(const ReceiverEntry &entry1, const ReceiverEntry &entry2) {
+ return entry1.receiver == entry2.receiver;
+}
+
+int operator!=(const ReceiverEntry &entry1, const ReceiverEntry &entry2) {
+ return entry1.receiver != entry2.receiver;
+}
+
+NotificationReceiver::NotificationReceiver() {
+ _notification = NULL;
+}
+
+NotificationReceiver::~NotificationReceiver() {
+ if (_notification)
+ _notification->cancelNotification(this);
+}
+
+void NotificationReceiver::receiveNotification(Notification *, const NotificationFlags) {
+}
+
+void NotificationReceiver::newNotification(Notification *notification) {
+ _notification = notification;
+}
+
+typedef NotificationList::iterator NotificationIterator;
+
+NotificationManager::NotificationManager() {
+}
+
+NotificationManager::~NotificationManager() {
+ detachNotifications();
+}
+
+void NotificationManager::addNotification(Notification *notification) {
+ _notifications.push_back(notification);
+}
+
+void NotificationManager::removeNotification(Notification *notification) {
+ for (NotificationIterator it = _notifications.begin(); it != _notifications.end();) {
+ if ((*it) == notification)
+ it = _notifications.erase(it);
+ else
+ it++;
+ }
+}
+
+void NotificationManager::detachNotifications() {
+ for (NotificationIterator it = _notifications.begin(); it != _notifications.end(); it++)
+ (*it)->_owner = 0;
+}
+
+void NotificationManager::checkNotifications() {
+ for (NotificationIterator it = _notifications.begin(); it != _notifications.end(); it++)
+ if ((*it)->_currentFlags != kNoNotificationFlags)
+ (*it)->checkReceivers();
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/notification.h b/engines/pegasus/notification.h
new file mode 100644
index 0000000000..19b69829be
--- /dev/null
+++ b/engines/pegasus/notification.h
@@ -0,0 +1,123 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_NOTIFICATION_H
+#define PEGASUS_NOTIFICATION_H
+
+#include "common/array.h"
+#include "common/list.h"
+
+#include "pegasus/types.h"
+#include "pegasus/util.h"
+
+namespace Pegasus {
+
+class NotificationManager;
+class NotificationReceiver;
+
+struct ReceiverEntry {
+ NotificationReceiver *receiver;
+ NotificationFlags mask;
+};
+
+int operator==(const ReceiverEntry &entry1, const ReceiverEntry &entry2);
+int operator!=(const ReceiverEntry &entry1, const ReceiverEntry &entry2);
+
+typedef Common::Array<ReceiverEntry> ReceiverList;
+
+/*
+ A notification can have 32 flags associated with it, which can be user-defined.
+*/
+
+class Notification : public IDObject {
+friend class NotificationManager;
+
+public:
+ Notification(const NotificationID id, NotificationManager *owner);
+ virtual ~Notification();
+
+ // notifyMe will have this receiver notified when any of the specified notification
+ // flags are set.
+ // If there is already a notification set for this receiver, notifyMe does a bitwise
+ // OR with the receiver's current notification flags.
+
+ // Can selectively set or clear notification bits by using the flags and mask argument.
+
+ void notifyMe(NotificationReceiver*, NotificationFlags flags, NotificationFlags mask);
+ void cancelNotification(NotificationReceiver *receiver);
+
+ void setNotificationFlags(NotificationFlags flags, NotificationFlags mask);
+ NotificationFlags getNotificationFlags() { return _currentFlags; }
+
+ void clearNotificationFlags() { setNotificationFlags(0, ~(NotificationFlags)0); }
+
+protected:
+ void checkReceivers();
+
+ NotificationManager *_owner;
+ ReceiverList _receivers;
+ NotificationFlags _currentFlags;
+};
+
+class NotificationReceiver {
+friend class Notification;
+
+public:
+ NotificationReceiver();
+ virtual ~NotificationReceiver();
+
+protected:
+ // receiveNotification is called automatically whenever a notification that this
+ // receiver depends on has its flags set
+
+ virtual void receiveNotification(Notification *, const NotificationFlags);
+ virtual void newNotification(Notification *notification);
+
+private:
+ Notification *_notification;
+};
+
+typedef Common::List<Notification *> NotificationList;
+
+class NotificationManager : public NotificationReceiver {
+friend class Notification;
+
+public:
+ NotificationManager();
+ virtual ~NotificationManager();
+
+ void checkNotifications();
+
+protected:
+ void addNotification(Notification *notification);
+ void removeNotification(Notification *notification);
+ void detachNotifications();
+
+ NotificationList _notifications;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/pegasus.cpp b/engines/pegasus/pegasus.cpp
new file mode 100644
index 0000000000..420ca39331
--- /dev/null
+++ b/engines/pegasus/pegasus.cpp
@@ -0,0 +1,2347 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/config-manager.h"
+#include "common/error.h"
+#include "common/events.h"
+#include "common/fs.h"
+#include "common/file.h"
+#include "common/memstream.h"
+#include "common/savefile.h"
+#include "common/textconsole.h"
+#include "common/translation.h"
+#include "common/random.h"
+#include "base/plugins.h"
+#include "base/version.h"
+#include "gui/saveload.h"
+#include "video/qt_decoder.h"
+
+#include "pegasus/console.h"
+#include "pegasus/cursor.h"
+#include "pegasus/energymonitor.h"
+#include "pegasus/gamestate.h"
+#include "pegasus/interface.h"
+#include "pegasus/menu.h"
+#include "pegasus/movie.h"
+#include "pegasus/pegasus.h"
+#include "pegasus/timers.h"
+#include "pegasus/ai/ai_area.h"
+#include "pegasus/items/itemlist.h"
+#include "pegasus/items/biochips/aichip.h"
+#include "pegasus/items/biochips/biochipitem.h"
+#include "pegasus/items/biochips/mapchip.h"
+#include "pegasus/items/biochips/opticalchip.h"
+#include "pegasus/items/biochips/pegasuschip.h"
+#include "pegasus/items/biochips/retscanchip.h"
+#include "pegasus/items/biochips/shieldchip.h"
+#include "pegasus/items/inventory/airmask.h"
+#include "pegasus/items/inventory/gascanister.h"
+#include "pegasus/items/inventory/inventoryitem.h"
+#include "pegasus/items/inventory/keycard.h"
+#include "pegasus/neighborhood/neighborhood.h"
+#include "pegasus/neighborhood/caldoria/caldoria.h"
+#include "pegasus/neighborhood/mars/mars.h"
+#include "pegasus/neighborhood/norad/constants.h"
+#include "pegasus/neighborhood/norad/alpha/noradalpha.h"
+#include "pegasus/neighborhood/norad/delta/noraddelta.h"
+#include "pegasus/neighborhood/prehistoric/prehistoric.h"
+#include "pegasus/neighborhood/tsa/fulltsa.h"
+#include "pegasus/neighborhood/tsa/tinytsa.h"
+#include "pegasus/neighborhood/wsc/wsc.h"
+
+namespace Pegasus {
+
+PegasusEngine::PegasusEngine(OSystem *syst, const PegasusGameDescription *gamedesc) : Engine(syst), InputHandler(0), _gameDescription(gamedesc),
+ _shellNotification(kJMPDCShellNotificationID, this), _returnHotspot(kInfoReturnSpotID), _itemDragger(this), _bigInfoMovie(kNoDisplayElement),
+ _smallInfoMovie(kNoDisplayElement) {
+ _continuePoint = 0;
+ _saveAllowed = _loadAllowed = true;
+ _saveRequested = _loadRequested = false;
+ _gameMenu = 0;
+ _deathReason = kDeathStranded;
+ _neighborhood = 0;
+ _FXLevel = 0x80;
+ _ambientLevel = 0x80;
+ _gameMode = kNoMode;
+ _switchModesSync = false;
+ _draggingItem = 0;
+ _dragType = kDragNoDrag;
+ _idlerHead = 0;
+ _currentCD = 1;
+ _introTimer = 0;
+ _aiSaveStream = 0;
+}
+
+PegasusEngine::~PegasusEngine() {
+ delete _resFork;
+ delete _console;
+ delete _cursor;
+ delete _continuePoint;
+ delete _gameMenu;
+ delete _neighborhood;
+ delete _rnd;
+ delete _introTimer;
+ delete _aiSaveStream;
+
+ for (ItemIterator it = _allItems.begin(); it != _allItems.end(); it++)
+ delete *it;
+
+ InputDeviceManager::destroy();
+ GameStateManager::destroy();
+
+ // NOTE: This must be deleted last!
+ delete _gfx;
+}
+
+Common::Error PegasusEngine::run() {
+ _console = new PegasusConsole(this);
+ _gfx = new GraphicsManager(this);
+ _resFork = new Common::MacResManager();
+ _cursor = new Cursor();
+ _rnd = new Common::RandomSource("Pegasus");
+
+ if (!_resFork->open("JMP PP Resources") || !_resFork->hasResFork())
+ error("Could not load JMP PP Resources");
+
+ // Initialize items
+ createItems();
+
+ // Initialize cursors
+ _cursor->addCursorFrames(0x80); // Main
+ _cursor->addCursorFrames(900); // Mars Shuttle
+
+ // Initialize the item dragger bounds
+ _itemDragger.setHighlightBounds();
+
+ if (!isDemo() && !detectOpeningClosingDirectory()) {
+ Common::String message = "Missing intro directory. ";
+
+ // Give Mac OS X a more specific message because we can
+#ifdef MACOSX
+ message += "Make sure \"Opening/Closing\" is present.";
+#else
+ message += "Be sure to rename \"Opening/Closing\" to \"Opening_Closing\".";
+#endif
+
+ GUIErrorMessage(message);
+ warning("%s", message.c_str());
+ return Common::kNoGameDataFoundError;
+ }
+
+ // Set up input
+ InputHandler::setInputHandler(this);
+ allowInput(true);
+
+ // Set up inventories
+ _items.setWeightLimit(9);
+ _items.setOwnerID(kPlayerID);
+ _biochips.setWeightLimit(8);
+ _biochips.setOwnerID(kPlayerID);
+
+ _returnHotspot.setArea(Common::Rect(kNavAreaLeft, kNavAreaTop, 512 + kNavAreaLeft, 256 + kNavAreaTop));
+ _returnHotspot.setHotspotFlags(kInfoReturnSpotFlag);
+ _allHotspots.push_back(&_returnHotspot);
+
+ _screenDimmer.setBounds(Common::Rect(0, 0, 640, 480));
+ _screenDimmer.setDisplayOrder(kScreenDimmerOrder);
+
+ // Load from the launcher/cli if requested (and don't show the intro in those cases)
+ bool doIntro = true;
+ if (ConfMan.hasKey("save_slot")) {
+ uint32 gameToLoad = ConfMan.getInt("save_slot");
+ doIntro = (loadGameState(gameToLoad).getCode() != Common::kNoError);
+ }
+
+ _shellNotification.notifyMe(this, kJMPShellNotificationFlags, kJMPShellNotificationFlags);
+
+ if (doIntro)
+ // Start up the first notification
+ _shellNotification.setNotificationFlags(kGameStartingFlag, kGameStartingFlag);
+
+ if (!isDemo()) {
+ _introTimer = new FuseFunction();
+ _introTimer->setFunctor(new Common::Functor0Mem<void, PegasusEngine>(this, &PegasusEngine::introTimerExpired));
+ }
+
+ while (!shouldQuit()) {
+ processShell();
+ _system->delayMillis(10); // Ease off the CPU
+ }
+
+ return Common::kNoError;
+}
+
+bool PegasusEngine::canLoadGameStateCurrently() {
+ return _loadAllowed && !isDemo();
+}
+
+bool PegasusEngine::canSaveGameStateCurrently() {
+ return _saveAllowed && !isDemo() && g_neighborhood;
+}
+
+bool PegasusEngine::detectOpeningClosingDirectory() {
+ // We need to detect what our Opening/Closing directory is listed as
+ // On the original disc, it was 'Opening/Closing' but only HFS(+) supports the slash
+ // Mac OS X will display this as 'Opening:Closing' and we can use that directly
+ // On other systems, users will need to rename to "Opening_Closing"
+
+ Common::FSNode gameDataDir(ConfMan.get("path"));
+ gameDataDir = gameDataDir.getChild("Images");
+
+ if (!gameDataDir.exists())
+ return false;
+
+ Common::FSList fsList;
+ if (!gameDataDir.getChildren(fsList, Common::FSNode::kListDirectoriesOnly, true))
+ return false;
+
+ for (uint i = 0; i < fsList.size() && _introDirectory.empty(); i++) {
+ Common::String name = fsList[i].getName();
+
+ if (name.equalsIgnoreCase("Opening:Closing"))
+ _introDirectory = name;
+ else if (name.equalsIgnoreCase("Opening_Closing"))
+ _introDirectory = name;
+ }
+
+ if (_introDirectory.empty())
+ return false;
+
+ debug(0, "Detected intro location as '%s'", _introDirectory.c_str());
+ _introDirectory = Common::String("Images/") + _introDirectory;
+ return true;
+}
+
+void PegasusEngine::createItems() {
+ Common::SeekableReadStream *res = _resFork->getResource(MKTAG('N', 'I', 't', 'm'), 0x80);
+
+ uint16 entryCount = res->readUint16BE();
+
+ for (uint16 i = 0; i < entryCount; i++) {
+ ItemID itemID = res->readUint16BE();
+ NeighborhoodID neighborhoodID = res->readUint16BE();
+ RoomID roomID = res->readUint16BE();
+ DirectionConstant direction = res->readByte();
+ res->readByte(); // alignment
+
+ createItem(itemID, neighborhoodID, roomID, direction);
+ }
+
+ delete res;
+}
+
+void PegasusEngine::createItem(ItemID itemID, NeighborhoodID neighborhoodID, RoomID roomID, DirectionConstant direction) {
+ switch (itemID) {
+ case kInterfaceBiochip:
+ // Unused in game, but still in the data and we need to create
+ // it because it's saved/loaded from save files.
+ new BiochipItem(itemID, neighborhoodID, roomID, direction);
+ break;
+ case kAIBiochip:
+ new AIChip(itemID, neighborhoodID, roomID, direction);
+ break;
+ case kPegasusBiochip:
+ new PegasusChip(itemID, neighborhoodID, roomID, direction);
+ break;
+ case kOpticalBiochip:
+ new OpticalChip(itemID, neighborhoodID, roomID, direction);
+ break;
+ case kMapBiochip:
+ new MapChip(itemID, neighborhoodID, roomID, direction);
+ break;
+ case kRetinalScanBiochip:
+ new RetScanChip(itemID, neighborhoodID, roomID, direction);
+ break;
+ case kShieldBiochip:
+ new ShieldChip(itemID, neighborhoodID, roomID, direction);
+ break;
+ case kAirMask:
+ new AirMask(itemID, neighborhoodID, roomID, direction);
+ break;
+ case kKeyCard:
+ new KeyCard(itemID, neighborhoodID, roomID, direction);
+ break;
+ case kGasCanister:
+ new GasCanister(itemID, neighborhoodID, roomID, direction);
+ break;
+ default:
+ // Everything else is a normal inventory item
+ new InventoryItem(itemID, neighborhoodID, roomID, direction);
+ break;
+ }
+}
+
+void PegasusEngine::runIntro() {
+ stopIntroTimer();
+
+ bool skipped = false;
+
+ 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();
+
+ if (frame) {
+ _system->copyRectToScreen((byte *)frame->pixels, frame->pitch, 0, 0, frame->w, frame->h);
+ _system->updateScreen();
+ }
+ }
+
+ Input input;
+ InputDevice.getInput(input, kFilterAllInput);
+ if (input.anyInput())
+ skipped = true;
+
+ _system->delayMillis(10);
+ }
+ }
+
+ delete video;
+
+ if (shouldQuit() || skipped)
+ return;
+
+ video = new Video::QuickTimeDecoder();
+
+ if (!video->loadFile(_introDirectory + "/Big Movie.movie"))
+ error("Could not load intro movie");
+
+ video->seek(Audio::Timestamp(0, 10 * 600, 600));
+ video->start();
+
+ playMovieScaled(video, 0, 0);
+
+ delete video;
+}
+
+Common::Error PegasusEngine::showLoadDialog() {
+ GUI::SaveLoadChooser slc(_("Load game:"), _("Load"), false);
+
+ Common::String gameId = ConfMan.get("gameid");
+
+ const EnginePlugin *plugin = 0;
+ EngineMan.findGame(gameId, &plugin);
+
+ int slot = slc.runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName());
+
+ Common::Error result;
+
+ if (slot >= 0) {
+ if (loadGameState(slot).getCode() == Common::kNoError)
+ result = Common::kNoError;
+ else
+ result = Common::kUnknownError;
+ } else {
+ result = Common::kUserCanceled;
+ }
+
+ return result;
+}
+
+Common::Error PegasusEngine::showSaveDialog() {
+ GUI::SaveLoadChooser slc(_("Save game:"), _("Save"), true);
+
+ Common::String gameId = ConfMan.get("gameid");
+
+ const EnginePlugin *plugin = 0;
+ EngineMan.findGame(gameId, &plugin);
+
+ int slot = slc.runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName());
+
+ Common::Error result;
+
+ if (slot >= 0) {
+ if (saveGameState(slot, slc.getResultString()).getCode() == Common::kNoError)
+ result = Common::kNoError;
+ else
+ result = Common::kUnknownError;
+ } else {
+ result = Common::kUserCanceled;
+ }
+
+ return result;
+}
+
+GUI::Debugger *PegasusEngine::getDebugger() {
+ return _console;
+}
+
+void PegasusEngine::addIdler(Idler *idler) {
+ idler->_nextIdler = _idlerHead;
+ if (_idlerHead)
+ _idlerHead->_prevIdler = idler;
+ idler->_prevIdler = 0;
+ _idlerHead = idler;
+}
+
+void PegasusEngine::removeIdler(Idler *idler) {
+ if (idler->_prevIdler)
+ idler->_prevIdler->_nextIdler = idler->_nextIdler;
+ if (idler->_nextIdler)
+ idler->_nextIdler->_prevIdler = idler->_prevIdler;
+ if (idler == _idlerHead)
+ _idlerHead = idler->_nextIdler;
+ idler->_nextIdler = 0;
+ idler->_prevIdler = 0;
+}
+
+void PegasusEngine::giveIdleTime() {
+ for (Idler *idler = _idlerHead; idler != 0; idler = idler->_nextIdler)
+ idler->useIdleTime();
+}
+
+void PegasusEngine::addTimeBase(TimeBase *timeBase) {
+ _timeBases.push_back(timeBase);
+}
+
+void PegasusEngine::removeTimeBase(TimeBase *timeBase) {
+ _timeBases.remove(timeBase);
+}
+
+bool PegasusEngine::loadFromStream(Common::ReadStream *stream) {
+ // Dispose currently running stuff
+ useMenu(0);
+ useNeighborhood(0);
+ removeAllItemsFromInventory();
+ removeAllItemsFromBiochips();
+ _currentItemID = kNoItemID;
+ _currentBiochipID = kNoItemID;
+
+ if (!g_interface)
+ createInterface();
+
+ // Signature
+ uint32 creator = stream->readUint32BE();
+ if (creator != kPegasusPrimeCreator) {
+ warning("Bad save creator '%s'", tag2str(creator));
+ return false;
+ }
+
+ uint32 gameType = stream->readUint32BE();
+ int saveType;
+
+ switch (gameType) {
+ case kPegasusPrimeDisk1GameType:
+ case kPegasusPrimeDisk2GameType:
+ case kPegasusPrimeDisk3GameType:
+ case kPegasusPrimeDisk4GameType:
+ _currentCD = gameType - kPegasusPrimeDisk1GameType + 1;
+ saveType = kNormalSave;
+ break;
+ case kPegasusPrimeContinueType:
+ saveType = kContinueSave;
+ break;
+ default:
+ // There are five other possible game types on the Pippin
+ // version, but hopefully we don't see any of those here
+ warning("Unhandled pegasus game type '%s'", tag2str(gameType));
+ return false;
+ }
+
+ uint32 version = stream->readUint32BE();
+ if (version != kPegasusPrimeVersion) {
+ warning("Where did you get this save? It's a beta (v%04x)!", version & 0x7fff);
+ return false;
+ }
+
+ // Game State
+ GameState.readGameState(stream);
+
+ // Energy
+ setLastEnergyValue(stream->readUint32BE());
+
+ // Death reason
+ setEnergyDeathReason(stream->readByte());
+
+ // Items
+ _allItems.readFromStream(stream);
+
+ // Inventory
+ byte itemCount = stream->readByte();
+
+ if (itemCount > 0) {
+ for (byte i = 0; i < itemCount; i++) {
+ InventoryItem *inv = (InventoryItem *)_allItems.findItemByID((ItemID)stream->readUint16BE());
+ addItemToInventory(inv);
+ }
+
+ g_interface->setCurrentInventoryItemID((ItemID)stream->readUint16BE());
+ }
+
+ // Biochips
+ byte biochipCount = stream->readByte();
+
+ if (biochipCount > 0) {
+ for (byte i = 0; i < biochipCount; i++) {
+ BiochipItem *biochip = (BiochipItem *)_allItems.findItemByID((ItemID)stream->readUint16BE());
+ addItemToBiochips(biochip);
+ }
+
+ g_interface->setCurrentBiochipID((ItemID)stream->readUint16BE());
+ }
+
+
+ // TODO: Disc check
+
+ // Jump to environment
+ jumpToNewEnvironment(GameState.getCurrentNeighborhood(), GameState.getCurrentRoom(), GameState.getCurrentDirection());
+ _shellNotification.setNotificationFlags(0, kNeedNewJumpFlag);
+ performJump(GameState.getCurrentNeighborhood());
+
+ // AI rules
+ if (g_AIArea)
+ g_AIArea->readAIRules(stream);
+
+ startNeighborhood();
+
+ // Make a new continue point if this isn't already one
+ if (saveType == kNormalSave)
+ makeContinuePoint();
+
+ return true;
+}
+
+bool PegasusEngine::writeToStream(Common::WriteStream *stream, int saveType) {
+ // WORKAROUND: If we don't have the interface, we can't actually save.
+ // However, we should still have a continue point, so we will just dump that
+ // out. This is needed for saving a game while in the space chase.
+ if (!g_interface) {
+ // Saving a continue stream from a continue stream should
+ // never happen. In addition, we do need to have a continue
+ // stream for this to work.
+ if (saveType != kNormalSave || !_continuePoint)
+ return false;
+
+ writeContinueStream(stream);
+ return true;
+ }
+
+ if (g_neighborhood)
+ g_neighborhood->flushGameState();
+
+ // Signature
+ stream->writeUint32BE(kPegasusPrimeCreator);
+
+ if (saveType == kNormalSave)
+ stream->writeUint32BE(kPegasusPrimeDisk1GameType + _currentCD - 1);
+ else // Continue
+ stream->writeUint32BE(kPegasusPrimeContinueType);
+
+ stream->writeUint32BE(kPegasusPrimeVersion);
+
+ // Game State
+ GameState.writeGameState(stream);
+
+ // Energy
+ stream->writeUint32BE(getSavedEnergyValue());
+
+ // Death reason
+ stream->writeByte(getEnergyDeathReason());
+
+ // Items
+ _allItems.writeToStream(stream);
+
+ // Inventory
+ byte itemCount = _items.getNumItems();
+ stream->writeByte(itemCount);
+
+ if (itemCount > 0) {
+ for (uint32 i = 0; i < itemCount; i++)
+ stream->writeUint16BE(_items.getItemIDAt(i));
+
+ stream->writeUint16BE(g_interface->getCurrentInventoryItem()->getObjectID());
+ }
+
+ // Biochips
+ byte biochipCount = _biochips.getNumItems();
+ stream->writeByte(biochipCount);
+
+ if (biochipCount > 0) {
+ for (uint32 i = 0; i < biochipCount; i++)
+ stream->writeUint16BE(_biochips.getItemIDAt(i));
+
+ stream->writeUint16BE(g_interface->getCurrentBiochip()->getObjectID());
+ }
+
+ // AI rules
+ if (g_AIArea)
+ g_AIArea->writeAIRules(stream);
+
+ return true;
+}
+
+void PegasusEngine::makeContinuePoint() {
+ // WORKAROUND: Do not attempt to make a continue point if the interface is not set
+ // up. The original did *not* do this and attempting to restore the game using the pause
+ // menu during the canyon/space chase sequence would segfault the game and crash the
+ // system. Nice!
+ if (!g_interface)
+ return;
+
+ delete _continuePoint;
+
+ Common::MemoryWriteStreamDynamic newPoint(DisposeAfterUse::NO);
+ writeToStream(&newPoint, kContinueSave);
+ _continuePoint = new Common::MemoryReadStream(newPoint.getData(), newPoint.size(), DisposeAfterUse::YES);
+}
+
+void PegasusEngine::loadFromContinuePoint() {
+ // Failure to load a continue point is fatal
+
+ if (!_continuePoint)
+ error("Attempting to load from non-existant continue point");
+
+ _continuePoint->seek(0);
+
+ if (!loadFromStream(_continuePoint))
+ error("Failed loading continue point");
+}
+
+void PegasusEngine::writeContinueStream(Common::WriteStream *stream) {
+ // We're going to pretty much copy the stream, except for the save type
+ _continuePoint->seek(0);
+ stream->writeUint32BE(_continuePoint->readUint32BE());
+ _continuePoint->readUint32BE(); // skip the continue type
+ stream->writeUint32BE(kPegasusPrimeDisk1GameType + _currentCD - 1);
+
+ // Now just copy over the rest
+ uint32 size = _continuePoint->size() - _continuePoint->pos();
+ byte *data = new byte[size];
+ _continuePoint->read(data, size);
+ stream->write(data, size);
+ delete[] data;
+}
+
+Common::Error PegasusEngine::loadGameState(int slot) {
+ Common::StringArray filenames = _saveFileMan->listSavefiles("pegasus-*.sav");
+ Common::InSaveFile *loadFile = _saveFileMan->openForLoading(filenames[slot]);
+ if (!loadFile)
+ return Common::kUnknownError;
+
+ bool valid = loadFromStream(loadFile);
+ delete loadFile;
+
+ return valid ? Common::kNoError : Common::kUnknownError;
+}
+
+Common::Error PegasusEngine::saveGameState(int slot, const Common::String &desc) {
+ Common::String output = Common::String::format("pegasus-%s.sav", desc.c_str());
+ Common::OutSaveFile *saveFile = _saveFileMan->openForSaving(output, false);
+ if (!saveFile)
+ return Common::kUnknownError;
+
+ bool valid = writeToStream(saveFile, kNormalSave);
+ delete saveFile;
+
+ return valid ? Common::kNoError : Common::kUnknownError;
+}
+
+void PegasusEngine::receiveNotification(Notification *notification, const NotificationFlags flags) {
+ if (&_shellNotification == notification) {
+ switch (flags) {
+ case kGameStartingFlag: {
+ useMenu(new MainMenu());
+
+ if (!isDemo()) {
+ runIntro();
+ resetIntroTimer();
+ } else {
+ showTempScreen("Images/Demo/NGsplashScrn.pict");
+ }
+
+ if (shouldQuit())
+ return;
+
+ _gfx->invalRect(Common::Rect(0, 0, 640, 480));
+ _gfx->updateDisplay();
+ ((MainMenu *)_gameMenu)->startMainMenuLoop();
+ break;
+ }
+ case kPlayerDiedFlag:
+ doDeath();
+ break;
+ case kNeedNewJumpFlag:
+ performJump(GameState.getNextNeighborhood());
+ startNeighborhood();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void PegasusEngine::checkCallBacks() {
+ for (Common::List<TimeBase *>::iterator it = _timeBases.begin(); it != _timeBases.end(); it++)
+ (*it)->checkCallBacks();
+}
+
+void PegasusEngine::resetIntroTimer() {
+ if (!isDemo() && _gameMenu && _gameMenu->getObjectID() == kMainMenuID) {
+ _introTimer->stopFuse();
+ _introTimer->primeFuse(kIntroTimeOut);
+ _introTimer->lightFuse();
+ }
+}
+
+void PegasusEngine::introTimerExpired() {
+ if (_gameMenu && _gameMenu->getObjectID() == kMainMenuID) {
+ ((MainMenu *)_gameMenu)->stopMainMenuLoop();
+
+ bool skipped = false;
+
+ 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;
+
+ if (shouldQuit())
+ return;
+
+ if (!skipped) {
+ runIntro();
+
+ if (shouldQuit())
+ return;
+ }
+
+ resetIntroTimer();
+ _gfx->invalRect(Common::Rect(0, 0, 640, 480));
+
+ swapSaveAllowed(saveAllowed);
+ swapLoadAllowed(openAllowed);
+
+ _gfx->updateDisplay();
+ ((MainMenu *)_gameMenu)->startMainMenuLoop();
+ }
+}
+
+void PegasusEngine::stopIntroTimer() {
+ if (_introTimer)
+ _introTimer->stopFuse();
+}
+
+void PegasusEngine::delayShell(TimeValue time, TimeScale scale) {
+ if (time == 0 || scale == 0)
+ return;
+
+ uint32 startTime = g_system->getMillis();
+ uint32 timeInMillis = time * 1000 / scale;
+
+ while (g_system->getMillis() < startTime + timeInMillis) {
+ checkCallBacks();
+ _gfx->updateDisplay();
+ }
+}
+
+void PegasusEngine::useMenu(GameMenu *newMenu) {
+ if (_gameMenu) {
+ _gameMenu->restorePreviousHandler();
+ delete _gameMenu;
+ }
+
+ _gameMenu = newMenu;
+
+ if (_gameMenu)
+ _gameMenu->becomeCurrentHandler();
+}
+
+bool PegasusEngine::checkGameMenu() {
+ GameMenuCommand command = kMenuCmdNoCommand;
+
+ if (_gameMenu) {
+ command = _gameMenu->getLastCommand();
+ if (command != kMenuCmdNoCommand) {
+ _gameMenu->clearLastCommand();
+ doGameMenuCommand(command);
+ }
+ }
+
+ return command != kMenuCmdNoCommand;
+}
+
+void PegasusEngine::doGameMenuCommand(const GameMenuCommand command) {
+ Common::Error result;
+
+ switch (command) {
+ case kMenuCmdStartAdventure:
+ stopIntroTimer();
+ GameState.setWalkthroughMode(false);
+ startNewGame();
+ break;
+ case kMenuCmdCredits:
+ if (isDemo()) {
+ showTempScreen("Images/Demo/DemoCredits.pict");
+ _gfx->doFadeOutSync();
+ _gfx->updateDisplay();
+ _gfx->doFadeInSync();
+ } else {
+ stopIntroTimer();
+ _gfx->doFadeOutSync();
+ useMenu(new CreditsMenu());
+ _gfx->updateDisplay();
+ _gfx->doFadeInSync();
+ }
+ break;
+ case kMenuCmdQuit:
+ case kMenuCmdDeathQuitDemo:
+ if (isDemo())
+ showTempScreen("Images/Demo/NGquitScrn.pict");
+ _system->quit();
+ break;
+ case kMenuCmdOverview:
+ stopIntroTimer();
+ doInterfaceOverview();
+ resetIntroTimer();
+ break;
+ case kMenuCmdStartWalkthrough:
+ stopIntroTimer();
+ GameState.setWalkthroughMode(true);
+ startNewGame();
+ break;
+ case kMenuCmdRestore:
+ stopIntroTimer();
+ // fall through
+ case kMenuCmdDeathRestore:
+ result = showLoadDialog();
+ if (command == kMenuCmdRestore && result.getCode() != Common::kNoError)
+ resetIntroTimer();
+ break;
+ case kMenuCmdCreditsMainMenu:
+ _gfx->doFadeOutSync();
+ useMenu(new MainMenu());
+ _gfx->updateDisplay();
+ ((MainMenu *)_gameMenu)->startMainMenuLoop();
+ _gfx->doFadeInSync();
+ resetIntroTimer();
+ break;
+ case kMenuCmdDeathContinue:
+ if (((DeathMenu *)_gameMenu)->playerWon()) {
+ if (isDemo()) {
+ showTempScreen("Images/Demo/DemoCredits.pict");
+ _gfx->doFadeOutSync();
+ _gfx->updateDisplay();
+ _gfx->doFadeInSync();
+ } else {
+ _gfx->doFadeOutSync();
+ useMenu(0);
+ _gfx->clearScreen();
+ _gfx->updateDisplay();
+
+ 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;
+
+ if (shouldQuit())
+ return;
+
+ useMenu(new MainMenu());
+ _gfx->updateDisplay();
+ ((MainMenu *)_gameMenu)->startMainMenuLoop();
+ _gfx->doFadeInSync();
+ resetIntroTimer();
+ }
+ } else {
+ loadFromContinuePoint();
+ }
+ break;
+ case kMenuCmdDeathMainMenuDemo:
+ case kMenuCmdDeathMainMenu:
+ _gfx->doFadeOutSync();
+ useMenu(new MainMenu());
+ _gfx->updateDisplay();
+ ((MainMenu *)_gameMenu)->startMainMenuLoop();
+ _gfx->doFadeInSync();
+ resetIntroTimer();
+ break;
+ case kMenuCmdPauseSave:
+ if (showSaveDialog().getCode() != Common::kUserCanceled)
+ pauseMenu(false);
+ break;
+ case kMenuCmdPauseContinue:
+ pauseMenu(false);
+ break;
+ case kMenuCmdPauseRestore:
+ makeContinuePoint();
+ result = showLoadDialog();
+
+ if (result.getCode() == Common::kNoError) {
+ // Successfully loaded, unpause the game
+ pauseMenu(false);
+ } else if (result.getCode() != Common::kUserCanceled) {
+ // Try to get us back to a sane state
+ loadFromContinuePoint();
+ }
+ break;
+ case kMenuCmdPauseQuit:
+ _gfx->doFadeOutSync();
+ throwAwayEverything();
+ pauseMenu(false);
+ useMenu(new MainMenu());
+ _gfx->updateDisplay();
+ ((MainMenu *)_gameMenu)->startMainMenuLoop();
+ _gfx->doFadeInSync();
+ resetIntroTimer();
+ break;
+ case kMenuCmdNoCommand:
+ break;
+ default:
+ error("Unknown menu command %d", command);
+ }
+}
+
+void PegasusEngine::handleInput(const Input &input, const Hotspot *cursorSpot) {
+ if (!checkGameMenu())
+ shellGameInput(input, cursorSpot);
+
+ // Handle the console here
+ if (input.isConsoleRequested()) {
+ _console->attach();
+ _console->onFrame();
+ }
+
+ // Handle save requests here
+ if (_saveRequested && _saveAllowed) {
+ _saveRequested = false;
+
+ // Can only save during a game and not in the demo
+ if (g_neighborhood && !isDemo()) {
+ pauseEngine(true);
+ showSaveDialog();
+ pauseEngine(false);
+ }
+ }
+
+ // Handle load requests here
+ if (_loadRequested && _loadAllowed) {
+ _loadRequested = false;
+
+ // WORKAROUND: Do not entertain load requests when the pause menu is up
+ // The original did and the game entered a bad state after loading.
+ // It's theoretically possible to make it so it does work while the
+ // pause menu is up, but the pause state of the engine is just too weird.
+ // Just use the pause menu's restore button since it's there for that
+ // for you to load anyway.
+ if (!isDemo() && !(_gameMenu && _gameMenu->getObjectID() == kPauseMenuID)) {
+ pauseEngine(true);
+
+ if (g_neighborhood) {
+ makeContinuePoint();
+
+ Common::Error result = showLoadDialog();
+ if (result.getCode() != Common::kNoError && result.getCode() != Common::kUserCanceled)
+ loadFromContinuePoint();
+ } else {
+ if (_introTimer)
+ _introTimer->stopFuse();
+
+ Common::Error result = showLoadDialog();
+ if (result.getCode() != Common::kNoError) {
+ if (!_gameMenu) {
+ useMenu(new MainMenu());
+ ((MainMenu *)_gameMenu)->startMainMenuLoop();
+ }
+
+ resetIntroTimer();
+ }
+ }
+
+ pauseEngine(false);
+ }
+ }
+}
+
+void PegasusEngine::doInterfaceOverview() {
+ static const short kNumOverviewSpots = 11;
+ static const Common::Rect overviewSpots[kNumOverviewSpots] = {
+ Common::Rect(354, 318, 354 + 204, 318 + 12),
+ Common::Rect(211, 34, 211 + 114, 34 + 28),
+ Common::Rect(502, 344, 502 + 138, 344 + 120),
+ Common::Rect(132, 40, 132 + 79, 40 + 22),
+ Common::Rect(325, 40, 332 + 115, 40 + 22),
+ Common::Rect(70, 318, 70 + 284, 318 + 12),
+ Common::Rect(76, 334, 76 + 96, 334 + 96),
+ Common::Rect(64, 64, 64 + 512, 64 + 256),
+ Common::Rect(364, 334, 364 + 96, 334 + 96),
+ Common::Rect(172, 334, 172 + 192, 334 + 96),
+ Common::Rect(542, 36, 542 + 58, 36 + 20)
+ };
+
+ _gfx->doFadeOutSync();
+ useMenu(0);
+
+ Picture leftBackground(kNoDisplayElement);
+ leftBackground.initFromPICTFile("Images/Interface/OVLeft.mac");
+ leftBackground.setDisplayOrder(0);
+ leftBackground.moveElementTo(kBackground1Left, kBackground1Top);
+ leftBackground.startDisplaying();
+ leftBackground.show();
+
+ Picture topBackground(kNoDisplayElement);
+ topBackground.initFromPICTFile("Images/Interface/OVTop.mac");
+ topBackground.setDisplayOrder(0);
+ topBackground.moveElementTo(kBackground2Left, kBackground2Top);
+ topBackground.startDisplaying();
+ topBackground.show();
+
+ Picture rightBackground(kNoDisplayElement);
+ rightBackground.initFromPICTFile("Images/Interface/OVRight.mac");
+ rightBackground.setDisplayOrder(0);
+ rightBackground.moveElementTo(kBackground3Left, kBackground3Top);
+ rightBackground.startDisplaying();
+ rightBackground.show();
+
+ Picture bottomBackground(kNoDisplayElement);
+ bottomBackground.initFromPICTFile("Images/Interface/OVBottom.mac");
+ bottomBackground.setDisplayOrder(0);
+ bottomBackground.moveElementTo(kBackground4Left, kBackground4Top);
+ bottomBackground.startDisplaying();
+ bottomBackground.show();
+
+ Picture controllerHighlight(kNoDisplayElement);
+ controllerHighlight.initFromPICTFile("Images/Interface/OVcontrollerHilite.mac");
+ controllerHighlight.setDisplayOrder(0);
+ controllerHighlight.moveElementTo(kOverviewControllerLeft, kOverviewControllerTop);
+ controllerHighlight.startDisplaying();
+
+ Movie overviewText(kNoDisplayElement);
+ overviewText.initFromMovieFile("Images/Interface/Overview Mac.movie");
+ overviewText.setDisplayOrder(0);
+ overviewText.moveElementTo(kNavAreaLeft, kNavAreaTop);
+ overviewText.startDisplaying();
+ overviewText.show();
+ overviewText.redrawMovieWorld();
+
+ DropHighlight highlight(kNoDisplayElement);
+ highlight.setDisplayOrder(1);
+ highlight.startDisplaying();
+ highlight.setHighlightThickness(4);
+ highlight.setHighlightColor(g_system->getScreenFormat().RGBToColor(239, 239, 0));
+ highlight.setHighlightCornerDiameter(8);
+
+ Input input;
+ InputDevice.getInput(input, kFilterAllInput);
+
+ Common::Point cursorLoc;
+ input.getInputLocation(cursorLoc);
+
+ uint16 i;
+ for (i = 0; i < kNumOverviewSpots; ++i)
+ if (overviewSpots[i].contains(cursorLoc))
+ break;
+
+ TimeValue time;
+ if (i == kNumOverviewSpots)
+ time = 5;
+ else if (i > 4)
+ time = i + 1;
+ else
+ time = i;
+
+ if (time == 2) {
+ highlight.hide();
+ controllerHighlight.show();
+ } else if (i != kNumOverviewSpots) {
+ controllerHighlight.hide();
+ Common::Rect r = overviewSpots[i];
+ r.grow(5);
+ highlight.setBounds(r);
+ highlight.show();
+ } else {
+ highlight.hide();
+ controllerHighlight.hide();
+ }
+
+ overviewText.setTime(time * 3 + 2, 15);
+ overviewText.redrawMovieWorld();
+
+ _cursor->setCurrentFrameIndex(3);
+ _cursor->show();
+
+ _gfx->updateDisplay();
+ _gfx->doFadeInSync();
+
+ for (;;) {
+ InputDevice.getInput(input, kFilterAllInput);
+
+ if (input.anyInput() || shouldQuit() || _loadRequested || _saveRequested)
+ break;
+
+ input.getInputLocation(cursorLoc);
+ for (i = 0; i < kNumOverviewSpots; ++i)
+ if (overviewSpots[i].contains(cursorLoc))
+ break;
+
+ if (i == kNumOverviewSpots)
+ time = 5;
+ else if (i > 4)
+ time = i + 1;
+ else
+ time = i;
+
+ if (time == 2) {
+ highlight.hide();
+ controllerHighlight.show();
+ } else if (i != kNumOverviewSpots) {
+ controllerHighlight.hide();
+ Common::Rect r = overviewSpots[i];
+ r.grow(5);
+ highlight.setBounds(r);
+ highlight.show();
+ } else {
+ highlight.hide();
+ controllerHighlight.hide();
+ }
+
+ overviewText.setTime(time * 3 + 2, 15);
+ overviewText.redrawMovieWorld();
+
+ refreshDisplay();
+ _system->delayMillis(10);
+ }
+
+ if (shouldQuit())
+ return;
+
+ highlight.hide();
+ _cursor->hide();
+
+ _gfx->doFadeOutSync();
+ useMenu(new MainMenu());
+ _gfx->updateDisplay();
+ ((MainMenu *)_gameMenu)->startMainMenuLoop();
+ _gfx->doFadeInSync();
+
+ _saveRequested = false;
+ _loadRequested = false;
+}
+
+void PegasusEngine::showTempScreen(const Common::String &fileName) {
+ _gfx->doFadeOutSync();
+
+ Picture picture(0);
+ picture.initFromPICTFile(fileName);
+ picture.setDisplayOrder(kMaxAvailableOrder);
+ picture.startDisplaying();
+ picture.show();
+ _gfx->updateDisplay();
+
+ _gfx->doFadeInSync();
+
+ // Wait for the next event
+ bool done = false;
+ while (!shouldQuit() && !done) {
+ Common::Event event;
+ while (_eventMan->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_LBUTTONUP:
+ case Common::EVENT_RBUTTONUP:
+ case Common::EVENT_KEYDOWN:
+ done = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ _system->delayMillis(10);
+ }
+}
+
+void PegasusEngine::refreshDisplay() {
+ giveIdleTime();
+ _gfx->updateDisplay();
+}
+
+void PegasusEngine::resetEnergyDeathReason() {
+ switch (getCurrentNeighborhoodID()) {
+ case kMarsID:
+ _deathReason = kDeathArrestedInMars;
+ break;
+ case kNoradAlphaID:
+ case kNoradDeltaID:
+ _deathReason = kDeathArrestedInNorad;
+ break;
+ case kWSCID:
+ _deathReason = kDeathArrestedInWSC;
+ break;
+ default:
+ _deathReason = kDeathStranded;
+ break;
+ }
+}
+
+bool PegasusEngine::playerHasItem(const Item *item) {
+ return playerHasItemID(item->getObjectID());
+}
+
+bool PegasusEngine::playerHasItemID(const ItemID itemID) {
+ return itemInInventory(itemID) || itemInBiochips(itemID);
+}
+
+InventoryItem *PegasusEngine::getCurrentInventoryItem() {
+ if (g_interface)
+ return g_interface->getCurrentInventoryItem();
+
+ return 0;
+}
+
+bool PegasusEngine::itemInInventory(InventoryItem *item) {
+ return _items.itemInInventory(item);
+}
+
+bool PegasusEngine::itemInInventory(ItemID id) {
+ return _items.itemInInventory(id);
+}
+
+BiochipItem *PegasusEngine::getCurrentBiochip() {
+ if (g_interface)
+ return g_interface->getCurrentBiochip();
+
+ return 0;
+}
+
+bool PegasusEngine::itemInBiochips(BiochipItem *item) {
+ return _biochips.itemInInventory(item);
+}
+
+bool PegasusEngine::itemInBiochips(ItemID id) {
+ return _biochips.itemInInventory(id);
+}
+
+bool PegasusEngine::playerAlive() {
+ return (_shellNotification.getNotificationFlags() & kPlayerDiedFlag) == 0;
+}
+
+Common::String PegasusEngine::getBriefingMovie() {
+ if (_neighborhood)
+ return _neighborhood->getBriefingMovie();
+
+ return Common::String();
+}
+
+Common::String PegasusEngine::getEnvScanMovie() {
+ if (_neighborhood)
+ return _neighborhood->getEnvScanMovie();
+
+ return Common::String();
+}
+
+uint PegasusEngine::getNumHints() {
+ if (_neighborhood)
+ return _neighborhood->getNumHints();
+
+ return 0;
+}
+
+Common::String PegasusEngine::getHintMovie(uint hintNum) {
+ if (_neighborhood)
+ return _neighborhood->getHintMovie(hintNum);
+
+ return Common::String();
+}
+
+bool PegasusEngine::canSolve() {
+ if (_neighborhood)
+ return _neighborhood->canSolve();
+
+ return false;
+}
+
+void PegasusEngine::prepareForAIHint(const Common::String &movieName) {
+ if (g_neighborhood)
+ g_neighborhood->prepareForAIHint(movieName);
+}
+
+void PegasusEngine::cleanUpAfterAIHint(const Common::String &movieName) {
+ if (g_neighborhood)
+ g_neighborhood->cleanUpAfterAIHint(movieName);
+}
+
+void PegasusEngine::jumpToNewEnvironment(const NeighborhoodID neighborhoodID, const RoomID roomID, const DirectionConstant direction) {
+ GameState.setNextLocation(neighborhoodID, roomID, direction);
+ _shellNotification.setNotificationFlags(kNeedNewJumpFlag, kNeedNewJumpFlag);
+}
+
+void PegasusEngine::checkFlashlight() {
+ if (_neighborhood)
+ _neighborhood->checkFlashlight();
+}
+
+bool PegasusEngine::playMovieScaled(Video::VideoDecoder *video, uint16 x, uint16 y) {
+ bool skipped = false;
+
+ while (!shouldQuit() && !video->endOfVideo() && !skipped) {
+ if (video->needsUpdate()) {
+ const Graphics::Surface *frame = video->decodeNextFrame();
+
+ if (frame)
+ drawScaledFrame(frame, x, y);
+ }
+
+ Input input;
+ InputDevice.getInput(input, kFilterAllInput);
+ if (input.anyInput() || _saveRequested || _loadRequested)
+ skipped = true;
+
+ _system->delayMillis(10);
+ }
+
+ return skipped;
+}
+
+void PegasusEngine::die(const DeathReason reason) {
+ Input dummy;
+ if (isDragging())
+ _itemDragger.stopTracking(dummy);
+
+ _deathReason = reason;
+ _shellNotification.setNotificationFlags(kPlayerDiedFlag, kPlayerDiedFlag);
+}
+
+void PegasusEngine::doDeath() {
+ _gfx->doFadeOutSync();
+ throwAwayEverything();
+ useMenu(new DeathMenu(_deathReason));
+ _gfx->updateDisplay();
+ _gfx->doFadeInSync();
+}
+
+void PegasusEngine::throwAwayEverything() {
+ if (_items.getNumItems() != 0 && g_interface)
+ _currentItemID = g_interface->getCurrentInventoryItem()->getObjectID();
+ else
+ _currentItemID = kNoItemID;
+
+ if (_biochips.getNumItems() != 0 && g_interface)
+ _currentBiochipID = g_interface->getCurrentBiochip()->getObjectID();
+ else
+ _currentBiochipID = kNoItemID;
+
+ useMenu(0);
+ useNeighborhood(0);
+
+ delete g_interface;
+ g_interface = 0;
+}
+
+void PegasusEngine::processShell() {
+ checkCallBacks();
+ checkNotifications();
+ InputHandler::pollForInput();
+ refreshDisplay();
+}
+
+void PegasusEngine::createInterface() {
+ if (!g_interface)
+ new Interface();
+
+ g_interface->createInterface();
+}
+
+void PegasusEngine::setGameMode(const GameMode newMode) {
+ if (newMode != _gameMode && canSwitchGameMode(newMode, _gameMode)) {
+ switchGameMode(newMode, _gameMode);
+ _gameMode = newMode;
+ }
+}
+
+void PegasusEngine::switchGameMode(const GameMode newMode, const GameMode oldMode) {
+ // Start raising panels before lowering panels, to give the activating panel time
+ // to set itself up without cutting into the lowering panel's animation time.
+
+ if (_switchModesSync) {
+ if (newMode == kModeInventoryPick)
+ raiseInventoryDrawerSync();
+ else if (newMode == kModeBiochipPick)
+ raiseBiochipDrawerSync();
+ else if (newMode == kModeInfoScreen)
+ showInfoScreen();
+
+ if (oldMode == kModeInventoryPick)
+ lowerInventoryDrawerSync();
+ else if (oldMode == kModeBiochipPick)
+ lowerBiochipDrawerSync();
+ else if (oldMode == kModeInfoScreen)
+ hideInfoScreen();
+ } else {
+ if (newMode == kModeInventoryPick)
+ raiseInventoryDrawer();
+ else if (newMode == kModeBiochipPick)
+ raiseBiochipDrawer();
+ else if (newMode == kModeInfoScreen)
+ showInfoScreen();
+
+ if (oldMode == kModeInventoryPick)
+ lowerInventoryDrawer();
+ else if (oldMode == kModeBiochipPick)
+ lowerBiochipDrawer();
+ else if (oldMode == kModeInfoScreen)
+ hideInfoScreen();
+ }
+}
+
+bool PegasusEngine::canSwitchGameMode(const GameMode newMode, const GameMode oldMode) {
+ if (newMode == kModeInventoryPick && oldMode == kModeBiochipPick)
+ return false;
+ if (newMode == kModeBiochipPick && oldMode == kModeInventoryPick)
+ return false;
+ return true;
+}
+
+bool PegasusEngine::itemInLocation(const ItemID itemID, const NeighborhoodID neighborhood, const RoomID room, const DirectionConstant direction) {
+ NeighborhoodID itemNeighborhood;
+ RoomID itemRoom;
+ DirectionConstant itemDirection;
+
+ Item *item = _allItems.findItemByID(itemID);
+ item->getItemRoom(itemNeighborhood, itemRoom, itemDirection);
+
+ return itemNeighborhood == neighborhood && itemRoom == room && itemDirection == direction;
+}
+
+InventoryResult PegasusEngine::addItemToInventory(InventoryItem *item) {
+ InventoryResult result;
+
+ do {
+ if (g_interface)
+ result = g_interface->addInventoryItem(item);
+ else
+ result = _items.addItem(item);
+
+ if (result == kTooMuchWeight)
+ destroyInventoryItem(pickItemToDestroy());
+ } while (result != kInventoryOK);
+
+ GameState.setTakenItem(item, true);
+ if (g_neighborhood)
+ g_neighborhood->pickedUpItem(item);
+
+ g_AIArea->checkMiddleArea();
+
+ return result;
+}
+
+void PegasusEngine::useNeighborhood(Neighborhood *neighborhood) {
+ delete _neighborhood;
+ _neighborhood = neighborhood;
+
+ if (_neighborhood) {
+ InputHandler::setInputHandler(_neighborhood);
+ _neighborhood->init();
+ _neighborhood->moveNavTo(kNavAreaLeft, kNavAreaTop);
+ g_interface->setDate(_neighborhood->getDateResID());
+ } else {
+ InputHandler::setInputHandler(this);
+ }
+}
+
+void PegasusEngine::performJump(NeighborhoodID neighborhoodID) {
+ if (_neighborhood)
+ useNeighborhood(0);
+
+ // Sub chase is special
+ if (neighborhoodID == kNoradSubChaseID) {
+ throwAwayEverything();
+ _loadAllowed = false;
+ doSubChase();
+
+ if (shouldQuit())
+ return;
+
+ neighborhoodID = kNoradDeltaID;
+ GameState.setNextRoom(kNorad41);
+ GameState.setNextDirection(kEast);
+ _loadAllowed = true;
+ }
+
+ Neighborhood *neighborhood;
+ makeNeighborhood(neighborhoodID, neighborhood);
+ useNeighborhood(neighborhood);
+
+ // Update the CD variable (used just for saves currently)
+ _currentCD = getNeighborhoodCD(neighborhoodID);
+}
+
+void PegasusEngine::startNeighborhood() {
+ if (g_interface && _currentItemID != kNoItemID)
+ g_interface->setCurrentInventoryItemID(_currentItemID);
+
+ if (g_interface && _currentBiochipID != kNoItemID)
+ g_interface->setCurrentBiochipID(_currentBiochipID);
+
+ setGameMode(kModeNavigation);
+
+ if (_neighborhood)
+ _neighborhood->start();
+}
+
+void PegasusEngine::startNewGame() {
+ // WORKAROUND: The original game ignored the menu difficulty
+ // setting. We're going to pass it through here so that
+ // the menu actually makes sense now.
+ bool isWalkthrough = GameState.getWalkthroughMode();
+ GameState.resetGameState();
+ GameState.setWalkthroughMode(isWalkthrough);
+
+ // TODO: Enable erase
+ _gfx->doFadeOutSync();
+ useMenu(0);
+ _gfx->updateDisplay();
+ _gfx->enableUpdates();
+
+ createInterface();
+
+ if (isDemo()) {
+ setLastEnergyValue(kFullEnergy);
+ jumpToNewEnvironment(kPrehistoricID, kPrehistoric02, kSouth);
+ GameState.setPrehistoricSeenTimeStream(false);
+ GameState.setPrehistoricSeenFlyer1(false);
+ GameState.setPrehistoricSeenFlyer2(false);
+ GameState.setPrehistoricSeenBridgeZoom(false);
+ GameState.setPrehistoricBreakerThrown(false);
+ } else {
+ jumpToNewEnvironment(kCaldoriaID, kCaldoria00, kEast);
+ }
+
+ removeAllItemsFromInventory();
+ removeAllItemsFromBiochips();
+
+ BiochipItem *biochip = (BiochipItem *)_allItems.findItemByID(kAIBiochip);
+ addItemToBiochips(biochip);
+
+ if (isDemo()) {
+ biochip = (BiochipItem *)_allItems.findItemByID(kPegasusBiochip);
+ addItemToBiochips(biochip);
+ biochip = (BiochipItem *)_allItems.findItemByID(kMapBiochip);
+ addItemToBiochips(biochip);
+ InventoryItem *item = (InventoryItem *)_allItems.findItemByID(kKeyCard);
+ addItemToInventory(item);
+ item = (InventoryItem *)_allItems.findItemByID(kJourneymanKey);
+ addItemToInventory(item);
+ _currentItemID = kJourneymanKey;
+ } else {
+ _currentItemID = kNoItemID;
+ }
+
+ _currentBiochipID = kAIBiochip;
+
+ // Clear jump notification flags and just perform the jump...
+ _shellNotification.setNotificationFlags(0, kNeedNewJumpFlag);
+
+ performJump(GameState.getNextNeighborhood());
+
+ startNeighborhood();
+}
+
+void PegasusEngine::makeNeighborhood(NeighborhoodID neighborhoodID, Neighborhood *&neighborhood) {
+ // TODO: CD check
+
+ switch (neighborhoodID) {
+ case kCaldoriaID:
+ neighborhood = new Caldoria(g_AIArea, this);
+ break;
+ case kMarsID:
+ neighborhood = new Mars(g_AIArea, this);
+ break;
+ case kPrehistoricID:
+ neighborhood = new Prehistoric(g_AIArea, this);
+ break;
+ case kFullTSAID:
+ neighborhood = new FullTSA(g_AIArea, this);
+ break;
+ case kTinyTSAID:
+ neighborhood = new TinyTSA(g_AIArea, this);
+ break;
+ case kWSCID:
+ neighborhood = new WSC(g_AIArea, this);
+ break;
+ case kNoradAlphaID:
+ neighborhood = new NoradAlpha(g_AIArea, this);
+ break;
+ case kNoradDeltaID:
+ createInterface();
+ neighborhood = new NoradDelta(g_AIArea, this);
+ break;
+ default:
+ error("Unknown neighborhood %d", neighborhoodID);
+ }
+}
+
+bool PegasusEngine::wantsCursor() {
+ return _gameMenu == 0;
+}
+
+void PegasusEngine::updateCursor(const Common::Point, const Hotspot *cursorSpot) {
+ if (_itemDragger.isTracking()) {
+ _cursor->setCurrentFrameIndex(5);
+ } else {
+ if (!cursorSpot) {
+ _cursor->setCurrentFrameIndex(0);
+ } else {
+ uint32 id = cursorSpot->getObjectID();
+
+ switch (id) {
+ case kCurrentItemSpotID:
+ if (countInventoryItems() != 0)
+ _cursor->setCurrentFrameIndex(4);
+ else
+ _cursor->setCurrentFrameIndex(0);
+ break;
+ default:
+ HotSpotFlags flags = cursorSpot->getHotspotFlags();
+
+ if (flags & kZoomInSpotFlag)
+ _cursor->setCurrentFrameIndex(1);
+ else if (flags & kZoomOutSpotFlag)
+ _cursor->setCurrentFrameIndex(2);
+ else if (flags & (kPickUpItemSpotFlag | kPickUpBiochipSpotFlag))
+ _cursor->setCurrentFrameIndex(4);
+ else if (flags & kJMPClickingSpotFlags)
+ _cursor->setCurrentFrameIndex(3);
+ else
+ _cursor->setCurrentFrameIndex(0);
+ }
+ }
+ }
+}
+
+void PegasusEngine::toggleInventoryDisplay() {
+ if (_gameMode == kModeInventoryPick)
+ setGameMode(kModeNavigation);
+ else
+ setGameMode(kModeInventoryPick);
+}
+
+void PegasusEngine::toggleBiochipDisplay() {
+ if (_gameMode == kModeBiochipPick)
+ setGameMode(kModeNavigation);
+ else
+ setGameMode(kModeBiochipPick);
+}
+
+void PegasusEngine::showInfoScreen() {
+ if (g_neighborhood) {
+ // Break the input handler chain...
+ _savedHandler = InputHandler::getCurrentHandler();
+ InputHandler::setInputHandler(this);
+
+ Picture *pushPicture = ((Neighborhood *)g_neighborhood)->getTurnPushPicture();
+
+ _bigInfoMovie.shareSurface(pushPicture);
+ _smallInfoMovie.shareSurface(pushPicture);
+
+ g_neighborhood->hideNav();
+
+ _smallInfoMovie.initFromMovieFile("Images/Items/Info Right Movie");
+ _smallInfoMovie.setDisplayOrder(kInfoSpinOrder);
+ _smallInfoMovie.moveElementTo(kNavAreaLeft + 304, kNavAreaTop + 8);
+ _smallInfoMovie.moveMovieBoxTo(304, 8);
+ _smallInfoMovie.startDisplaying();
+ _smallInfoMovie.show();
+
+ TimeValue startTime, stopTime;
+ g_AIArea->getSmallInfoSegment(startTime, stopTime);
+ _smallInfoMovie.setSegment(startTime, stopTime);
+ _smallInfoMovie.setTime(startTime);
+ _smallInfoMovie.setFlags(kLoopTimeBase);
+
+ _bigInfoMovie.initFromMovieFile("Images/Items/Info Left Movie");
+ _bigInfoMovie.setDisplayOrder(kInfoBackgroundOrder);
+ _bigInfoMovie.moveElementTo(kNavAreaLeft, kNavAreaTop);
+ _bigInfoMovie.startDisplaying();
+ _bigInfoMovie.show();
+ _bigInfoMovie.setTime(g_AIArea->getBigInfoTime());
+
+ _bigInfoMovie.redrawMovieWorld();
+ _smallInfoMovie.redrawMovieWorld();
+ _smallInfoMovie.start();
+ }
+}
+
+void PegasusEngine::hideInfoScreen() {
+ if (g_neighborhood) {
+ InputHandler::setInputHandler(_savedHandler);
+
+ _bigInfoMovie.hide();
+ _bigInfoMovie.stopDisplaying();
+ _bigInfoMovie.releaseMovie();
+
+ _smallInfoMovie.hide();
+ _smallInfoMovie.stopDisplaying();
+ _smallInfoMovie.stop();
+ _smallInfoMovie.releaseMovie();
+
+ g_neighborhood->showNav();
+ }
+}
+
+void PegasusEngine::raiseInventoryDrawer() {
+ if (g_interface)
+ g_interface->raiseInventoryDrawer();
+}
+
+void PegasusEngine::raiseBiochipDrawer() {
+ if (g_interface)
+ g_interface->raiseBiochipDrawer();
+}
+
+void PegasusEngine::lowerInventoryDrawer() {
+ if (g_interface)
+ g_interface->lowerInventoryDrawer();
+}
+
+void PegasusEngine::lowerBiochipDrawer() {
+ if (g_interface)
+ g_interface->lowerBiochipDrawer();
+}
+
+void PegasusEngine::raiseInventoryDrawerSync() {
+ if (g_interface)
+ g_interface->raiseInventoryDrawerSync();
+}
+
+void PegasusEngine::raiseBiochipDrawerSync() {
+ if (g_interface)
+ g_interface->raiseBiochipDrawerSync();
+}
+
+void PegasusEngine::lowerInventoryDrawerSync() {
+ if (g_interface)
+ g_interface->lowerInventoryDrawerSync();
+}
+
+void PegasusEngine::lowerBiochipDrawerSync() {
+ if (g_interface)
+ g_interface->lowerBiochipDrawerSync();
+}
+
+void PegasusEngine::toggleInfo() {
+ if (_gameMode == kModeInfoScreen)
+ setGameMode(kModeNavigation);
+ else if (_gameMode == kModeNavigation)
+ setGameMode(kModeInfoScreen);
+}
+
+void PegasusEngine::dragTerminated(const Input &) {
+ Hotspot *finalSpot = _itemDragger.getLastHotspot();
+ InventoryResult result;
+
+ if (_dragType == kDragInventoryPickup) {
+ if (finalSpot && finalSpot->getObjectID() == kInventoryDropSpotID)
+ result = addItemToInventory((InventoryItem *)_draggingItem);
+ else
+ result = kTooMuchWeight;
+
+ if (result != kInventoryOK)
+ autoDragItemIntoRoom(_draggingItem, _draggingSprite);
+ else
+ delete _draggingSprite;
+ } else if (_dragType == kDragBiochipPickup) {
+ if (finalSpot && finalSpot->getObjectID() == kBiochipDropSpotID)
+ result = addItemToBiochips((BiochipItem *)_draggingItem);
+ else
+ result = kTooMuchWeight;
+
+ if (result != kInventoryOK)
+ autoDragItemIntoRoom(_draggingItem, _draggingSprite);
+ else
+ delete _draggingSprite;
+ } else if (_dragType == kDragInventoryUse) {
+ if (finalSpot && (finalSpot->getHotspotFlags() & kDropItemSpotFlag) != 0) {
+ // *** Need to decide on a case by case basis what to do here.
+ // the crowbar should break the cover off the Mars reactor if its frozen, the
+ // global transport card should slide through the slot, the oxygen mask should
+ // attach to the filling station, and so on...
+ _neighborhood->dropItemIntoRoom(_draggingItem, finalSpot);
+ delete _draggingSprite;
+ } else {
+ autoDragItemIntoInventory(_draggingItem, _draggingSprite);
+ }
+ }
+
+ _dragType = kDragNoDrag;
+
+ if (g_AIArea)
+ g_AIArea->unlockAI();
+}
+
+
+void PegasusEngine::dragItem(const Input &input, Item *item, DragType type) {
+ _draggingItem = item;
+ _dragType = type;
+
+ // Create the sprite.
+ _draggingSprite = _draggingItem->getDragSprite(kDraggingSpriteID);
+ Common::Point where;
+ input.getInputLocation(where);
+ Common::Rect r1;
+ _draggingSprite->getBounds(r1);
+ r1 = Common::Rect::center(where.x, where.y, r1.width(), r1.height());
+ _draggingSprite->setBounds(r1);
+
+ // Set up drag constraints.
+ DisplayElement *navMovie = _gfx->findDisplayElement(kNavMovieID);
+ Common::Rect r2;
+ navMovie->getBounds(r2);
+ r2.left -= r1.width() / 3;
+ r2.right += r1.width() / 3;
+ r2.top -= r1.height() / 3;
+ r2.bottom += r2.height() / 3;
+
+ r1 = Common::Rect(-30000, -30000, 30000, 30000);
+ _itemDragger.setDragConstraints(r2, r1);
+
+ // Start dragging.
+ _draggingSprite->setDisplayOrder(kDragSpriteOrder);
+ _draggingSprite->startDisplaying();
+ _draggingSprite->show();
+ _itemDragger.setDragSprite(_draggingSprite);
+ _itemDragger.setNextHandler(_neighborhood);
+ _itemDragger.startTracking(input);
+
+ if (g_AIArea)
+ g_AIArea->lockAIOut();
+}
+
+void PegasusEngine::shellGameInput(const Input &input, const Hotspot *cursorSpot) {
+ if (_gameMode == kModeInfoScreen) {
+ if (JMPPPInput::isToggleAIMiddleInput(input)) {
+ LowerClientSignature middleOwner = g_AIArea->getMiddleAreaOwner();
+ g_AIArea->toggleMiddleAreaOwner();
+
+ if (middleOwner != g_AIArea->getMiddleAreaOwner()) {
+ _bigInfoMovie.setTime(g_AIArea->getBigInfoTime());
+ _smallInfoMovie.stop();
+ _smallInfoMovie.setFlags(0);
+
+ TimeValue startTime, stopTime;
+ g_AIArea->getSmallInfoSegment(startTime, stopTime);
+ _smallInfoMovie.setSegment(startTime, stopTime);
+ _smallInfoMovie.setTime(startTime);
+ _smallInfoMovie.setFlags(kLoopTimeBase);
+
+ _bigInfoMovie.redrawMovieWorld();
+ _smallInfoMovie.redrawMovieWorld();
+ _smallInfoMovie.start();
+ }
+ }
+ } else {
+ if (JMPPPInput::isRaiseInventoryInput(input))
+ toggleInventoryDisplay();
+
+ if (JMPPPInput::isRaiseBiochipsInput(input))
+ toggleBiochipDisplay();
+
+ if (JMPPPInput::isTogglePauseInput(input) && _neighborhood)
+ pauseMenu(!isPaused());
+ }
+
+ if (JMPPPInput::isToggleInfoInput(input))
+ toggleInfo();
+}
+
+void PegasusEngine::activateHotspots() {
+ if (_gameMode == kModeInfoScreen) {
+ _allHotspots.activateOneHotspot(kInfoReturnSpotID);
+ } else {
+ // Set up hot spots.
+ if (_dragType == kDragInventoryPickup)
+ _allHotspots.activateOneHotspot(kInventoryDropSpotID);
+ else if (_dragType == kDragBiochipPickup)
+ _allHotspots.activateOneHotspot(kBiochipDropSpotID);
+ else if (_dragType == kDragNoDrag)
+ _allHotspots.activateMaskedHotspots(kShellSpotFlag);
+ }
+}
+
+bool PegasusEngine::isClickInput(const Input &input, const Hotspot *cursorSpot) {
+ if (_cursor->isVisible() && cursorSpot)
+ return JMPPPInput::isClickInput(input);
+ else
+ return false;
+}
+
+InputBits PegasusEngine::getClickFilter() {
+ return JMPPPInput::getClickInputFilter();
+}
+
+void PegasusEngine::clickInHotspot(const Input &input, const Hotspot *clickedSpot) {
+ if (clickedSpot->getObjectID() == kCurrentItemSpotID) {
+ InventoryItem *currentItem = getCurrentInventoryItem();
+ if (currentItem) {
+ removeItemFromInventory(currentItem);
+ dragItem(input, currentItem, kDragInventoryUse);
+ }
+ } else if (clickedSpot->getObjectID() == kInfoReturnSpotID) {
+ toggleInfo();
+ }
+}
+
+InventoryResult PegasusEngine::removeItemFromInventory(InventoryItem *item) {
+ InventoryResult result;
+
+ if (g_interface)
+ result = g_interface->removeInventoryItem(item);
+ else
+ result = _items.removeItem(item);
+
+ // This should never happen
+ assert(result == kInventoryOK);
+
+ return result;
+}
+
+void PegasusEngine::removeAllItemsFromInventory() {
+ if (g_interface)
+ g_interface->removeAllItemsFromInventory();
+ else
+ _items.removeAllItems();
+}
+
+/////////////////////////////////////////////
+//
+// Biochip handling.
+
+// Adding biochips to the biochip drawer is a little funny, because of two things:
+// -- We get the map biochip and pegasus biochip at the same time by dragging
+// one sprite in TSA
+// -- We can drag in more than one copy of the various biochips.
+// Because of this we need to make sure that no more than one copy of each biochip
+// is ever added.
+
+InventoryResult PegasusEngine::addItemToBiochips(BiochipItem *biochip) {
+ InventoryResult result;
+
+ if (g_interface)
+ result = g_interface->addBiochip(biochip);
+ else
+ result = _biochips.addItem(biochip);
+
+ // This can never happen
+ assert(result == kInventoryOK);
+
+ GameState.setTakenItem(biochip, true);
+
+ if (g_neighborhood)
+ g_neighborhood->pickedUpItem(biochip);
+
+ g_AIArea->checkMiddleArea();
+
+ return result;
+}
+
+void PegasusEngine::removeAllItemsFromBiochips() {
+ if (g_interface)
+ g_interface->removeAllItemsFromBiochips();
+ else
+ _biochips.removeAllItems();
+}
+
+void PegasusEngine::setSoundFXLevel(uint16 fxLevel) {
+ _FXLevel = fxLevel;
+ if (_neighborhood)
+ _neighborhood->setSoundFXLevel(fxLevel);
+ if (g_AIArea)
+ g_AIArea->setAIVolume(fxLevel);
+}
+
+void PegasusEngine::setAmbienceLevel(uint16 ambientLevel) {
+ _ambientLevel = ambientLevel;
+ if (_neighborhood)
+ _neighborhood->setAmbienceLevel(ambientLevel);
+}
+
+void PegasusEngine::pauseMenu(bool menuUp) {
+ if (menuUp) {
+ pauseEngine(true);
+ _screenDimmer.startDisplaying();
+ _screenDimmer.show();
+ _gfx->updateDisplay();
+ useMenu(new PauseMenu());
+ } else {
+ pauseEngine(false);
+ _screenDimmer.hide();
+ _screenDimmer.stopDisplaying();
+ useMenu(0);
+ g_AIArea->checkMiddleArea();
+ }
+}
+
+void PegasusEngine::autoDragItemIntoRoom(Item *item, Sprite *draggingSprite) {
+ if (g_AIArea)
+ g_AIArea->lockAIOut();
+
+ Common::Point start, stop;
+ draggingSprite->getLocation(start.x, start.y);
+
+ Hotspot *dropSpot = _neighborhood->getItemScreenSpot(item, draggingSprite);
+
+ if (dropSpot) {
+ dropSpot->getCenter(stop.x, stop.y);
+ } else {
+ stop.x = kNavAreaLeft + 256;
+ stop.y = kNavAreaTop + 128;
+ }
+
+ Common::Rect bounds;
+ draggingSprite->getBounds(bounds);
+ stop.x -= bounds.width() >> 1;
+ stop.y -= bounds.height() >> 1;
+
+ int dx = ABS(stop.x - start.x);
+ int dy = ABS(stop.y - start.y);
+ TimeValue time = MAX(dx, dy);
+
+ allowInput(false);
+ _autoDragger.autoDrag(draggingSprite, start, stop, time, kDefaultTimeScale);
+
+ while (_autoDragger.isDragging()) {
+ checkCallBacks();
+ refreshDisplay();
+ _system->delayMillis(10);
+ }
+
+ _neighborhood->dropItemIntoRoom(_draggingItem, dropSpot);
+ allowInput(true);
+ delete _draggingSprite;
+
+ if (g_AIArea)
+ g_AIArea->unlockAI();
+}
+
+void PegasusEngine::autoDragItemIntoInventory(Item *, Sprite *draggingSprite) {
+ if (g_AIArea)
+ g_AIArea->lockAIOut();
+
+ Common::Point start;
+ draggingSprite->getLocation(start.x, start.y);
+
+ Common::Rect r;
+ draggingSprite->getBounds(r);
+
+ Common::Point stop((76 + 172 - r.width()) / 2, 334 - (2 * r.height() / 3));
+
+ int dx = ABS(stop.x - start.x);
+ int dy = ABS(stop.y - start.y);
+ TimeValue time = MAX(dx, dy);
+
+ allowInput(false);
+ _autoDragger.autoDrag(draggingSprite, start, stop, time, kDefaultTimeScale);
+
+ while (_autoDragger.isDragging()) {
+ checkCallBacks();
+ refreshDisplay();
+ _system->delayMillis(10);
+ }
+
+ addItemToInventory((InventoryItem *)_draggingItem);
+ allowInput(true);
+ delete _draggingSprite;
+
+ if (g_AIArea)
+ g_AIArea->unlockAI();
+}
+
+NeighborhoodID PegasusEngine::getCurrentNeighborhoodID() const {
+ if (_neighborhood)
+ return _neighborhood->getObjectID();
+
+ return kNoNeighborhoodID;
+}
+
+void PegasusEngine::pauseEngineIntern(bool pause) {
+ Engine::pauseEngineIntern(pause);
+
+ if (pause) {
+ for (Common::List<TimeBase *>::iterator it = _timeBases.begin(); it != _timeBases.end(); it++)
+ (*it)->pause();
+ } else {
+ for (Common::List<TimeBase *>::iterator it = _timeBases.begin(); it != _timeBases.end(); it++)
+ (*it)->resume();
+ }
+}
+
+uint PegasusEngine::getRandomBit() {
+ return _rnd->getRandomBit();
+}
+
+uint PegasusEngine::getRandomNumber(uint max) {
+ return _rnd->getRandomNumber(max);
+}
+
+void PegasusEngine::shuffleArray(int32 *arr, int32 count) {
+ if (count > 1) {
+ for (int32 i = 1; i < count; ++i) {
+ int32 j = _rnd->getRandomNumber(i);
+ if (j != i)
+ SWAP(arr[i], arr[j]);
+ }
+ }
+}
+
+void PegasusEngine::playEndMessage() {
+ if (g_interface) {
+ allowInput(false);
+ g_interface->playEndMessage();
+ allowInput(true);
+ }
+
+ die(kPlayerWonGame);
+}
+
+void PegasusEngine::doSubChase() {
+ Video::VideoDecoder *video = new Video::QuickTimeDecoder();
+ if (!video->loadFile("Images/Norad Alpha/Sub Chase Movie"))
+ error("Failed to load sub chase");
+
+ video->setEndTime(Audio::Timestamp(0, 133200, 600));
+ video->start();
+
+ while (!shouldQuit() && !video->endOfVideo()) {
+ if (video->needsUpdate()) {
+ const Graphics::Surface *frame = video->decodeNextFrame();
+
+ if (frame)
+ drawScaledFrame(frame, 0, 0);
+ }
+
+ Common::Event event;
+ while (_eventMan->pollEvent(event))
+ ;
+
+ _system->delayMillis(10);
+ }
+
+ delete video;
+}
+
+template<typename PixelInt>
+static void scaleFrame(const PixelInt *src, PixelInt *dst, int w, int h, int srcPitch) {
+ assert((srcPitch % sizeof(PixelInt)) == 0); // sanity check; allows some simpler code
+
+ PixelInt *dst1 = dst;
+ PixelInt *dst2 = dst + w * 2;
+
+ int srcInc = (srcPitch / sizeof(PixelInt)) - w;
+ int dstInc = w * 2;
+
+ while (h--) {
+ for (int x = 0; x < w; x++) {
+ PixelInt pixel = *src++;
+ *dst1++ = pixel;
+ *dst1++ = pixel;
+ *dst2++ = pixel;
+ *dst2++ = pixel;
+ }
+
+ src += srcInc;
+ dst1 += dstInc;
+ dst2 += dstInc;
+ }
+}
+
+void PegasusEngine::drawScaledFrame(const Graphics::Surface *frame, uint16 x, uint16 y) {
+ // Scale up the frame doing some simple scaling
+ Graphics::Surface scaledFrame;
+ scaledFrame.create(frame->w * 2, frame->h * 2, frame->format);
+
+ if (frame->format.bytesPerPixel == 2)
+ scaleFrame<uint16>((uint16 *)frame->pixels, (uint16 *)scaledFrame.pixels, frame->w, frame->h, frame->pitch);
+ else
+ scaleFrame<uint32>((uint32 *)frame->pixels, (uint32 *)scaledFrame.pixels, frame->w, frame->h, frame->pitch);
+
+ _system->copyRectToScreen((byte *)scaledFrame.pixels, scaledFrame.pitch, x, y, scaledFrame.w, scaledFrame.h);
+ _system->updateScreen();
+ scaledFrame.free();
+}
+
+void PegasusEngine::destroyInventoryItem(const ItemID itemID) {
+ InventoryItem *item = (InventoryItem *)_allItems.findItemByID(itemID);
+
+ ItemExtraEntry entry;
+
+ switch (itemID) {
+ case kAirMask:
+ item->findItemExtra(kRemoveAirMask, entry);
+ item->setItemRoom(kMarsID, kMars49, kSouth);
+ break;
+ case kArgonCanister:
+ item->findItemExtra(kRemoveArgon, entry);
+ item->setItemRoom(kWSCID, kWSC02Morph, kSouth);
+ break;
+ case kCrowbar:
+ item->findItemExtra(kRemoveCrowbar, entry);
+ item->setItemRoom(kMarsID, kMars34, kSouth);
+ break;
+ case kJourneymanKey:
+ item->findItemExtra(kRemoveJourneymanKey, entry);
+ item->setItemRoom(kFullTSAID, kTSA22Red, kEast);
+ break;
+ case kMarsCard:
+ item->findItemExtra(kRemoveMarsCard, entry);
+ item->setItemRoom(kMarsID, kMars31South, kSouth);
+ break;
+ case kNitrogenCanister:
+ item->findItemExtra(kRemoveNitrogen, entry);
+ item->setItemRoom(kWSCID, kWSC02Messages, kSouth);
+ break;
+ case kOrangeJuiceGlassEmpty:
+ item->findItemExtra(kRemoveGlass, entry);
+ item->setItemRoom(kCaldoriaID, kCaldoriaReplicator, kNorth);
+ break;
+ case kPoisonDart:
+ item->findItemExtra(kRemoveDart, entry);
+ item->setItemRoom(kWSCID, kWSC01, kWest);
+ break;
+ case kSinclairKey:
+ item->findItemExtra(kRemoveSinclairKey, entry);
+ item->setItemRoom(kWSCID, kWSC02Morph, kSouth);
+ break;
+ default:
+ return;
+ }
+
+ g_interface->setCurrentInventoryItemID(itemID);
+ g_AIArea->playAIAreaSequence(kInventorySignature, kMiddleAreaSignature, entry.extraStart, entry.extraStop);
+ removeItemFromInventory(item);
+}
+
+ItemID PegasusEngine::pickItemToDestroy() {
+/*
+ Must pick an item to destroy
+
+ Part I: Polite -- try to find an item that's been used
+ Part II: Desperate -- return the first available item.
+*/
+
+ // Polite:
+ if (playerHasItemID(kOrangeJuiceGlassEmpty))
+ return kOrangeJuiceGlassEmpty;
+ if (playerHasItemID(kPoisonDart)) {
+ if (GameState.getCurrentNeighborhood() != kWSCID ||
+ GameState.getWSCAnalyzedDart())
+ return kPoisonDart;
+ }
+ if (playerHasItemID(kJourneymanKey)) {
+ if (GameState.getTSAState() >= kTSAPlayerGotHistoricalLog &&
+ GameState.getTSAState() != kPlayerOnWayToPrehistoric &&
+ GameState.getTSAState() != kPlayerWentToPrehistoric)
+ return kJourneymanKey;
+ }
+ if (playerHasItemID(kMarsCard)) {
+ if (GameState.getCurrentNeighborhood() != kMarsID || GameState.getMarsArrivedBelow())
+ return kMarsCard;
+ }
+
+ // Don't want to deal with deleting the sinclair key and argon canister, since it's
+ // impossible to pick them up one at a time.
+
+ if (playerHasItemID(kNitrogenCanister)) {
+ if (GameState.getScoringGotCardBomb() && GameState.getCurrentNeighborhood() != kMarsID)
+ return kNitrogenCanister;
+ }
+ if (playerHasItemID(kCrowbar)) {
+ if (GameState.getCurrentNeighborhood() == kWSCID) {
+ if (GameState.getCurrentRoom() >= kWSC62)
+ return kCrowbar;
+ } else if (GameState.getCurrentNeighborhood() == kMarsID) {
+ if (GameState.getScoringGotCardBomb())
+ return kCrowbar;
+ } else
+ return kCrowbar;
+ }
+ if (playerHasItemID(kAirMask)) {
+ if (GameState.getCurrentNeighborhood() == kMarsID) {
+ if (g_neighborhood->getAirQuality(GameState.getCurrentRoom()) == kAirQualityGood)
+ return kAirMask;
+ } else if (GameState.getCurrentNeighborhood() != kNoradAlphaID &&
+ GameState.getCurrentNeighborhood() != kNoradDeltaID) {
+ return kAirMask;
+ }
+ }
+
+ // Desperate:
+ if (playerHasItemID(kPoisonDart))
+ return kPoisonDart;
+ if (playerHasItemID(kJourneymanKey))
+ return kJourneymanKey;
+ if (playerHasItemID(kMarsCard))
+ return kMarsCard;
+ if (playerHasItemID(kNitrogenCanister))
+ return kNitrogenCanister;
+ if (playerHasItemID(kCrowbar))
+ return kCrowbar;
+ if (playerHasItemID(kAirMask))
+ return kAirMask;
+
+ // Should never get this far...
+ error("Could not find item to delete");
+
+ return kNoItemID;
+}
+
+uint PegasusEngine::getNeighborhoodCD(const NeighborhoodID neighborhood) const {
+ switch (neighborhood) {
+ case kCaldoriaID:
+ case kNoradAlphaID:
+ case kNoradSubChaseID:
+ return 1;
+ case kFullTSAID:
+ case kPrehistoricID:
+ return 2;
+ case kMarsID:
+ return 3;
+ case kWSCID:
+ case kNoradDeltaID:
+ return 4;
+ case kTinyTSAID:
+ // Tiny TSA exists on three of the CD's, so just continue
+ // with the CD we're on
+ return _currentCD;
+ }
+
+ // Can't really happen, but it's a good fallback anyway :P
+ return 1;
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/pegasus.h b/engines/pegasus/pegasus.h
new file mode 100644
index 0000000000..2a8ba22470
--- /dev/null
+++ b/engines/pegasus/pegasus.h
@@ -0,0 +1,327 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_H
+#define PEGASUS_H
+
+#include "common/list.h"
+#include "common/macresman.h"
+#include "common/rect.h"
+#include "common/scummsys.h"
+#include "common/system.h"
+#include "common/util.h"
+
+#include "engines/engine.h"
+
+#include "pegasus/graphics.h"
+#include "pegasus/hotspot.h"
+#include "pegasus/input.h"
+#include "pegasus/notification.h"
+#include "pegasus/timers.h"
+#include "pegasus/items/autodragger.h"
+#include "pegasus/items/inventory.h"
+#include "pegasus/items/itemdragger.h"
+#include "pegasus/neighborhood/neighborhood.h"
+
+namespace Common {
+ class RandomSource;
+}
+
+namespace Video {
+ class VideoDecoder;
+}
+
+namespace Pegasus {
+
+class PegasusConsole;
+struct PegasusGameDescription;
+class SoundManager;
+class GraphicsManager;
+class Idler;
+class Cursor;
+class TimeBase;
+class GameMenu;
+class InventoryItem;
+class BiochipItem;
+class Neighborhood;
+
+class PegasusEngine : public ::Engine, public InputHandler, public NotificationManager {
+friend class InputHandler;
+
+public:
+ PegasusEngine(OSystem *syst, const PegasusGameDescription *gamedesc);
+ virtual ~PegasusEngine();
+
+ // Engine stuff
+ const PegasusGameDescription *_gameDescription;
+ bool hasFeature(EngineFeature f) const;
+ GUI::Debugger *getDebugger();
+ bool canLoadGameStateCurrently();
+ bool canSaveGameStateCurrently();
+ Common::Error loadGameState(int slot);
+ Common::Error saveGameState(int slot, const Common::String &desc);
+
+ // Base classes
+ GraphicsManager *_gfx;
+ Common::MacResManager *_resFork;
+ Cursor *_cursor;
+
+ // Menu
+ void useMenu(GameMenu *menu);
+ bool checkGameMenu();
+
+ // Misc.
+ bool isDemo() const;
+ void addIdler(Idler *idler);
+ void removeIdler(Idler *idler);
+ void addTimeBase(TimeBase *timeBase);
+ void removeTimeBase(TimeBase *timeBase);
+ void delayShell(TimeValue time, TimeScale scale);
+ void resetIntroTimer();
+ void introTimerExpired();
+ void refreshDisplay();
+ bool playerAlive();
+ void processShell();
+ void checkCallBacks();
+ void createInterface();
+ void setGameMode(const GameMode);
+ GameMode getGameMode() const { return _gameMode; }
+ uint getRandomBit();
+ uint getRandomNumber(uint max);
+ void shuffleArray(int32 *arr, int32 count);
+ void drawScaledFrame(const Graphics::Surface *frame, uint16 x, uint16 y);
+ HotspotList &getAllHotspots() { return _allHotspots; }
+
+ // Energy
+ void setLastEnergyValue(const int32 value) { _savedEnergyValue = value; }
+ int32 getSavedEnergyValue() { return _savedEnergyValue; }
+
+ // Death
+ void setEnergyDeathReason(const DeathReason reason) { _deathReason = reason; }
+ DeathReason getEnergyDeathReason() { return _deathReason; }
+ void resetEnergyDeathReason();
+ void die(const DeathReason);
+ void playEndMessage();
+
+ // Volume
+ uint16 getSoundFXLevel() { return _FXLevel; }
+ void setSoundFXLevel(uint16);
+ uint16 getAmbienceLevel() { return _ambientLevel; }
+ void setAmbienceLevel(uint16);
+
+ // Items
+ ItemList &getAllItems() { return _allItems; }
+ bool playerHasItem(const Item *);
+ bool playerHasItemID(const ItemID);
+ void checkFlashlight();
+ bool itemInLocation(const ItemID, const NeighborhoodID, const RoomID, const DirectionConstant);
+
+ // Inventory Items
+ InventoryItem *getCurrentInventoryItem();
+ bool itemInInventory(InventoryItem *);
+ bool itemInInventory(ItemID);
+ Inventory *getItemsInventory() { return &_items; }
+ InventoryResult addItemToInventory(InventoryItem *);
+ void removeAllItemsFromInventory();
+ InventoryResult removeItemFromInventory(InventoryItem *);
+ uint32 countInventoryItems() { return _items.getNumItems(); }
+
+ // Biochips
+ BiochipItem *getCurrentBiochip();
+ bool itemInBiochips(BiochipItem *);
+ bool itemInBiochips(ItemID);
+ Inventory *getBiochipsInventory() { return &_biochips; }
+ void removeAllItemsFromBiochips();
+ InventoryResult addItemToBiochips(BiochipItem *);
+
+ // AI
+ Common::String getBriefingMovie();
+ Common::String getEnvScanMovie();
+ uint getNumHints();
+ Common::String getHintMovie(uint);
+ bool canSolve();
+ void prepareForAIHint(const Common::String &);
+ void cleanUpAfterAIHint(const Common::String &);
+ Common::SeekableReadStream *_aiSaveStream;
+
+ // Neighborhood
+ void jumpToNewEnvironment(const NeighborhoodID, const RoomID, const DirectionConstant);
+ NeighborhoodID getCurrentNeighborhoodID() const;
+
+ // Dragging
+ void dragItem(const Input &, Item *, DragType);
+ bool isDragging() const { return _dragType != kDragNoDrag; }
+ DragType getDragType() const { return _dragType; }
+ Item *getDraggingItem() const { return _draggingItem; }
+ void dragTerminated(const Input &);
+ void autoDragItemIntoRoom(Item *, Sprite *);
+ void autoDragItemIntoInventory(Item *, Sprite*);
+
+ // Save/Load
+ void makeContinuePoint();
+ bool swapSaveAllowed(bool allow) {
+ bool old = _saveAllowed;
+ _saveAllowed = allow;
+ return old;
+ }
+ bool swapLoadAllowed(bool allow) {
+ bool old = _loadAllowed;
+ _loadAllowed = allow;
+ return old;
+ }
+ void requestSave() { _saveRequested = true; }
+ bool saveRequested() const { return _saveRequested; }
+ void requestLoad() { _loadRequested = true; }
+ bool loadRequested() const { return _loadRequested; }
+
+protected:
+ Common::Error run();
+ void pauseEngineIntern(bool pause);
+
+ Notification _shellNotification;
+ virtual void receiveNotification(Notification *notification, const NotificationFlags flags);
+
+ void handleInput(const Input &input, const Hotspot *cursorSpot);
+ virtual bool isClickInput(const Input &, const Hotspot *);
+ virtual InputBits getClickFilter();
+
+ void clickInHotspot(const Input &, const Hotspot *);
+ void activateHotspots(void);
+
+ void updateCursor(const Common::Point, const Hotspot *);
+ bool wantsCursor();
+
+private:
+ // Console
+ PegasusConsole *_console;
+
+ // Intro
+ void runIntro();
+ void stopIntroTimer();
+ bool detectOpeningClosingDirectory();
+ Common::String _introDirectory;
+ FuseFunction *_introTimer;
+
+ // Idlers
+ Idler *_idlerHead;
+ void giveIdleTime();
+
+ // Items
+ ItemList _allItems;
+ void createItems();
+ void createItem(ItemID itemID, NeighborhoodID neighborhoodID, RoomID roomID, DirectionConstant direction);
+ Inventory _items;
+ Inventory _biochips;
+ ItemID _currentItemID;
+ ItemID _currentBiochipID;
+ void destroyInventoryItem(const ItemID itemID);
+ ItemID pickItemToDestroy();
+
+ // TimeBases
+ Common::List<TimeBase *> _timeBases;
+
+ // Save/Load
+ bool loadFromStream(Common::ReadStream *stream);
+ bool writeToStream(Common::WriteStream *stream, int saveType);
+ void loadFromContinuePoint();
+ void writeContinueStream(Common::WriteStream *stream);
+ Common::SeekableReadStream *_continuePoint;
+ bool _saveAllowed, _loadAllowed; // It's so nice that this was in the original code already :P
+ Common::Error showLoadDialog();
+ Common::Error showSaveDialog();
+ bool _saveRequested, _loadRequested;
+
+ // Misc.
+ Hotspot _returnHotspot;
+ HotspotList _allHotspots;
+ InputHandler *_savedHandler;
+ void showTempScreen(const Common::String &fileName);
+ bool playMovieScaled(Video::VideoDecoder *video, uint16 x, uint16 y);
+ void throwAwayEverything();
+ void shellGameInput(const Input &input, const Hotspot *cursorSpot);
+ Common::RandomSource *_rnd;
+ void doSubChase();
+ uint getNeighborhoodCD(const NeighborhoodID neighborhood) const;
+ uint _currentCD;
+
+ // Menu
+ GameMenu *_gameMenu;
+ void doGameMenuCommand(const GameMenuCommand);
+ void doInterfaceOverview();
+ ScreenDimmer _screenDimmer;
+ void pauseMenu(bool menuUp);
+
+ // Energy
+ int32 _savedEnergyValue;
+
+ // Death
+ DeathReason _deathReason;
+ void doDeath();
+
+ // Neighborhood
+ Neighborhood *_neighborhood;
+ void useNeighborhood(Neighborhood *neighborhood);
+ void performJump(NeighborhoodID start);
+ void startNewGame();
+ void startNeighborhood();
+ void makeNeighborhood(NeighborhoodID, Neighborhood *&);
+
+ // Sound
+ uint16 _ambientLevel;
+ uint16 _FXLevel;
+
+ // Game Mode
+ GameMode _gameMode;
+ bool _switchModesSync;
+ void switchGameMode(const GameMode, const GameMode);
+ bool canSwitchGameMode(const GameMode, const GameMode);
+
+ // Dragging
+ ItemDragger _itemDragger;
+ Item *_draggingItem;
+ Sprite *_draggingSprite;
+ DragType _dragType;
+ AutoDragger _autoDragger;
+
+ // Interface
+ void toggleInventoryDisplay();
+ void toggleBiochipDisplay();
+ void raiseInventoryDrawer();
+ void raiseBiochipDrawer();
+ void lowerInventoryDrawer();
+ void lowerBiochipDrawer();
+ void raiseInventoryDrawerSync();
+ void raiseBiochipDrawerSync();
+ void lowerInventoryDrawerSync();
+ void lowerBiochipDrawerSync();
+ void showInfoScreen();
+ void hideInfoScreen();
+ void toggleInfo();
+ Movie _bigInfoMovie, _smallInfoMovie;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/scoring.h b/engines/pegasus/scoring.h
new file mode 100644
index 0000000000..fbf8641ecb
--- /dev/null
+++ b/engines/pegasus/scoring.h
@@ -0,0 +1,281 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_SCORING_H
+#define PEGASUS_SCORING_H
+
+#include "pegasus/types.h"
+
+namespace Pegasus {
+
+/////////////////////////////////////////////
+//
+// Scoring.
+
+static const CoordType kDeathScreenScoreLeft = 151;
+static const CoordType kDeathScreenScoreTop = 212;
+static const CoordType kDeathScreenScoreWidth = 124;
+static const CoordType kDeathScreenScoreHeight = 12;
+static const CoordType kDeathScreenScoreSkipVert = -16;
+
+// Caldoria & TSA
+
+static const GameScoreType kSawINNScore = 5;
+static const GameScoreType kTookShowerScore = 2;
+static const GameScoreType kFixedHairScore = 2;
+static const GameScoreType kGotKeyCardScore = 5;
+static const GameScoreType kReadPaperScore = 2;
+static const GameScoreType kLookThroughTelescopeScore = 2;
+static const GameScoreType kSawCaldoriaKioskScore = 2;
+static const GameScoreType kGoToTSAScore = 3;
+
+static const GameScoreType kEnterTSAScore = 2;
+static const GameScoreType kSawBust1Score = 2;
+static const GameScoreType kSawBust2Score = 2;
+static const GameScoreType kSawBust3Score = 2;
+static const GameScoreType kSawBust4Score = 2;
+static const GameScoreType kSawBust5Score = 2;
+static const GameScoreType kSawBust6Score = 2;
+static const GameScoreType kSawTheoryScore = 4;
+static const GameScoreType kSawBackgroundScore = 4;
+static const GameScoreType kSawProcedureScore = 4;
+static const GameScoreType kGotJourneymanKeyScore = 5;
+static const GameScoreType kGotPegasusBiochipScore = 5;
+static const GameScoreType kGotBiosuitScore = 5;
+static const GameScoreType kGoToPrehistoricScore = 5;
+
+static const GameScoreType kPutLogInReaderScore = 5;
+static const GameScoreType kSawCaldoriaNormalScore = 2;
+static const GameScoreType kSawCaldoriaAlteredScore = 2;
+static const GameScoreType kSawNoradNormalScore = 2;
+static const GameScoreType kSawNoradAlteredScore = 2;
+static const GameScoreType kSawMarsNormalScore = 2;
+static const GameScoreType kSawMarsAlteredScore = 2;
+static const GameScoreType kSawWSCNormalScore = 2;
+static const GameScoreType kSawWSCAlteredScore = 2;
+static const GameScoreType kWentToReadyRoom2Score = 5;
+static const GameScoreType kWentAfterSinclairScore = 5;
+static const GameScoreType kUsedCardBombScore = 10;
+static const GameScoreType kShieldedCardBombScore = 5;
+static const GameScoreType kStunnedSinclairScore = 10;
+static const GameScoreType kDisarmedNukeScore = 10;
+
+static const GameScoreType kMaxCaldoriaTSAScoreBefore = kSawINNScore +
+ kTookShowerScore +
+ kFixedHairScore +
+ kGotKeyCardScore +
+ kReadPaperScore +
+ kLookThroughTelescopeScore +
+ kSawCaldoriaKioskScore +
+ kGoToTSAScore +
+ kEnterTSAScore +
+ kSawBust1Score +
+ kSawBust2Score +
+ kSawBust3Score +
+ kSawBust4Score +
+ kSawBust5Score +
+ kSawBust6Score +
+ kSawTheoryScore +
+ kSawBackgroundScore +
+ kSawProcedureScore +
+ kGotJourneymanKeyScore +
+ kGotPegasusBiochipScore +
+ kGotBiosuitScore +
+ kGoToPrehistoricScore +
+ kPutLogInReaderScore +
+ kSawCaldoriaNormalScore +
+ kSawCaldoriaAlteredScore +
+ kSawNoradNormalScore +
+ kSawNoradAlteredScore +
+ kSawMarsNormalScore +
+ kSawMarsAlteredScore +
+ kSawWSCNormalScore +
+ kSawWSCAlteredScore +
+ kWentToReadyRoom2Score;
+
+static const GameScoreType kMaxCaldoriaTSAScoreAfter = kWentAfterSinclairScore +
+ kUsedCardBombScore +
+ kShieldedCardBombScore +
+ kStunnedSinclairScore +
+ kDisarmedNukeScore;
+
+static const GameScoreType kMaxCaldoriaTSAScore = kMaxCaldoriaTSAScoreBefore +
+ kMaxCaldoriaTSAScoreAfter;
+
+// Prehistoric
+
+static const GameScoreType kThrewBreakerScore = 10;
+static const GameScoreType kExtendedBridgeScore = 10;
+static const GameScoreType kGotHistoricalLogScore = 5;
+static const GameScoreType kFinishedPrehistoricScore = 10;
+
+static const GameScoreType kMaxPrehistoricScore = kThrewBreakerScore +
+ kExtendedBridgeScore +
+ kGotHistoricalLogScore +
+ kFinishedPrehistoricScore;
+
+// Mars
+
+static const GameScoreType kThrownByRobotScore = 3;
+static const GameScoreType kGotMarsCardScore = 5;
+static const GameScoreType kSawMarsKioskScore = 2;
+static const GameScoreType kSawTransportMapScore = 2;
+static const GameScoreType kGotCrowBarScore = 5;
+static const GameScoreType kTurnedOnTransportScore = 5;
+static const GameScoreType kGotOxygenMaskScore = 5;
+static const GameScoreType kAvoidedRobotScore = 5;
+static const GameScoreType kActivatedPlatformScore = 2;
+static const GameScoreType kUsedLiquidNitrogenScore = 3;
+static const GameScoreType kUsedCrowBarScore = 3;
+static const GameScoreType kFoundCardBombScore = 4;
+static const GameScoreType kDisarmedCardBombScore = 8;
+static const GameScoreType kGotCardBombScore = 5;
+static const GameScoreType kThreadedMazeScore = 5;
+static const GameScoreType kThreadedGearRoomScore = 2;
+static const GameScoreType kEnteredShuttleScore = 2;
+static const GameScoreType kEnteredLaunchTubeScore = 4;
+static const GameScoreType kStoppedRobotsShuttleScore = 10;
+static const GameScoreType kGotMarsOpMemChipScore = 10;
+static const GameScoreType kFinishedMarsScore = 10;
+
+static const GameScoreType kMaxMarsScore = kThrownByRobotScore +
+ kGotMarsCardScore +
+ kSawMarsKioskScore +
+ kSawTransportMapScore +
+ kGotCrowBarScore +
+ kTurnedOnTransportScore +
+ kGotOxygenMaskScore +
+ kAvoidedRobotScore +
+ kActivatedPlatformScore +
+ kUsedLiquidNitrogenScore +
+ kUsedCrowBarScore +
+ kFoundCardBombScore +
+ kDisarmedCardBombScore +
+ kGotCardBombScore +
+ kThreadedMazeScore +
+ kThreadedGearRoomScore +
+ kEnteredShuttleScore +
+ kEnteredLaunchTubeScore +
+ kStoppedRobotsShuttleScore +
+ kGotMarsOpMemChipScore +
+ kFinishedMarsScore;
+
+// Norad
+
+static const GameScoreType kSawSecurityMonitorScore = 5;
+static const GameScoreType kFilledOxygenCanisterScore = 5;
+static const GameScoreType kFilledArgonCanisterScore = 5;
+static const GameScoreType kSawUnconsciousOperatorScore = 5;
+static const GameScoreType kWentThroughPressureDoorScore = 5;
+static const GameScoreType kPreppedSubScore = 5;
+static const GameScoreType kEnteredSubScore = 5;
+static const GameScoreType kExitedSubScore = 10;
+static const GameScoreType kSawRobotAt54NorthScore = 5;
+static const GameScoreType kPlayedWithClawScore = 5;
+static const GameScoreType kUsedRetinalChipScore = 5;
+static const GameScoreType kFinishedGlobeGameScore = 10;
+static const GameScoreType kStoppedNoradRobotScore = 10;
+static const GameScoreType kGotNoradOpMemChipScore = 10;
+static const GameScoreType kFinishedNoradScore = 10;
+
+static const GameScoreType kMaxNoradScore = kSawSecurityMonitorScore +
+ kFilledOxygenCanisterScore +
+ kFilledArgonCanisterScore +
+ kSawUnconsciousOperatorScore +
+ kWentThroughPressureDoorScore +
+ kPreppedSubScore +
+ kEnteredSubScore +
+ kExitedSubScore +
+ kSawRobotAt54NorthScore +
+ kPlayedWithClawScore +
+ kUsedRetinalChipScore +
+ kFinishedGlobeGameScore +
+ kStoppedNoradRobotScore +
+ kGotNoradOpMemChipScore +
+ kFinishedNoradScore;
+
+// WSC
+
+static const GameScoreType kRemovedDartScore = 5;
+static const GameScoreType kAnalyzedDartScore = 5;
+static const GameScoreType kBuiltAntidoteScore = 5;
+static const GameScoreType kGotSinclairKeyScore = 5;
+static const GameScoreType kGotArgonCanisterScore = 5;
+static const GameScoreType kGotNitrogenCanisterScore = 5;
+static const GameScoreType kPlayedWithMessagesScore = 2;
+static const GameScoreType kSawMorphExperimentScore = 3;
+static const GameScoreType kEnteredSinclairOfficeScore = 2;
+static const GameScoreType kSawBrochureScore = 3;
+static const GameScoreType kSawSinclairEntry1Score = 3;
+static const GameScoreType kSawSinclairEntry2Score = 3;
+static const GameScoreType kSawSinclairEntry3Score = 3;
+static const GameScoreType kSawWSCDirectoryScore = 3;
+static const GameScoreType kUsedCrowBarInWSCScore = 5;
+static const GameScoreType kFinishedPlasmaDodgeScore = 10;
+static const GameScoreType kOpenedCatwalkScore = 3;
+static const GameScoreType kStoppedWSCRobotScore = 10;
+static const GameScoreType kGotWSCOpMemChipScore = 10;
+static const GameScoreType kFinishedWSCScore = 10;
+
+static const GameScoreType kMaxWSCScore = kRemovedDartScore +
+ kAnalyzedDartScore +
+ kBuiltAntidoteScore +
+ kGotSinclairKeyScore +
+ kGotArgonCanisterScore +
+ kGotNitrogenCanisterScore +
+ kPlayedWithMessagesScore +
+ kSawMorphExperimentScore +
+ kEnteredSinclairOfficeScore +
+ kSawBrochureScore +
+ kSawSinclairEntry1Score +
+ kSawSinclairEntry2Score +
+ kSawSinclairEntry3Score +
+ kSawWSCDirectoryScore +
+ kUsedCrowBarInWSCScore +
+ kFinishedPlasmaDodgeScore +
+ kOpenedCatwalkScore +
+ kStoppedWSCRobotScore +
+ kGotWSCOpMemChipScore +
+ kFinishedWSCScore;
+
+// Gandhi
+
+static const GameScoreType kMarsGandhiScore = 10;
+static const GameScoreType kNoradGandhiScore = 10;
+static const GameScoreType kWSCGandhiScore = 10;
+
+static const GameScoreType kMaxGandhiScore = kMarsGandhiScore +
+ kNoradGandhiScore +
+ kWSCGandhiScore;
+
+static const GameScoreType kMaxTotalScore = kMaxCaldoriaTSAScore +
+ kMaxPrehistoricScore +
+ kMaxMarsScore +
+ kMaxNoradScore +
+ kMaxWSCScore +
+ kMaxGandhiScore;
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/sound.cpp b/engines/pegasus/sound.cpp
new file mode 100644
index 0000000000..bf15858e80
--- /dev/null
+++ b/engines/pegasus/sound.cpp
@@ -0,0 +1,181 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "audio/audiostream.h"
+#include "audio/decoders/aiff.h"
+#include "audio/decoders/quicktime.h"
+#include "common/file.h"
+#include "common/system.h"
+
+#include "pegasus/fader.h"
+#include "pegasus/sound.h"
+
+namespace Pegasus {
+
+Sound::Sound() {
+ _stream = 0;
+ _volume = 0xFF;
+ _fader = 0;
+}
+
+Sound::~Sound() {
+ disposeSound();
+}
+
+void Sound::disposeSound() {
+ stopSound();
+ delete _stream; _stream = 0;
+}
+
+void Sound::initFromAIFFFile(const Common::String &fileName) {
+ disposeSound();
+
+ Common::File *file = new Common::File();
+ if (!file->open(fileName)) {
+ warning("Failed to open AIFF file '%s'", fileName.c_str());
+ delete file;
+ return;
+ }
+
+ _stream = Audio::makeAIFFStream(file, DisposeAfterUse::YES);
+}
+
+void Sound::initFromQuickTime(const Common::String &fileName) {
+ disposeSound();
+
+ _stream = Audio::makeQuickTimeStream(fileName);
+
+ if (!_stream)
+ warning("Failed to open QuickTime file '%s'", fileName.c_str());
+}
+
+void Sound::attachFader(SoundFader *fader) {
+ if (_fader)
+ _fader->attachSound(0);
+
+ _fader = fader;
+
+ if (_fader)
+ _fader->attachSound(this);
+}
+
+void Sound::playSound() {
+ if (!isSoundLoaded())
+ return;
+
+ stopSound();
+
+ if (_fader)
+ setVolume(_fader->getFaderValue());
+
+ g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_handle, _stream, -1, _volume, 0, DisposeAfterUse::NO);
+}
+
+void Sound::loopSound() {
+ if (!isSoundLoaded())
+ return;
+
+ stopSound();
+
+ // Create a looping stream
+ Audio::AudioStream *loopStream = new Audio::LoopingAudioStream(_stream, 0, DisposeAfterUse::NO);
+
+ // Assume that if there is a fader, we're going to fade the sound in.
+ if (_fader)
+ setVolume(0);
+
+ g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_handle, loopStream, -1, _volume, 0, DisposeAfterUse::YES);
+}
+
+void Sound::playSoundSegment(uint32 start, uint32 end) {
+ if (!isSoundLoaded())
+ return;
+
+ stopSound();
+
+ Audio::AudioStream *subStream = new Audio::SubSeekableAudioStream(_stream, Audio::Timestamp(0, start, 600), Audio::Timestamp(0, end, 600), DisposeAfterUse::NO);
+
+ g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_handle, subStream, -1, _volume, 0, DisposeAfterUse::YES);
+}
+
+void Sound::stopSound() {
+ g_system->getMixer()->stopHandle(_handle);
+}
+
+void Sound::setVolume(const uint16 volume) {
+ // Clipping the volume to [0x00, 0xFF] instead of Apple's [0, 0x100]
+ // We store the volume in case SetVolume is called before the sound starts
+
+ _volume = (volume == 0x100) ? 0xFF : volume;
+ g_system->getMixer()->setChannelVolume(_handle, _volume);
+}
+
+bool Sound::isPlaying() {
+ return isSoundLoaded() && g_system->getMixer()->isSoundHandleActive(_handle);
+}
+
+bool Sound::isSoundLoaded() const {
+ return _stream != 0;
+}
+
+SoundTimeBase::SoundTimeBase() {
+ setScale(600);
+ _startScale = 600;
+ _stopScale = 600;
+ _setToStart = false;
+}
+
+void SoundTimeBase::playSoundSegment(uint32 startTime, uint32 endTime) {
+ _startTime = startTime;
+ _stopTime = endTime;
+ _setToStart = true;
+ _time = Common::Rational(startTime, getScale());
+ setRate(1);
+ Sound::playSoundSegment(startTime, endTime);
+}
+
+void SoundTimeBase::updateTime() {
+ if (_setToStart) {
+ if (isPlaying()) {
+ // Not at the end, let's get the time
+ uint numFrames = g_system->getMixer()->getSoundElapsedTime(_handle) * 600 / 1000;
+
+ // WORKAROUND: Our mixer is woefully inaccurate and quite often returns
+ // times that exceed the actual length of the clip. We'll just fake times
+ // that are under the final time to ensure any trigger for the end time is
+ // only sent when the sound has actually stopped.
+ if (numFrames >= (_stopTime - _startTime))
+ numFrames = _stopTime - _startTime - 1;
+
+ _time = Common::Rational(_startTime + numFrames, getScale());
+ } else {
+ // Assume we reached the end
+ _setToStart = false;
+ _time = Common::Rational(_stopTime, getScale());
+ }
+ }
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/sound.h b/engines/pegasus/sound.h
new file mode 100644
index 0000000000..57cfd52e41
--- /dev/null
+++ b/engines/pegasus/sound.h
@@ -0,0 +1,108 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_SOUND_H
+#define PEGASUS_SOUND_H
+
+#include "audio/mixer.h"
+#include "common/str.h"
+#include "pegasus/timers.h"
+
+namespace Audio {
+ class SeekableAudioStream;
+}
+
+namespace Pegasus {
+
+class SoundFader;
+
+// Things you might want to do with sound:
+// - Start it
+// - Stop it
+// - Loop it
+// - Pause it
+// - Set the volume
+// - Set the pitch (rate)
+// - Pan the sound
+// - Change these settings dynamically over time
+
+class Sound {
+public:
+ Sound();
+ ~Sound();
+
+ // We only have one access point here because we should
+ // only be opening an AIFF file from a file name. We're
+ // not using the resource fork string resources.
+ void initFromAIFFFile(const Common::String &fileName);
+
+ // Unlike the original game, we're going to use a regular
+ // audio stream for sound spots. The original treated them
+ // as movies.
+ void initFromQuickTime(const Common::String &fileName);
+
+ void disposeSound();
+ bool isSoundLoaded() const;
+ void playSound();
+ void loopSound();
+ void playSoundSegment(uint32 start, uint32 end);
+ void stopSound();
+ void setVolume(const uint16 volume);
+ bool isPlaying();
+
+ void attachFader(SoundFader *fader);
+
+protected:
+ Audio::SeekableAudioStream *_stream;
+ Audio::SoundHandle _handle;
+ byte _volume;
+
+ SoundFader *_fader;
+};
+
+// TODO: Make this class follow TimeBase better
+// Right now it's just a loose wrapper to plug callbacks
+// into sounds. Since this is only used for spot sounds,
+// I'm not too worried about it right now as its usage
+// is very limited.
+// At the very least, the regular TimeBase functions for
+// setting/getting should be neutered.
+class SoundTimeBase : public Sound, public TimeBase {
+public:
+ SoundTimeBase();
+ ~SoundTimeBase() {}
+
+ void playSoundSegment(uint32 start, uint32 end);
+
+protected:
+ void updateTime();
+
+private:
+ bool _setToStart;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/surface.cpp b/engines/pegasus/surface.cpp
new file mode 100644
index 0000000000..cdcb3c6e79
--- /dev/null
+++ b/engines/pegasus/surface.cpp
@@ -0,0 +1,396 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/file.h"
+#include "common/macresman.h"
+#include "common/stream.h"
+#include "common/system.h"
+#include "graphics/surface.h"
+#include "graphics/decoders/pict.h"
+#include "video/video_decoder.h"
+
+#include "pegasus/pegasus.h"
+#include "pegasus/surface.h"
+
+namespace Pegasus {
+
+Surface::Surface() {
+ _ownsSurface = false;
+ _surface = 0;
+}
+
+Surface::~Surface() {
+ deallocateSurface();
+}
+
+void Surface::deallocateSurface() {
+ if (_surface) {
+ if (_ownsSurface) {
+ _surface->free();
+ delete _surface;
+ }
+
+ _surface = 0;
+ _bounds = Common::Rect();
+ _ownsSurface = false;
+ }
+}
+
+void Surface::shareSurface(Surface *surface) {
+ deallocateSurface();
+
+ if (surface) {
+ _ownsSurface = false;
+ _surface = surface->getSurface();
+ surface->getSurfaceBounds(_bounds);
+ }
+}
+
+void Surface::allocateSurface(const Common::Rect &bounds) {
+ deallocateSurface();
+
+ if (bounds.isEmpty())
+ return;
+
+ _bounds = bounds;
+ _surface = new Graphics::Surface();
+ _surface->create(bounds.width(), bounds.height(), g_system->getScreenFormat());
+ _ownsSurface = true;
+}
+
+void Surface::getImageFromPICTFile(const Common::String &fileName) {
+ Common::File pict;
+ if (!pict.open(fileName))
+ error("Could not open picture '%s'", fileName.c_str());
+
+ if (!getImageFromPICTStream(&pict))
+ error("Failed to load PICT '%s'", fileName.c_str());
+}
+
+void Surface::getImageFromPICTResource(Common::MacResManager *resFork, uint16 id) {
+ Common::SeekableReadStream *res = resFork->getResource(MKTAG('P', 'I', 'C', 'T'), id);
+ if (!res)
+ error("Could not open PICT resource %d from '%s'", id, resFork->getBaseFileName().c_str());
+
+ if (!getImageFromPICTStream(res))
+ error("Failed to load PICT resource %d from '%s'", id, resFork->getBaseFileName().c_str());
+
+ delete res;
+}
+
+bool Surface::getImageFromPICTStream(Common::SeekableReadStream *stream) {
+ Graphics::PICTDecoder pict;
+
+ if (!pict.loadStream(*stream))
+ return false;
+
+ _surface = pict.getSurface()->convertTo(g_system->getScreenFormat(), pict.getPalette());
+ _ownsSurface = true;
+ _bounds = Common::Rect(0, 0, _surface->w, _surface->h);
+ return true;
+}
+
+void Surface::getImageFromMovieFrame(Video::VideoDecoder *video, TimeValue time) {
+ video->seek(Audio::Timestamp(0, time, 600));
+ const Graphics::Surface *frame = video->decodeNextFrame();
+
+ if (frame) {
+ if (!_surface)
+ _surface = new Graphics::Surface();
+
+ _surface->copyFrom(*frame);
+ _ownsSurface = true;
+ _bounds = Common::Rect(0, 0, _surface->w, _surface->h);
+ } else {
+ deallocateSurface();
+ }
+}
+
+void Surface::copyToCurrentPort() const {
+ copyToCurrentPort(_bounds);
+}
+
+void Surface::copyToCurrentPortTransparent() const {
+ copyToCurrentPortTransparent(_bounds);
+}
+
+void Surface::copyToCurrentPort(const Common::Rect &rect) const {
+ copyToCurrentPort(rect, rect);
+}
+
+void Surface::copyToCurrentPortTransparent(const Common::Rect &rect) const {
+ copyToCurrentPortTransparent(rect, rect);
+}
+
+void Surface::copyToCurrentPort(const Common::Rect &srcRect, const Common::Rect &dstRect) const {
+ Graphics::Surface *screen = ((PegasusEngine *)g_engine)->_gfx->getCurSurface();
+ byte *src = (byte *)_surface->getBasePtr(srcRect.left, srcRect.top);
+ byte *dst = (byte *)screen->getBasePtr(dstRect.left, dstRect.top);
+
+ int lineSize = srcRect.width() * _surface->format.bytesPerPixel;
+
+ for (int y = 0; y < srcRect.height(); y++) {
+ memcpy(dst, src, lineSize);
+ src += _surface->pitch;
+ dst += screen->pitch;
+ }
+}
+
+void Surface::copyToCurrentPortTransparent(const Common::Rect &srcRect, const Common::Rect &dstRect) const {
+ Graphics::Surface *screen = ((PegasusEngine *)g_engine)->_gfx->getCurSurface();
+ byte *src = (byte *)_surface->getBasePtr(srcRect.left, srcRect.top);
+ byte *dst = (byte *)screen->getBasePtr(dstRect.left, dstRect.top);
+
+ int lineSize = srcRect.width() * _surface->format.bytesPerPixel;
+
+ for (int y = 0; y < srcRect.height(); y++) {
+ for (int x = 0; x < srcRect.width(); x++) {
+ if (g_system->getScreenFormat().bytesPerPixel == 2) {
+ uint16 color = READ_UINT16(src);
+ if (!isTransparent(color))
+ memcpy(dst, src, 2);
+ } else if (g_system->getScreenFormat().bytesPerPixel == 4) {
+ uint32 color = READ_UINT32(src);
+ if (!isTransparent(color))
+ memcpy(dst, src, 4);
+ }
+
+ src += g_system->getScreenFormat().bytesPerPixel;
+ dst += g_system->getScreenFormat().bytesPerPixel;
+ }
+
+ src += _surface->pitch - lineSize;
+ dst += screen->pitch - lineSize;
+ }
+}
+
+void Surface::copyToCurrentPortMasked(const Common::Rect &srcRect, const Common::Rect &dstRect, const Surface *mask) const {
+ Graphics::Surface *screen = ((PegasusEngine *)g_engine)->_gfx->getCurSurface();
+ byte *src = (byte *)_surface->getBasePtr(srcRect.left, srcRect.top);
+ byte *dst = (byte *)screen->getBasePtr(dstRect.left, dstRect.top);
+
+ int lineSize = srcRect.width() * _surface->format.bytesPerPixel;
+
+ for (int y = 0; y < srcRect.height(); y++) {
+ byte *maskSrc = (byte *)mask->getSurface()->getBasePtr(0, y);
+
+ for (int x = 0; x < srcRect.width(); x++) {
+ if (g_system->getScreenFormat().bytesPerPixel == 2) {
+ uint16 color = READ_UINT16(maskSrc);
+ if (!isTransparent(color))
+ memcpy(dst, src, 2);
+ } else if (g_system->getScreenFormat().bytesPerPixel == 4) {
+ uint32 color = READ_UINT32(maskSrc);
+ if (!isTransparent(color))
+ memcpy(dst, src, 4);
+ }
+
+ src += g_system->getScreenFormat().bytesPerPixel;
+ maskSrc += g_system->getScreenFormat().bytesPerPixel;
+ dst += g_system->getScreenFormat().bytesPerPixel;
+ }
+
+ src += _surface->pitch - lineSize;
+ dst += screen->pitch - lineSize;
+ }
+}
+
+void Surface::copyToCurrentPortTransparentGlow(const Common::Rect &srcRect, const Common::Rect &dstRect) const {
+ // This is the same as copyToCurrentPortTransparent(), but turns the red value of each
+ // pixel all the way up.
+
+ Graphics::Surface *screen = ((PegasusEngine *)g_engine)->_gfx->getCurSurface();
+ byte *src = (byte *)_surface->getBasePtr(srcRect.left, srcRect.top);
+ byte *dst = (byte *)screen->getBasePtr(dstRect.left, dstRect.top);
+
+ int lineSize = srcRect.width() * _surface->format.bytesPerPixel;
+
+ for (int y = 0; y < srcRect.height(); y++) {
+ for (int x = 0; x < srcRect.width(); x++) {
+ if (g_system->getScreenFormat().bytesPerPixel == 2) {
+ uint16 color = READ_UINT16(src);
+ if (!isTransparent(color))
+ WRITE_UINT16(dst, getGlowColor(color));
+ } else if (g_system->getScreenFormat().bytesPerPixel == 4) {
+ uint32 color = READ_UINT32(src);
+ if (!isTransparent(color))
+ WRITE_UINT32(dst, getGlowColor(color));
+ }
+
+ src += g_system->getScreenFormat().bytesPerPixel;
+ dst += g_system->getScreenFormat().bytesPerPixel;
+ }
+
+ src += _surface->pitch - lineSize;
+ dst += screen->pitch - lineSize;
+ }
+}
+
+void Surface::scaleTransparentCopy(const Common::Rect &srcRect, const Common::Rect &dstRect) const {
+ // I'm doing simple linear scaling here
+ // dstRect(x, y) = srcRect(x * srcW / dstW, y * srcH / dstH);
+
+ Graphics::Surface *screen = ((PegasusEngine *)g_engine)->_gfx->getCurSurface();
+
+ int srcW = srcRect.width();
+ int srcH = srcRect.height();
+ int dstW = dstRect.width();
+ int dstH = dstRect.height();
+
+ for (int y = 0; y < dstH; y++) {
+ for (int x = 0; x < dstW; x++) {
+ if (g_system->getScreenFormat().bytesPerPixel == 2) {
+ uint16 color = READ_UINT16((byte *)_surface->getBasePtr(
+ x * srcW / dstW + srcRect.left,
+ y * srcH / dstH + srcRect.top));
+ if (!isTransparent(color))
+ WRITE_UINT16((byte *)screen->getBasePtr(x + dstRect.left, y + dstRect.top), color);
+ } else if (g_system->getScreenFormat().bytesPerPixel == 4) {
+ uint32 color = READ_UINT32((byte *)_surface->getBasePtr(
+ x * srcW / dstW + srcRect.left,
+ y * srcH / dstH + srcRect.top));
+ if (!isTransparent(color))
+ WRITE_UINT32((byte *)screen->getBasePtr(x + dstRect.left, y + dstRect.top), color);
+ }
+ }
+ }
+}
+
+void Surface::scaleTransparentCopyGlow(const Common::Rect &srcRect, const Common::Rect &dstRect) const {
+ // This is the same as scaleTransparentCopy(), but turns the red value of each
+ // pixel all the way up.
+
+ Graphics::Surface *screen = ((PegasusEngine *)g_engine)->_gfx->getCurSurface();
+
+ int srcW = srcRect.width();
+ int srcH = srcRect.height();
+ int dstW = dstRect.width();
+ int dstH = dstRect.height();
+
+ for (int y = 0; y < dstH; y++) {
+ for (int x = 0; x < dstW; x++) {
+ if (g_system->getScreenFormat().bytesPerPixel == 2) {
+ uint16 color = READ_UINT16((byte *)_surface->getBasePtr(
+ x * srcW / dstW + srcRect.left,
+ y * srcH / dstH + srcRect.top));
+ if (!isTransparent(color))
+ WRITE_UINT16((byte *)screen->getBasePtr(x + dstRect.left, y + dstRect.top), getGlowColor(color));
+ } else if (g_system->getScreenFormat().bytesPerPixel == 4) {
+ uint32 color = READ_UINT32((byte *)_surface->getBasePtr(
+ x * srcW / dstW + srcRect.left,
+ y * srcH / dstH + srcRect.top));
+ if (!isTransparent(color))
+ WRITE_UINT32((byte *)screen->getBasePtr(x + dstRect.left, y + dstRect.top), getGlowColor(color));
+ }
+ }
+ }
+}
+
+uint32 Surface::getGlowColor(uint32 color) const {
+ // Can't just 'or' it on like the original did :P
+ byte r, g, b;
+ g_system->getScreenFormat().colorToRGB(color, r, g, b);
+ return g_system->getScreenFormat().RGBToColor(0xff, g, b);
+}
+
+bool Surface::isTransparent(uint32 color) const {
+ // HACK: Seems we're truncating some color data somewhere...
+ uint32 transColor1 = g_system->getScreenFormat().RGBToColor(0xff, 0xff, 0xff);
+ uint32 transColor2 = g_system->getScreenFormat().RGBToColor(0xf8, 0xf8, 0xf8);
+
+ return color == transColor1 || color == transColor2;
+}
+
+PixelImage::PixelImage() {
+ _transparent = false;
+}
+
+void PixelImage::drawImage(const Common::Rect &sourceBounds, const Common::Rect &destBounds) {
+ if (!isSurfaceValid())
+ return;
+
+ // Draw from sourceBounds to destBounds based on _transparent
+ if (_transparent)
+ copyToCurrentPortTransparent(sourceBounds, destBounds);
+ else
+ copyToCurrentPort(sourceBounds, destBounds);
+}
+
+void Frame::initFromPICTFile(const Common::String &fileName, bool transparent) {
+ getImageFromPICTFile(fileName);
+ _transparent = transparent;
+}
+
+void Frame::initFromPICTResource(Common::MacResManager *resFork, uint16 id, bool transparent) {
+ getImageFromPICTResource(resFork, id);
+ _transparent = transparent;
+}
+
+void Frame::initFromMovieFrame(Video::VideoDecoder *video, TimeValue time, bool transparent) {
+ getImageFromMovieFrame(video, time);
+ _transparent = transparent;
+}
+
+void Picture::draw(const Common::Rect &r) {
+ Common::Rect surfaceBounds;
+ getSurfaceBounds(surfaceBounds);
+ Common::Rect r1 = r;
+
+ Common::Rect bounds;
+ getBounds(bounds);
+ surfaceBounds.moveTo(bounds.left, bounds.top);
+ r1 = r1.findIntersectingRect(surfaceBounds);
+ getSurfaceBounds(surfaceBounds);
+
+ Common::Rect r2 = r1;
+ r2.translate(surfaceBounds.left - bounds.left, surfaceBounds.top - bounds.top);
+ drawImage(r2, r1);
+}
+
+void Picture::initFromPICTFile(const Common::String &fileName, bool transparent) {
+ Frame::initFromPICTFile(fileName, transparent);
+
+ Common::Rect surfaceBounds;
+ getSurfaceBounds(surfaceBounds);
+ sizeElement(surfaceBounds.width(), surfaceBounds.height());
+}
+
+void Picture::initFromPICTResource(Common::MacResManager *resFork, uint16 id, bool transparent) {
+ Frame::initFromPICTResource(resFork, id, transparent);
+
+ Common::Rect surfaceBounds;
+ getSurfaceBounds(surfaceBounds);
+ sizeElement(surfaceBounds.width(), surfaceBounds.height());
+}
+
+void Picture::initFromMovieFrame(Video::VideoDecoder *video, TimeValue time, bool transparent) {
+ Frame::initFromMovieFrame(video, time, transparent);
+
+ Common::Rect surfaceBounds;
+ getSurfaceBounds(surfaceBounds);
+ sizeElement(surfaceBounds.width(), surfaceBounds.height());
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/surface.h b/engines/pegasus/surface.h
new file mode 100644
index 0000000000..47e3ef538c
--- /dev/null
+++ b/engines/pegasus/surface.h
@@ -0,0 +1,140 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_SURFACE_H
+#define PEGASUS_SURFACE_H
+
+#include "common/rect.h"
+#include "common/str.h"
+
+#include "pegasus/elements.h"
+#include "pegasus/types.h"
+
+namespace Common {
+ class MacResManager;
+}
+
+namespace Graphics {
+ struct Surface;
+}
+
+namespace Video {
+ class VideoDecoder;
+}
+
+namespace Pegasus {
+
+// Surface bounds are always normalized.
+
+class Surface {
+public:
+ Surface();
+ virtual ~Surface();
+
+ virtual void allocateSurface(const Common::Rect &);
+ virtual void deallocateSurface();
+ virtual void shareSurface(Surface *surface);
+ bool isSurfaceValid() const { return _surface != 0; }
+
+ Graphics::Surface *getSurface() const { return _surface; }
+ void getSurfaceBounds(Common::Rect &r) { r = _bounds; }
+
+ // None of the copyToCurrentPort* functions do any sanity checks.
+ // It's up to clients to make sure that the Surface is valid.
+ void copyToCurrentPort() const;
+ void copyToCurrentPortTransparent() const;
+ void copyToCurrentPort(const Common::Rect &) const;
+ void copyToCurrentPortTransparent(const Common::Rect &) const;
+ void copyToCurrentPort(const Common::Rect &, const Common::Rect &) const;
+ void copyToCurrentPortTransparent(const Common::Rect &, const Common::Rect &) const;
+ void copyToCurrentPortMasked(const Common::Rect &, const Common::Rect &, const Surface *) const;
+ void copyToCurrentPortTransparentGlow(const Common::Rect &, const Common::Rect &) const;
+ void scaleTransparentCopy(const Common::Rect &, const Common::Rect &) const;
+ void scaleTransparentCopyGlow(const Common::Rect &, const Common::Rect &) const;
+
+ virtual void getImageFromPICTFile(const Common::String &fileName);
+ virtual void getImageFromPICTResource(Common::MacResManager *resFork, uint16 id);
+ virtual void getImageFromMovieFrame(Video::VideoDecoder *, TimeValue);
+
+protected:
+ bool _ownsSurface;
+ Graphics::Surface *_surface;
+ Common::Rect _bounds;
+
+private:
+ bool getImageFromPICTStream(Common::SeekableReadStream *stream);
+
+ uint32 getGlowColor(uint32 color) const;
+ bool isTransparent(uint32 color) const;
+};
+
+class PixelImage : public Surface {
+public:
+ PixelImage();
+ virtual ~PixelImage() {}
+
+ void drawImage(const Common::Rect &, const Common::Rect &);
+
+protected:
+ virtual void setTransparent(bool transparent) { _transparent = transparent; }
+
+ bool _transparent;
+};
+
+class Frame : public PixelImage {
+public:
+ Frame() {}
+ virtual ~Frame() {}
+
+ 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::VideoDecoder *, TimeValue, bool transparent = false);
+};
+
+class SpriteFrame : public Frame {
+friend class Sprite;
+public:
+ SpriteFrame() { _referenceCount = 0; }
+ virtual ~SpriteFrame() {}
+
+protected:
+ uint32 _referenceCount;
+};
+
+class Picture : public DisplayElement, public Frame {
+public:
+ Picture(const DisplayElementID id) : DisplayElement(id) {}
+ virtual ~Picture() {}
+
+ 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::VideoDecoder *, TimeValue, bool transparent = false);
+
+ virtual void draw(const Common::Rect &);
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/timers.cpp b/engines/pegasus/timers.cpp
new file mode 100644
index 0000000000..3b875038cc
--- /dev/null
+++ b/engines/pegasus/timers.cpp
@@ -0,0 +1,429 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "pegasus/pegasus.h"
+#include "pegasus/notification.h"
+#include "pegasus/timers.h"
+
+namespace Pegasus {
+
+Idler::Idler() {
+ _isIdling = false;
+ _nextIdler = 0;
+ _prevIdler = 0;
+}
+
+Idler::~Idler() {
+ stopIdling();
+}
+
+void Idler::startIdling() {
+ if (!isIdling()) {
+ ((PegasusEngine *)g_engine)->addIdler(this);
+ _isIdling = true;
+ }
+}
+
+void Idler::stopIdling() {
+ if (isIdling()) {
+ ((PegasusEngine *)g_engine)->removeIdler(this);
+ _isIdling = false;
+ }
+}
+
+TimeBase::TimeBase(const TimeScale preferredScale) {
+ _preferredScale = preferredScale;
+ _callBackList = 0;
+ _paused = false;
+ _flags = 0;
+ _lastMillis = 0;
+ _time = 0;
+ _rate = 0;
+ _startTime = 0;
+ _startScale = 1;
+ _stopTime = 0xffffffff;
+ _stopScale = 1;
+ _master = 0;
+ _pausedRate = 0;
+ _pauseStart = 0;
+
+ ((PegasusEngine *)g_engine)->addTimeBase(this);
+}
+
+TimeBase::~TimeBase() {
+ if (_master)
+ _master->_slaves.remove(this);
+
+ ((PegasusEngine *)g_engine)->removeTimeBase(this);
+ disposeAllCallBacks();
+
+ // TODO: Remove slaves? Make them remove themselves?
+}
+
+void TimeBase::setTime(const TimeValue time, const TimeScale scale) {
+ _time = Common::Rational(time, (scale == 0) ? _preferredScale : scale);
+ _lastMillis = 0;
+}
+
+TimeValue TimeBase::getTime(const TimeScale scale) {
+ return _time.getNumerator() * ((scale == 0) ? _preferredScale : scale) / _time.getDenominator();
+}
+
+void TimeBase::setRate(const Common::Rational rate) {
+ _rate = rate;
+
+ if (_rate == 0)
+ _paused = false;
+}
+
+Common::Rational TimeBase::getEffectiveRate() const {
+ return _rate * ((_master == 0) ? 1 : _master->getEffectiveRate());
+}
+
+void TimeBase::start() {
+ if (_paused)
+ _pausedRate = 1;
+ else
+ setRate(1);
+}
+
+void TimeBase::stop() {
+ setRate(0);
+ _paused = false;
+}
+
+void TimeBase::pause() {
+ if (isRunning() && !_paused) {
+ _pausedRate = getRate();
+ stop();
+ _paused = true;
+ _pauseStart = g_system->getMillis();
+ }
+}
+
+void TimeBase::resume() {
+ if (_paused) {
+ setRate(_pausedRate);
+ _paused = false;
+
+ if (isRunning())
+ _lastMillis += g_system->getMillis() - _pauseStart;
+ }
+}
+
+bool TimeBase::isRunning() {
+ if (_paused && _pausedRate != 0)
+ return true;
+
+ Common::Rational rate = getRate();
+
+ if (rate == 0)
+ return false;
+
+ if (getFlags() & kLoopTimeBase)
+ return true;
+
+ if (rate > 0)
+ return getTime() != getStop();
+
+ return getTime() != getStart();
+}
+
+void TimeBase::setStart(const TimeValue startTime, const TimeScale scale) {
+ _startTime = startTime;
+ _startScale = (scale == 0) ? _preferredScale : scale;
+}
+
+TimeValue TimeBase::getStart(const TimeScale scale) const {
+ if (scale)
+ return _startTime * scale / _startScale;
+
+ return _startTime * _preferredScale / _startScale;
+}
+
+void TimeBase::setStop(const TimeValue stopTime, const TimeScale scale) {
+ _stopTime = stopTime;
+ _stopScale = (scale == 0) ? _preferredScale : scale;
+}
+
+TimeValue TimeBase::getStop(const TimeScale scale) const {
+ if (scale)
+ return _stopTime * scale / _stopScale;
+
+ return _stopTime * _preferredScale / _stopScale;
+}
+
+void TimeBase::setSegment(const TimeValue startTime, const TimeValue stopTime, const TimeScale scale) {
+ setStart(startTime, scale);
+ setStop(stopTime, scale);
+}
+
+void TimeBase::getSegment(TimeValue &startTime, TimeValue &stopTime, const TimeScale scale) const {
+ startTime = getStart(scale);
+ stopTime = getStop(scale);
+}
+
+TimeValue TimeBase::getDuration(const TimeScale scale) const {
+ TimeValue startTime, stopTime;
+ getSegment(startTime, stopTime, scale);
+ return stopTime - startTime;
+}
+
+void TimeBase::setMasterTimeBase(TimeBase *tb) {
+ // TODO: We're just ignoring the master (except for effective rate)
+ // for now to simplify things
+ if (_master)
+ _master->_slaves.remove(this);
+
+ _master = tb;
+
+ if (_master)
+ _master->_slaves.push_back(this);
+}
+
+void TimeBase::updateTime() {
+ if (_lastMillis == 0) {
+ _lastMillis = g_system->getMillis();
+ } else {
+ uint32 curTime = g_system->getMillis();
+ if (_lastMillis == curTime) // No change
+ return;
+
+ _time += Common::Rational(curTime - _lastMillis, 1000) * getEffectiveRate();
+ _lastMillis = curTime;
+ }
+}
+
+void TimeBase::checkCallBacks() {
+ // Nothing to do if we're paused or not running
+ if (_paused || !isRunning())
+ return;
+
+ Common::Rational startTime = Common::Rational(_startTime, _startScale);
+ Common::Rational stopTime = Common::Rational(_stopTime, _stopScale);
+
+ // First step: update the times
+ updateTime();
+
+ // Clip time to the boundaries
+ if (_time >= stopTime)
+ _time = stopTime;
+ else if (_time <= startTime)
+ _time = startTime;
+
+ // TODO: Update the slaves?
+
+ Common::Rational time = Common::Rational(getTime(), getScale());
+
+ // Check if we've triggered any callbacks
+ for (TimeBaseCallBack *runner = _callBackList; runner != 0; runner = runner->_nextCallBack) {
+ if (runner->_hasBeenTriggered)
+ continue;
+
+ if (runner->_type == kCallBackAtTime && runner->_trigger == kTriggerTimeFwd) {
+ if (getTime() >= (runner->_param2 * _preferredScale / runner->_param3) && getRate() > 0) {
+ uint param2 = runner->_param2, param3 = runner->_param3;
+ runner->callBack();
+ // HACK: Only stop future time forward callbacks if the parameters have not been changed
+ // This fixes striding callbacks. Since only striding callbacks do this kind of
+ // craziness, I'm not too worried about this.
+ runner->_hasBeenTriggered = (runner->_param2 == param2 && runner->_param3 == param3);
+ }
+ } else if (runner->_type == kCallBackAtExtremes) {
+ if (runner->_trigger == kTriggerAtStop) {
+ if (time == stopTime) {
+ runner->callBack();
+ runner->_hasBeenTriggered = true;
+ }
+ } else if (runner->_trigger == kTriggerAtStart) {
+ if (time == startTime) {
+ runner->callBack();
+ runner->_hasBeenTriggered = true;
+ }
+ }
+ }
+ }
+
+ if (getFlags() & kLoopTimeBase) {
+ // Loop if necessary
+ if (getRate() < 0 && time == startTime)
+ setTime(_stopTime, _stopScale);
+ else if (getRate() > 0 && time == stopTime)
+ setTime(_startTime, _startScale);
+ } else {
+ // Stop at the end
+ if ((getRate() > 0 && time == stopTime) || (getRate() < 0 && time == startTime))
+ stop();
+ }
+}
+
+// Protected functions only called by TimeBaseCallBack.
+
+void TimeBase::addCallBack(TimeBaseCallBack *callBack) {
+ callBack->_nextCallBack = _callBackList;
+ _callBackList = callBack;
+}
+
+void TimeBase::removeCallBack(TimeBaseCallBack *callBack) {
+ if (_callBackList == callBack) {
+ _callBackList = callBack->_nextCallBack;
+ } else {
+ TimeBaseCallBack *runner, *prevRunner;
+
+ for (runner = _callBackList->_nextCallBack, prevRunner = _callBackList; runner != callBack; prevRunner = runner, runner = runner->_nextCallBack)
+ ;
+
+ prevRunner->_nextCallBack = runner->_nextCallBack;
+ }
+
+ callBack->_nextCallBack = 0;
+}
+
+void TimeBase::disposeAllCallBacks() {
+ TimeBaseCallBack *nextRunner;
+
+ for (TimeBaseCallBack *runner = _callBackList; runner != 0; runner = nextRunner) {
+ nextRunner = runner->_nextCallBack;
+ runner->disposeCallBack();
+ runner->_nextCallBack = 0;
+ }
+
+ _callBackList = 0;
+}
+
+TimeBaseCallBack::TimeBaseCallBack() {
+ _timeBase = 0;
+ _nextCallBack = 0;
+ _trigger = kTriggerNone;
+ _type = kCallBackNone;
+ _hasBeenTriggered = false;
+}
+
+TimeBaseCallBack::~TimeBaseCallBack() {
+ releaseCallBack();
+}
+
+void TimeBaseCallBack::initCallBack(TimeBase *tb, CallBackType type) {
+ releaseCallBack();
+ _timeBase = tb;
+ _timeBase->addCallBack(this);
+ _type = type;
+}
+
+void TimeBaseCallBack::releaseCallBack() {
+ if (_timeBase)
+ _timeBase->removeCallBack(this);
+ disposeCallBack();
+}
+
+void TimeBaseCallBack::disposeCallBack() {
+ _timeBase = 0;
+ _hasBeenTriggered = false;
+}
+
+void TimeBaseCallBack::scheduleCallBack(CallBackTrigger trigger, uint32 param2, uint32 param3) {
+ // TODO: Rename param2/param3?
+ _trigger = trigger;
+ _param2 = param2;
+ _param3 = param3;
+ _hasBeenTriggered = false;
+}
+
+void TimeBaseCallBack::cancelCallBack() {
+ _trigger = kTriggerNone;
+ _hasBeenTriggered = false;
+}
+
+IdlerTimeBase::IdlerTimeBase() {
+ _lastTime = 0xffffffff;
+ startIdling();
+}
+
+void IdlerTimeBase::useIdleTime() {
+ uint32 currentTime = getTime();
+ if (currentTime != _lastTime) {
+ _lastTime = currentTime;
+ timeChanged(_lastTime);
+ }
+}
+
+NotificationCallBack::NotificationCallBack() {
+ _callBackFlag = 0;
+ _notifier = 0;
+}
+
+void NotificationCallBack::callBack() {
+ if (_notifier)
+ _notifier->setNotificationFlags(_callBackFlag, _callBackFlag);
+}
+
+static const NotificationFlags kFuseExpiredFlag = 1;
+
+Fuse::Fuse() : _fuseNotification(0, (NotificationManager *)((PegasusEngine *)g_engine)) {
+ _fuseNotification.notifyMe(this, kFuseExpiredFlag, kFuseExpiredFlag);
+ _fuseCallBack.setNotification(&_fuseNotification);
+ _fuseCallBack.initCallBack(&_fuseTimer, kCallBackAtExtremes);
+ _fuseCallBack.setCallBackFlag(kFuseExpiredFlag);
+}
+
+void Fuse::primeFuse(const TimeValue frequency, const TimeScale scale) {
+ stopFuse();
+ _fuseTimer.setScale(scale);
+ _fuseTimer.setSegment(0, frequency);
+ _fuseTimer.setTime(0);
+}
+
+void Fuse::lightFuse() {
+ if (!_fuseTimer.isRunning()) {
+ _fuseCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
+ _fuseTimer.start();
+ }
+}
+
+void Fuse::stopFuse() {
+ _fuseTimer.stop();
+ _fuseCallBack.cancelCallBack();
+ // Make sure the fuse has not triggered but not been caught yet...
+ _fuseNotification.setNotificationFlags(0, 0xffffffff);
+}
+
+void Fuse::advanceFuse(const TimeValue time) {
+ if (_fuseTimer.isRunning()) {
+ _fuseTimer.stop();
+ _fuseTimer.setTime(_fuseTimer.getTime() + time);
+ _fuseTimer.start();
+ }
+}
+
+TimeValue Fuse::getTimeRemaining() {
+ return _fuseTimer.getStop() - _fuseTimer.getTime();
+}
+
+void Fuse::receiveNotification(Notification *, const NotificationFlags) {
+ stopFuse();
+ invokeAction();
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/timers.h b/engines/pegasus/timers.h
new file mode 100644
index 0000000000..bcdca6e860
--- /dev/null
+++ b/engines/pegasus/timers.h
@@ -0,0 +1,260 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_TIMERS_H
+#define PEGASUS_TIMERS_H
+
+#include "common/list.h"
+#include "common/rational.h"
+#include "common/func.h"
+
+#include "pegasus/constants.h"
+#include "pegasus/notification.h"
+#include "pegasus/util.h"
+
+namespace Pegasus {
+
+class Idler {
+friend class PegasusEngine;
+
+public:
+ Idler();
+ virtual ~Idler();
+
+ virtual void startIdling();
+ virtual void stopIdling();
+ bool isIdling() const { return _isIdling; }
+
+protected:
+ virtual void useIdleTime() {}
+
+ bool _isIdling;
+ Idler *_nextIdler, *_prevIdler;
+};
+
+enum {
+ kLoopTimeBase = 1,
+ kPalindromeLoopTimeBase = 2,
+ kMaintainTimeBaseZero = 4
+};
+
+class TimeBaseCallBack;
+
+class TimeBase {
+friend class TimeBaseCallBack;
+public:
+ TimeBase(const TimeScale = kDefaultTimeScale);
+ virtual ~TimeBase();
+
+ virtual void setTime(const TimeValue, const TimeScale = 0);
+ virtual TimeValue getTime(const TimeScale = 0);
+
+ virtual void setScale(const TimeScale scale) { _preferredScale = scale; }
+ virtual TimeScale getScale() const { return _preferredScale; }
+
+ virtual void setRate(const Common::Rational);
+ virtual Common::Rational getRate() const { return _rate; }
+
+ virtual void start();
+ virtual void stop();
+ virtual bool isRunning();
+
+ virtual void pause();
+ virtual void resume();
+ bool isPaused() const { return _paused; }
+
+ virtual void setFlags(const uint32 flags) { _flags = flags; }
+ virtual uint32 getFlags() const { return _flags; }
+
+ virtual void setStart(const TimeValue, const TimeScale = 0);
+ virtual TimeValue getStart(const TimeScale = 0) const;
+
+ virtual void setStop(const TimeValue, const TimeScale = 0);
+ virtual TimeValue getStop(const TimeScale = 0) const;
+
+ virtual void setSegment(const TimeValue, const TimeValue, const TimeScale = 0);
+ virtual void getSegment(TimeValue&, TimeValue&, const TimeScale = 0) const;
+
+ virtual TimeValue getDuration(const TimeScale = 0) const;
+
+ virtual void setMasterTimeBase(TimeBase *timeBase);
+
+ void disposeAllCallBacks();
+
+ // ScummVM's API additions (to replace the need for actual timers)
+ virtual void checkCallBacks();
+
+protected:
+ void addCallBack(TimeBaseCallBack *);
+ void removeCallBack(TimeBaseCallBack *);
+ virtual void updateTime();
+
+ TimeBase *_master;
+ TimeScale _preferredScale;
+ TimeBaseCallBack *_callBackList;
+ Common::Rational _rate, _pausedRate;
+ bool _paused;
+ uint32 _startTime, _startScale;
+ uint32 _stopTime, _stopScale;
+ uint32 _flags;
+
+ Common::Rational _time;
+ uint32 _lastMillis, _pauseStart;
+
+private:
+ Common::Rational getEffectiveRate() const;
+
+ Common::List<TimeBase *> _slaves;
+};
+
+// Type passed to initCallBack()
+enum CallBackType {
+ kCallBackNone = 0,
+ kCallBackAtTime = 1,
+ kCallBackAtExtremes = 4
+};
+
+// Trigger passed to scheduleCallBack()
+enum CallBackTrigger {
+ kTriggerNone = 0,
+
+ // AtTime flags
+ kTriggerTimeFwd = 1,
+
+ // AtExtremes flags
+ kTriggerAtStart = 1,
+ kTriggerAtStop = 2
+};
+
+class TimeBaseCallBack {
+friend class TimeBase;
+
+public:
+ TimeBaseCallBack();
+ virtual ~TimeBaseCallBack();
+
+ void initCallBack(TimeBase *, CallBackType type);
+
+ void releaseCallBack();
+
+ void scheduleCallBack(CallBackTrigger trigger, uint32 param2, uint32 param3);
+ void cancelCallBack();
+
+protected:
+ virtual void callBack() = 0;
+
+ TimeBase *_timeBase;
+
+ // Owned and operated by TimeBase;
+ TimeBaseCallBack *_nextCallBack;
+
+ // Our storage of the QuickTime timer crap
+ CallBackType _type;
+ CallBackTrigger _trigger;
+ uint32 _param2, _param3;
+ bool _hasBeenTriggered;
+
+private:
+ void disposeCallBack();
+};
+
+class IdlerTimeBase : public Idler, public TimeBase {
+public:
+ IdlerTimeBase();
+ virtual ~IdlerTimeBase() { stopIdling(); }
+
+ TimeValue getLastTime() const { return _lastTime; }
+
+protected:
+ virtual void useIdleTime();
+ virtual void timeChanged(const TimeValue) {}
+
+ TimeValue _lastTime;
+
+};
+
+class NotificationCallBack : public TimeBaseCallBack {
+public:
+ NotificationCallBack();
+ virtual ~NotificationCallBack() {}
+
+ void setNotification(Notification *notifier) { _notifier = notifier; }
+
+ void setCallBackFlag(const NotificationFlags flag) { _callBackFlag = flag; }
+ NotificationFlags getCallBackFlag() const { return _callBackFlag; }
+
+protected:
+ void callBack();
+
+ Notification *_notifier;
+ NotificationFlags _callBackFlag;
+};
+
+class DynamicElement : public TimeBase {
+public:
+ TimeValue percentSeconds(const uint32 percent) { return getScale() * percent / 100; }
+};
+
+class Fuse : private NotificationReceiver {
+public:
+ Fuse();
+ virtual ~Fuse() {}
+
+ void primeFuse(const TimeValue, const TimeScale = 1); // An appropriately named function :P
+ void lightFuse();
+ void stopFuse();
+ bool isFuseLit() { return _fuseTimer.isRunning() || _fuseTimer.isPaused(); }
+ void advanceFuse(const TimeValue);
+ TimeValue getTimeRemaining();
+ TimeScale getFuseScale() { return _fuseTimer.getScale(); }
+
+ void pauseFuse() { _fuseTimer.pause(); }
+ void resumeFuse() { _fuseTimer.resume(); }
+ bool isFusePaused() { return _fuseTimer.isPaused(); }
+
+protected:
+ virtual void receiveNotification(Notification *, const NotificationFlags);
+ virtual void invokeAction() {}
+
+ TimeBase _fuseTimer;
+ NotificationCallBack _fuseCallBack;
+ Notification _fuseNotification;
+};
+
+class FuseFunction : public Fuse {
+public:
+ FuseFunction() : _functor(0) {}
+ virtual ~FuseFunction() { delete _functor; }
+
+ void setFunctor(Common::Functor0<void> *functor) { delete _functor; _functor = functor; }
+protected:
+ virtual void invokeAction() { if (_functor && _functor->isValid()) (*_functor)(); }
+
+ Common::Functor0<void> *_functor;
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/transition.cpp b/engines/pegasus/transition.cpp
new file mode 100644
index 0000000000..1ae212df85
--- /dev/null
+++ b/engines/pegasus/transition.cpp
@@ -0,0 +1,200 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/system.h"
+#include "graphics/surface.h"
+
+#include "pegasus/transition.h"
+
+namespace Pegasus {
+
+ScreenFader::ScreenFader() {
+ _isBlack = true;
+ // Initially, assume screens are on at full brightness.
+ Fader::setFaderValue(100);
+ _screen = new Graphics::Surface();
+}
+
+ScreenFader::~ScreenFader() {
+ _screen->free();
+ delete _screen;
+}
+
+void ScreenFader::doFadeOutSync(const TimeValue duration, const TimeValue scale, bool isBlack) {
+ _isBlack = isBlack;
+ _screen->copyFrom(*g_system->lockScreen());
+ g_system->unlockScreen();
+
+ FaderMoveSpec spec;
+ spec.makeTwoKnotFaderSpec(scale, 0, getFaderValue(), duration, 0);
+ startFaderSync(spec);
+
+ _screen->free();
+}
+
+void ScreenFader::doFadeInSync(const TimeValue duration, const TimeValue scale, bool isBlack) {
+ _isBlack = isBlack;
+ _screen->copyFrom(*g_system->lockScreen());
+ g_system->unlockScreen();
+
+ FaderMoveSpec spec;
+ spec.makeTwoKnotFaderSpec(scale, 0, getFaderValue(), duration, 100);
+ startFaderSync(spec);
+
+ _screen->free();
+}
+
+void ScreenFader::setFaderValue(const int32 value) {
+ if (value != getFaderValue()) {
+ Fader::setFaderValue(value);
+
+ if (_screen->pixels) {
+ // The original game does a gamma fade here using the Mac API. In order to do
+ // that, it would require an immense amount of CPU processing. This does a
+ // linear fade instead, which looks fairly well, IMO.
+ Graphics::Surface *screen = g_system->lockScreen();
+
+ for (uint y = 0; y < _screen->h; y++) {
+ for (uint x = 0; x < _screen->w; x++) {
+ if (_screen->format.bytesPerPixel == 2)
+ WRITE_UINT16(screen->getBasePtr(x, y), fadePixel(READ_UINT16(_screen->getBasePtr(x, y)), value));
+ else
+ WRITE_UINT32(screen->getBasePtr(x, y), fadePixel(READ_UINT32(_screen->getBasePtr(x, y)), value));
+ }
+ }
+
+ g_system->unlockScreen();
+ g_system->updateScreen();
+ }
+ }
+}
+
+static inline byte fadeComponent(byte comp, int32 percent) {
+ return comp * percent / 100;
+}
+
+uint32 ScreenFader::fadePixel(uint32 color, int32 percent) const {
+ byte r, g, b;
+ g_system->getScreenFormat().colorToRGB(color, r, g, b);
+
+ if (_isBlack) {
+ r = fadeComponent(r, percent);
+ g = fadeComponent(g, percent);
+ b = fadeComponent(b, percent);
+ } else {
+ r = 0xFF - fadeComponent(0xFF - r, percent);
+ g = 0xFF - fadeComponent(0xFF - g, percent);
+ b = 0xFF - fadeComponent(0xFF - b, percent);
+ }
+
+ return g_system->getScreenFormat().RGBToColor(r, g, b);
+}
+
+Transition::Transition(const DisplayElementID id) : FaderAnimation(id) {
+ _outPicture = 0;
+ _inPicture = 0;
+}
+
+void Transition::setBounds(const Common::Rect &r) {
+ FaderAnimation::setBounds(r);
+ _boundsWidth = _bounds.width();
+ _boundsHeight = _bounds.height();
+}
+
+void Transition::setInAndOutElements(DisplayElement *inElement, DisplayElement *outElement) {
+ _inPicture = inElement;
+ _outPicture = outElement;
+
+ Common::Rect r;
+
+ if (_outPicture)
+ _outPicture->getBounds(r);
+ else if (_inPicture)
+ _inPicture->getBounds(r);
+
+ setBounds(r);
+}
+
+void Slide::draw(const Common::Rect &r) {
+ Common::Rect oldBounds, newBounds;
+
+ adjustSlideRects(oldBounds, newBounds);
+ drawElements(r, oldBounds, newBounds);
+}
+
+void Slide::adjustSlideRects(Common::Rect &oldBounds, Common::Rect &newBounds) {
+ oldBounds = _bounds;
+ newBounds = _bounds;
+}
+
+void Slide::drawElements(const Common::Rect &drawRect, const Common::Rect &oldBounds, const Common::Rect &newBounds) {
+ drawSlideElement(drawRect, oldBounds, _outPicture);
+ drawSlideElement(drawRect, newBounds, _inPicture);
+}
+
+void Slide::drawSlideElement(const Common::Rect &drawRect, const Common::Rect &oldBounds, DisplayElement *picture) {
+ if (picture && drawRect.intersects(oldBounds)) {
+ picture->moveElementTo(oldBounds.left, oldBounds.top);
+ picture->draw(drawRect.findIntersectingRect(oldBounds));
+ }
+}
+
+void Push::adjustSlideRects(Common::Rect &oldBounds, Common::Rect &newBounds) {
+ switch (_direction & kSlideHorizMask) {
+ case kSlideLeftMask:
+ newBounds.left = oldBounds.right = _bounds.right - pegasusRound(getFaderValue() * _boundsWidth, kTransitionRange);
+ newBounds.right = newBounds.left + _boundsWidth;
+ oldBounds.left = oldBounds.right - _boundsWidth;
+ break;
+ case kSlideRightMask:
+ oldBounds.left = newBounds.right = _bounds.left + pegasusRound(getFaderValue() * _boundsWidth, kTransitionRange);
+ oldBounds.right = oldBounds.left + _boundsWidth;
+ newBounds.left = newBounds.right - _boundsWidth;
+ break;
+ default:
+ newBounds.left = oldBounds.left = _bounds.left;
+ newBounds.right = oldBounds.right = _bounds.right;
+ break;
+ }
+
+ switch (_direction & kSlideVertMask) {
+ case kSlideDownMask:
+ oldBounds.top = newBounds.bottom = _bounds.top + pegasusRound(getFaderValue() * _boundsHeight, kTransitionRange);
+ oldBounds.bottom = oldBounds.top + _boundsHeight;
+ newBounds.top = newBounds.bottom - _boundsHeight;
+ break;
+ case kSlideUpMask:
+ newBounds.top = oldBounds.bottom = _bounds.bottom - pegasusRound(getFaderValue() * _boundsHeight, kTransitionRange);
+ newBounds.bottom = newBounds.top + _boundsHeight;
+ oldBounds.top = oldBounds.bottom - _boundsHeight;
+ break;
+ default:
+ newBounds.top = oldBounds.top = _bounds.top;
+ newBounds.bottom = oldBounds.bottom = _bounds.bottom;
+ break;
+ }
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/transition.h b/engines/pegasus/transition.h
new file mode 100644
index 0000000000..84241a2bd2
--- /dev/null
+++ b/engines/pegasus/transition.h
@@ -0,0 +1,108 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_TRANSITION_H
+#define PEGASUS_TRANSITION_H
+
+#include "pegasus/fader.h"
+
+namespace Graphics {
+struct Surface;
+}
+
+namespace Pegasus {
+
+class ScreenFader : public Fader {
+public:
+ ScreenFader();
+ virtual ~ScreenFader();
+
+ void doFadeOutSync(const TimeValue = kOneSecondPerThirtyTicks, const TimeScale = kThirtyTicksPerSecond, bool isBlack = true);
+ void doFadeInSync(const TimeValue = kHalfSecondPerThirtyTicks, const TimeScale = kThirtyTicksPerSecond, bool isBlack = true);
+
+ void setFaderValue(const int32);
+
+private:
+ bool _isBlack;
+ uint32 fadePixel(uint32 color, int32 percent) const;
+ Graphics::Surface *_screen;
+};
+
+// Transitions are faders that range over [0,1000], which makes their
+// "resolution" one tenth of a percent
+
+static const int kTransitionBottom = 0;
+static const int kTransitionTop = 1000;
+
+static const int kTransitionRange = kTransitionTop - kTransitionBottom;
+
+class Transition : public FaderAnimation {
+public:
+ Transition(const DisplayElementID id);
+ virtual ~Transition() {}
+
+ virtual void setBounds(const Common::Rect &);
+
+ virtual void setInAndOutElements(DisplayElement *, DisplayElement *);
+ DisplayElement *getInElement() { return _inPicture; }
+ DisplayElement *getOutElement() { return _outPicture; }
+
+protected:
+ DisplayElement *_outPicture;
+ DisplayElement *_inPicture;
+
+ CoordType _boundsWidth, _boundsHeight;
+};
+
+class Slide : public Transition {
+public:
+ Slide(const DisplayElementID id) : Transition(id) {}
+ virtual ~Slide() {}
+
+ virtual void setSlideDirection(SlideDirection dir) { _direction = dir; }
+ virtual void draw(const Common::Rect &);
+
+ virtual void setDirection(const SlideDirection dir) { _direction = dir; }
+
+protected:
+ virtual void adjustSlideRects(Common::Rect &, Common::Rect &);
+ virtual void drawElements(const Common::Rect &, const Common::Rect &, const Common::Rect &);
+ virtual void drawSlideElement(const Common::Rect &, const Common::Rect &, DisplayElement *);
+
+ SlideDirection _direction;
+};
+
+class Push : public Slide {
+public:
+ Push(const DisplayElementID id) : Slide(id) {}
+ virtual ~Push() {}
+
+protected:
+ virtual void adjustSlideRects(Common::Rect &, Common::Rect &);
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/types.h b/engines/pegasus/types.h
new file mode 100644
index 0000000000..64ab4e5bb2
--- /dev/null
+++ b/engines/pegasus/types.h
@@ -0,0 +1,161 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_TYPES_H
+#define PEGASUS_TYPES_H
+
+#include "common/scummsys.h"
+
+namespace Pegasus {
+
+// TODO: Probably all of these don't really need to be typedef'd...
+
+typedef int32 DisplayElementID;
+typedef int32 DisplayOrder;
+
+typedef int16 HotSpotID;
+typedef uint32 HotSpotFlags;
+
+typedef byte ButtonState;
+typedef uint32 InputBits;
+
+typedef int32 NotificationID;
+typedef uint32 NotificationFlags;
+
+// Mac types.
+typedef int16 ResIDType;
+typedef int16 CoordType;
+
+enum SlideDirection {
+ kSlideLeftMask = 1,
+ kSlideRightMask = kSlideLeftMask << 1,
+ kSlideUpMask = kSlideRightMask << 1 << 1,
+ kSlideDownMask = kSlideUpMask << 1,
+
+ kSlideHorizMask = kSlideLeftMask | kSlideRightMask,
+ kSlideVertMask = kSlideUpMask | kSlideDownMask,
+
+ kSlideUpLeftMask = kSlideLeftMask | kSlideUpMask,
+ kSlideUpRightMask = kSlideRightMask | kSlideUpMask,
+ kSlideDownLeftMask = kSlideLeftMask | kSlideDownMask,
+ kSlideDownRightMask = kSlideRightMask | kSlideDownMask
+};
+
+// ScummVM QuickTime/QuickDraw replacement types
+typedef uint TimeValue;
+typedef uint TimeScale;
+
+typedef int16 GameID;
+
+typedef GameID ItemID;
+typedef GameID ActorID;
+typedef GameID RoomID;
+typedef GameID NeighborhoodID;
+typedef byte AlternateID;
+typedef int8 HotSpotActivationID;
+
+typedef int16 WeightType;
+
+typedef byte DirectionConstant;
+typedef byte TurnDirection;
+
+// Meant to be room in low 16 bits and direction in high 16 bits.
+typedef uint32 RoomViewID;
+
+#define MakeRoomView(room, direction) (((RoomViewID) (room)) | (((RoomViewID) (direction)) << 16))
+
+typedef uint32 ExtraID;
+
+typedef int16 GameMode;
+
+typedef int16 WeightType;
+
+typedef int16 ItemState;
+
+typedef int8 DeathReason;
+
+typedef int32 GameMenuCommand;
+
+typedef int32 GameScoreType;
+
+typedef long CanMoveForwardReason;
+
+typedef long CanTurnReason;
+
+typedef long CanOpenDoorReason;
+
+enum InventoryResult {
+ kInventoryOK,
+ kTooMuchWeight,
+ kItemNotInInventory
+};
+
+typedef int32 InteractionID;
+
+typedef int32 AIConditionID;
+
+enum EnergyStage {
+ kStageNoStage,
+ kStageCasual, // more than 50% energy
+ kStageWorried, // more than 25% energy
+ kStageNervous, // more than 5% energy
+ kStagePanicStricken // less than 5% energy
+};
+
+enum NoradSubPrepState {
+ kSubNotPrepped,
+ kSubPrepped,
+ kSubDamaged
+};
+
+enum LowerClientSignature {
+ kNoClientSignature,
+ kInventorySignature,
+ kBiochipSignature,
+ kAISignature
+};
+
+enum LowerAreaSignature {
+ kLeftAreaSignature,
+ kMiddleAreaSignature,
+ kRightAreaSignature
+};
+
+enum AirQuality {
+ kAirQualityGood,
+ kAirQualityDirty,
+ kAirQualityVacuum
+};
+
+enum DragType {
+ kDragNoDrag,
+ kDragInventoryPickup,
+ kDragBiochipPickup,
+ kDragInventoryUse
+};
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/pegasus/util.cpp b/engines/pegasus/util.cpp
new file mode 100644
index 0000000000..59df610c33
--- /dev/null
+++ b/engines/pegasus/util.cpp
@@ -0,0 +1,77 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/random.h"
+#include "common/system.h"
+#include "common/util.h"
+
+#include "pegasus/util.h"
+
+namespace Pegasus {
+
+IDObject::IDObject(const int32 id) {
+ _objectID = id;
+}
+
+IDObject::~IDObject() {
+}
+
+int32 IDObject::getObjectID() const {
+ return _objectID;
+}
+
+int operator==(const IDObject &arg1, const IDObject &arg2) {
+ return arg1.getObjectID() == arg2.getObjectID();
+}
+
+int operator!=(const IDObject &arg1, const IDObject &arg2) {
+ return arg1.getObjectID() != arg2.getObjectID();
+}
+
+int32 pegasusRound(const int32 a, const int32 b) {
+ if (b < 0)
+ if (a < 0)
+ return -((a - (-b >> 1)) / -b);
+ else
+ return -((a + (-b >> 1)) / -b);
+ else
+ if (a < 0)
+ return (a - (b >> 1)) / b;
+ else
+ return (a + (b >> 1)) / b;
+}
+
+int32 linearInterp(const int32 start1, const int32 stop1, const int32 current1, const int32 start2, const int32 stop2) {
+ if (start2 == stop2)
+ return start2;
+ else
+ return start2 + pegasusRound((current1 - start1) * (stop2 - start2), (stop1 - start1));
+}
+
+uint32 tickCount() {
+ return g_system->getMillis() * 60 / 1000;
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/util.h b/engines/pegasus/util.h
new file mode 100644
index 0000000000..97ba1c20c3
--- /dev/null
+++ b/engines/pegasus/util.h
@@ -0,0 +1,117 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PEGASUS_UTIL_H
+#define PEGASUS_UTIL_H
+
+#include "common/stream.h"
+
+#include "pegasus/types.h"
+
+namespace Common {
+ class RandomSource;
+}
+
+namespace Pegasus {
+
+class IDObject {
+public:
+ IDObject(const int32 id);
+ ~IDObject();
+
+ int32 getObjectID() const;
+
+private:
+ int32 _objectID;
+};
+
+#define NUM_FLAGS (sizeof(Unit) * 8)
+#define BIT_INDEX_SHIFT (sizeof(Unit) + 2 - (sizeof(Unit)) / 3)
+#define BIT_INDEX_MASK (NUM_FLAGS - 1)
+
+template <typename Unit, uint32 kNumFlags>
+class FlagsArray {
+public:
+ FlagsArray() { clearAllFlags(); }
+ void clearAllFlags() { memset(_flags, 0, sizeof(_flags)); }
+ void setAllFlags() { memset(_flags, ~((Unit)0), sizeof(_flags)); }
+ void setFlag(uint32 flag) { _flags[flag >> BIT_INDEX_SHIFT] |= 1 << (flag & BIT_INDEX_MASK); }
+ void clearFlag(uint32 flag) { _flags[flag >> BIT_INDEX_SHIFT] &= ~(1 << (flag & BIT_INDEX_MASK)); }
+ void setFlag(uint32 flag, bool val) { if (val) setFlag(flag); else clearFlag(flag); }
+ bool getFlag(uint32 flag) { return (_flags[flag >> BIT_INDEX_SHIFT] & (1 << (flag & BIT_INDEX_MASK))) != 0; }
+ bool anyFlagSet() {
+ for (uint32 i = 0; i < sizeof(_flags); i++)
+ if (_flags[i] != 0)
+ return true;
+ return false;
+ }
+
+ void readFromStream(Common::ReadStream *stream) {
+ // Shortcut
+ if (sizeof(Unit) == 1) {
+ stream->read(_flags, sizeof(_flags));
+ return;
+ }
+
+ for (uint32 i = 0; i < ARRAYSIZE(_flags); i++) {
+ if (sizeof(Unit) == 2)
+ _flags[i] = stream->readUint16BE();
+ else /* if (sizeof(Unit) == 4) */
+ _flags[i] = stream->readUint32BE();
+ }
+ }
+
+ void writeToStream(Common::WriteStream *stream) {
+ // Shortcut
+ if (sizeof(Unit) == 1) {
+ stream->write(_flags, sizeof(_flags));
+ return;
+ }
+
+ for (uint32 i = 0; i < ARRAYSIZE(_flags); i++) {
+ if (sizeof(Unit) == 2)
+ stream->writeUint16BE(_flags[i]);
+ else /* if (sizeof(Unit) == 4) */
+ stream->writeUint32BE(_flags[i]);
+ }
+ }
+
+private:
+ Unit _flags[(kNumFlags - 1) / NUM_FLAGS + 1];
+};
+
+#undef NUM_FLAGS
+#undef BIT_INDEX_SHIFT
+#undef BIT_INDEX_MASK
+
+int32 linearInterp(const int32 start1, const int32 stop1, const int32 current1, const int32 start2, const int32 stop2);
+
+int32 pegasusRound(const int32 a, const int32 b);
+
+uint32 tickCount();
+
+} // End of namespace Pegasus
+
+#endif
diff --git a/engines/plugins_table.h b/engines/plugins_table.h
index c07dbc66a4..e5ac5efeb4 100644
--- a/engines/plugins_table.h
+++ b/engines/plugins_table.h
@@ -59,6 +59,9 @@ LINK_PLUGIN(MOHAWK)
#if PLUGIN_ENABLED_STATIC(PARALLACTION)
LINK_PLUGIN(PARALLACTION)
#endif
+#if PLUGIN_ENABLED_STATIC(PEGASUS)
+LINK_PLUGIN(PEGASUS)
+#endif
#if PLUGIN_ENABLED_STATIC(QUEEN)
LINK_PLUGIN(QUEEN)
#endif
diff --git a/engines/queen/display.cpp b/engines/queen/display.cpp
index 83dc1a9f60..cd9a1075fa 100644
--- a/engines/queen/display.cpp
+++ b/engines/queen/display.cpp
@@ -23,9 +23,13 @@
#include "common/system.h"
#include "common/events.h"
+#include "common/stream.h"
+#include "common/memstream.h"
#include "graphics/cursorman.h"
#include "graphics/palette.h"
+#include "graphics/surface.h"
+#include "graphics/decoders/pcx.h"
#include "queen/display.h"
#include "queen/input.h"
@@ -806,28 +810,22 @@ void Display::fill(uint8 *dstBuf, uint16 dstPitch, uint16 x, uint16 y, uint16 w,
}
void Display::decodePCX(const uint8 *src, uint32 srcSize, uint8 *dst, uint16 dstPitch, uint16 *w, uint16 *h, uint8 *pal, uint16 palStart, uint16 palEnd) {
- *w = READ_LE_UINT16(src + 12);
- *h = READ_LE_UINT16(src + 14);
+ Common::MemoryReadStream str(src, srcSize);
+
+ ::Graphics::PCXDecoder pcx;
+ if (!pcx.loadStream(str))
+ error("Error while reading PCX image");
+
+ const ::Graphics::Surface *pcxSurface = pcx.getSurface();
+ if (pcxSurface->format.bytesPerPixel != 1)
+ error("Invalid bytes per pixel in PCX surface (%d)", pcxSurface->format.bytesPerPixel);
+ *w = pcxSurface->w;
+ *h = pcxSurface->h;
assert(palStart <= palEnd && palEnd <= 256);
- const uint8 *palData = src + srcSize - 768;
- memcpy(pal, palData + palStart * 3, (palEnd - palStart) * 3);
-
- src += 128;
- for (int y = 0; y < *h; ++y) {
- uint8 *p = dst;
- while (p < dst + *w) {
- uint8 col = *src++;
- if ((col & 0xC0) == 0xC0) {
- uint8 len = col & 0x3F;
- memset(p, *src++, len);
- p += len;
- } else {
- *p++ = col;
- }
- }
- dst += dstPitch;
- }
+ memcpy(pal, pcx.getPalette() + palStart * 3, (palEnd - palStart) * 3);
+ for (uint16 y = 0; y < pcxSurface->h; y++)
+ memcpy(dst + y * dstPitch, pcxSurface->getBasePtr(0, y), pcxSurface->w);
}
void Display::decodeLBM(const uint8 *src, uint32 srcSize, uint8 *dst, uint16 dstPitch, uint16 *w, uint16 *h, uint8 *pal, uint16 palStart, uint16 palEnd, uint8 colorBase) {
diff --git a/engines/queen/queen.cpp b/engines/queen/queen.cpp
index f3b183c84f..c403536e22 100644
--- a/engines/queen/queen.cpp
+++ b/engines/queen/queen.cpp
@@ -113,12 +113,12 @@ int QueenMetaEngine::getMaximumSaveSlot() const { return 99; }
const ExtraGuiOptions QueenMetaEngine::getExtraGuiOptions(const Common::String &target) const {
Common::String guiOptions;
ExtraGuiOptions options;
-
+
if (target.empty()) {
options.push_back(queenExtraGuiOption);
return options;
}
-
+
if (ConfMan.hasKey("guioptions", target)) {
guiOptions = ConfMan.get("guioptions", target);
guiOptions = parseGameGUIOptions(guiOptions);
diff --git a/engines/saga/script.cpp b/engines/saga/script.cpp
index 96746b538c..3efc554cb3 100644
--- a/engines/saga/script.cpp
+++ b/engines/saga/script.cpp
@@ -948,7 +948,7 @@ void Script::opSpeak(SCRIPTOP_PARAMS) {
// scripts change to scene 5, but do not clear the cutaway that appears
// before Gorrister's speech starts, resulting in a deadlock. We do this
// manually here.
- if (_vm->getGameId() == GID_IHNM && _vm->_scene->currentChapterNumber() == 1 &&
+ if (_vm->getGameId() == GID_IHNM && _vm->_scene->currentChapterNumber() == 1 &&
_vm->_scene->currentSceneNumber() == 5 && _vm->_anim->hasCutaway()) {
_vm->_anim->returnFromCutaway();
}
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 1889d53480..5ae8245e5a 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -2882,17 +2882,17 @@ bool Console::cmdDisassemble(int argc, const char **argv) {
reg_t addr = NULL_REG;
if (!obj) {
- DebugPrintf("Not an object.");
+ DebugPrintf("Not an object.\n");
return true;
}
if (selectorId < 0) {
- DebugPrintf("Not a valid selector name.");
+ DebugPrintf("Not a valid selector name.\n");
return true;
}
if (lookupSelector(_engine->_gamestate->_segMan, objAddr, selectorId, NULL, &addr) != kSelectorMethod) {
- DebugPrintf("Not a method.");
+ DebugPrintf("Not a method.\n");
return true;
}
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp
index 58ac5f1fa6..ebad3d039a 100644
--- a/engines/sci/detection.cpp
+++ b/engines/sci/detection.cpp
@@ -103,6 +103,7 @@ static const PlainGameDescriptor s_sciGameTitles[] = {
{"pq4", "Police Quest IV: Open Season"}, // floppy is SCI2, CD SCI2.1
{"qfg4", "Quest for Glory IV: Shadows of Darkness"}, // floppy is SCI2, CD SCI2.1
// === SCI2.1 games ========================================================
+ {"chest", "Inside the Chest"}, // aka Behind the Developer's Shield
{"gk2", "The Beast Within: A Gabriel Knight Mystery"},
// TODO: Inside The Chest/Behind the Developer's Shield
{"kq7", "King's Quest VII: The Princeless Bride"},
@@ -132,6 +133,7 @@ static const GameIdStrToEnum s_gameIdStrToEnum[] = {
{ "astrochicken", GID_ASTROCHICKEN },
{ "camelot", GID_CAMELOT },
{ "castlebrain", GID_CASTLEBRAIN },
+ { "chest", GID_CHEST },
{ "christmas1988", GID_CHRISTMAS1988 },
{ "christmas1990", GID_CHRISTMAS1990 },
{ "christmas1992", GID_CHRISTMAS1992 },
@@ -208,6 +210,7 @@ struct OldNewIdTableEntry {
};
static const OldNewIdTableEntry s_oldNewTable[] = {
+ { "archive", "chest", SCI_VERSION_NONE },
{ "arthur", "camelot", SCI_VERSION_NONE },
{ "brain", "castlebrain", SCI_VERSION_1_MIDDLE }, // Amiga
{ "brain", "castlebrain", SCI_VERSION_1_LATE },
@@ -834,12 +837,16 @@ Common::Error SciEngine::saveGameState(int slot, const Common::String &desc) {
return Common::kNoError;
}
+// Before enabling the load option in the ScummVM menu, the main game loop must
+// have run at least once. When the game loop runs, kGameIsRestarting is invoked,
+// thus the speed throttler is initialized. Hopefully fixes bug #3565505.
+
bool SciEngine::canLoadGameStateCurrently() {
- return !_gamestate->executionStackBase;
+ return !_gamestate->executionStackBase && (_gamestate->_throttleLastTime > 0 || _gamestate->_throttleTrigger);
}
bool SciEngine::canSaveGameStateCurrently() {
- return !_gamestate->executionStackBase;
+ return !_gamestate->executionStackBase && (_gamestate->_throttleLastTime > 0 || _gamestate->_throttleTrigger);
}
} // End of namespace Sci
diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h
index b978f40aba..8e8b818854 100644
--- a/engines/sci/detection_tables.h
+++ b/engines/sci/detection_tables.h
@@ -129,6 +129,16 @@ 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) },
+ // Castle of Dr. Brain - English DOS 5.25" Floppy VGA 1.1 (from rnjacobs, bug report #3578286)
+ {"castlebrain", "", {
+ {"resource.map", 0, "a1deac2647ad09472c63656bfb950a4d", 2739},
+ {"resource.000", 0, "27ec5fa09cd12a7fd16e86d96a2ed245", 347071},
+ {"resource.001", 0, "13e81e1839cd7b216d2bb5615c1ca160", 356812},
+ {"resource.002", 0, "583d348c908f89f94f8551d7fe0a2eca", 991752},
+ {"resource.003", 0, "6c3d1bb26ad532c94046bc9ac49b5ff4", 728315},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Castle of Dr. Brain - English DOS Floppy 1.1
{"castlebrain", "", {
{"resource.map", 0, "f77728304c70017c54793eb6ca648174", 2745},
@@ -162,6 +172,16 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::ES_ESP, Common::kPlatformPC, ADGF_ADDENGLISH, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+#ifdef ENABLE_SCI32
+ // Inside the Chest / Behind the Developer's Shield
+ // SCI interpreter version 2.000.000
+ {"chest", "", {
+ {"resource.map", 0, "9dd015e79cac4f91e7de805448f39775", 1912},
+ {"resource.000", 0, "e4efcd042f86679dd4e1834bb3a38edb", 3770943},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformPC, ADGF_UNSTABLE, GUIO3(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_FB01_MIDI) },
+#endif
+
// Christmas Card 1988 - English DOS
// SCI interpreter version 0.000.294
{"christmas1988", "", {
@@ -268,7 +288,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.006", 0, "08050329aa113a9f14ed99cbfe3536ec", 232942},
{"resource.007", 0, "64f342463f6f35ba71b3509ef696ae3f", 267702},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformPC, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformPC, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
// Conquests of Camelot - English Amiga (from www.back2roots.org)
// Executable scanning reports "1.002.030"
diff --git a/engines/sci/engine/features.cpp b/engines/sci/engine/features.cpp
index 22c0a1479d..49e2bfc79f 100644
--- a/engines/sci/engine/features.cpp
+++ b/engines/sci/engine/features.cpp
@@ -466,6 +466,14 @@ bool GameFeatures::autoDetectSci21KernelType() {
// This case doesn't occur in early SCI2.1 games, and we've only
// seen it happen in the RAMA demo, thus we can assume that the
// game is using a SCI2.1 table
+
+ // HACK: The Inside the Chest Demo doesn't have sounds at all, but
+ // it's using a SCI2 kernel
+ if (g_sci->getGameId() == GID_CHEST) {
+ _sci21KernelType = SCI_VERSION_2;
+ return true;
+ }
+
warning("autoDetectSci21KernelType(): Sound object not loaded, assuming a SCI2.1 table");
_sci21KernelType = SCI_VERSION_2_1;
return true;
diff --git a/engines/sci/engine/file.cpp b/engines/sci/engine/file.cpp
index a0f7ebf4a2..3dc042389e 100644
--- a/engines/sci/engine/file.cpp
+++ b/engines/sci/engine/file.cpp
@@ -95,7 +95,7 @@ reg_t file_open(EngineState *s, const Common::String &filename, int mode, bool u
outFile = saveFileMan->openForSaving(wrappedName, isCompressed);
if (!outFile)
debugC(kDebugLevelFile, " -> file_open(_K_FILE_MODE_CREATE): failed to create file '%s'", englishName.c_str());
-
+
// QfG1 opens the character export file with _K_FILE_MODE_CREATE first,
// closes it immediately and opens it again with this here. Perhaps
// other games use this for read access as well. I guess changing this
@@ -387,7 +387,7 @@ uint32 VirtualIndexFile::read(char *buffer, uint32 size) {
uint32 VirtualIndexFile::write(const char *buffer, uint32 size) {
_changed = true;
uint32 curPos = _ptr - _buffer;
-
+
// Check if the buffer needs to be resized
if (curPos + size >= _bufferSize) {
_bufferSize = curPos + size + 1;
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index f5f46285be..d0c9b9b1cf 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -94,7 +94,7 @@ static const SciKernelMapSubEntry kDoSound_subops[] = {
{ SIG_SOUNDSCI0, 7, MAP_CALL(DoSoundResumeAfterRestore), "", NULL },
{ SIG_SOUNDSCI0, 8, MAP_CALL(DoSoundMasterVolume), "(i)", NULL },
{ SIG_SOUNDSCI0, 9, MAP_CALL(DoSoundUpdate), "o", NULL },
- { SIG_SOUNDSCI0, 10, MAP_CALL(DoSoundFade), "o", kDoSoundFade_workarounds },
+ { SIG_SOUNDSCI0, 10, MAP_CALL(DoSoundFade), "[o0]", kDoSoundFade_workarounds },
{ SIG_SOUNDSCI0, 11, MAP_CALL(DoSoundGetPolyphony), "", NULL },
{ SIG_SOUNDSCI0, 12, MAP_CALL(DoSoundStopAll), "", NULL },
{ SIG_SOUNDSCI1EARLY, 0, MAP_CALL(DoSoundMasterVolume), NULL, NULL },
@@ -524,7 +524,7 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(PalCycle), SIG_EVERYWHERE, "i(.*)", NULL, NULL },
// SCI2 Empty functions
-
+
// Debug function used to track resources
{ MAP_EMPTY(ResourceTrack), SIG_EVERYWHERE, "(.*)", NULL, NULL },
// Future TODO: This call is used in the floppy version of QFG4 to add
diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp
index f7cc4f44b5..e977f15c0c 100644
--- a/engines/sci/engine/kfile.cpp
+++ b/engines/sci/engine/kfile.cpp
@@ -340,7 +340,7 @@ reg_t kFileIOClose(EngineState *s, int argc, reg_t *argv) {
if (argv[0] == SIGNAL_REG)
return s->r_acc;
-
+
uint16 handle = argv[0].toUint16();
#ifdef ENABLE_SCI32
@@ -624,7 +624,7 @@ reg_t kFileIOExists(EngineState *s, int argc, reg_t *argv) {
// Special case for KQ6 Mac: The game checks for two video files to see
// if they exist before it plays them. Since we support multiple naming
// schemes for resource fork files, we also need to support that here in
- // case someone has a "HalfDome.bin" file, etc.
+ // case someone has a "HalfDome.bin" file, etc.
if (!exists && g_sci->getGameId() == GID_KQ6 && g_sci->getPlatform() == Common::kPlatformMacintosh &&
(name == "HalfDome" || name == "Kq6Movie"))
exists = Common::MacResManager::exists(name);
@@ -998,7 +998,7 @@ reg_t kMakeSaveFileName(EngineState *s, int argc, reg_t *argv) {
if ((virtualId < SAVEGAMEID_OFFICIALRANGE_START) || (virtualId > SAVEGAMEID_OFFICIALRANGE_END))
error("kMakeSaveFileName: invalid savegame ID specified");
uint saveSlot = virtualId - SAVEGAMEID_OFFICIALRANGE_START;
-
+
Common::Array<SavegameDesc> saves;
listSavegames(saves);
diff --git a/engines/sci/engine/kpathing.cpp b/engines/sci/engine/kpathing.cpp
index 002ef1ff07..b839ac51c3 100644
--- a/engines/sci/engine/kpathing.cpp
+++ b/engines/sci/engine/kpathing.cpp
@@ -31,6 +31,9 @@
#include "common/debug-channels.h"
#include "common/list.h"
#include "common/system.h"
+#include "common/math.h"
+
+//#define DEBUG_MERGEPOLY
namespace Sci {
@@ -71,11 +74,25 @@ enum {
struct FloatPoint {
FloatPoint() : x(0), y(0) {}
FloatPoint(float x_, float y_) : x(x_), y(y_) {}
+ FloatPoint(Common::Point p) : x(p.x), y(p.y) {}
Common::Point toPoint() {
return Common::Point((int16)(x + 0.5), (int16)(y + 0.5));
}
+ float operator*(const FloatPoint &p) const {
+ return x*p.x + y*p.y;
+ }
+ FloatPoint operator*(float l) const {
+ return FloatPoint(l*x, l*y);
+ }
+ FloatPoint operator-(const FloatPoint &p) const {
+ return FloatPoint(x-p.x, y-p.y);
+ }
+ float norm() const {
+ return x*x+y*y;
+ }
+
float x, y;
};
@@ -135,15 +152,20 @@ public:
return _head;
}
- void insertHead(Vertex *elm) {
+ void insertAtEnd(Vertex *elm) {
if (_head == NULL) {
elm->_next = elm->_prev = elm;
+ _head = elm;
} else {
elm->_next = _head;
elm->_prev = _head->_prev;
_head->_prev = elm;
elm->_prev->_next = elm;
}
+ }
+
+ void insertHead(Vertex *elm) {
+ insertAtEnd(elm);
_head = elm;
}
@@ -788,10 +810,10 @@ int PathfindingState::findNearPoint(const Common::Point &p, Polygon *polygon, Co
* including the vertices themselves)
* Parameters: (const Common::Point &) a, b: The line segment (a, b)
* (Vertex *) vertex: The first vertex of the edge
- * Returns : (int) FP_OK on success, PF_ERROR otherwise
+ * Returns : (int) PF_OK on success, PF_ERROR otherwise
* (FloatPoint) *ret: The intersection point
*/
-static int intersection(const Common::Point &a, const Common::Point &b, Vertex *vertex, FloatPoint *ret) {
+static int intersection(const Common::Point &a, const Common::Point &b, const Vertex *vertex, FloatPoint *ret) {
// Parameters of parametric equations
float s, t;
// Numerator and denominator of equations
@@ -1344,7 +1366,16 @@ static void AStar(PathfindingState *s) {
// other, while we apply a penalty to paths traversing it.
// This difference might lead to problems, but none are
// known at the time of writing.
- if (s->pointOnScreenBorder(vertex->v))
+
+ // WORKAROUND: This check fails in QFG1VGA, room 81 (bug report #3568452).
+ // However, it is needed in other SCI1.1 games, such as LB2. Therefore, we
+ // add this workaround for that scene in QFG1VGA, until our algorithm matches
+ // better what SSCI is doing. With this workaround, QFG1VGA no longer freezes
+ // in that scene.
+ bool qfg1VgaWorkaround = (g_sci->getGameId() == GID_QFG1VGA &&
+ g_sci->getEngineState()->currentRoomNumber() == 81);
+
+ if (s->pointOnScreenBorder(vertex->v) && !qfg1VgaWorkaround)
new_dist += 10000;
if (new_dist < vertex->costG) {
@@ -1783,39 +1814,619 @@ reg_t kIntersections(EngineState *s, int argc, reg_t *argv) {
}
}
+// ==========================================================================
+// kMergePoly utility functions
+
+// Compute square of the distance of p to the segment a-b.
+static float pointSegDistance(const Common::Point &a, const Common::Point &b,
+ const Common::Point &p) {
+ FloatPoint ba(b-a);
+ FloatPoint pa(p-a);
+ FloatPoint bp(b-p);
+
+ // Check if the projection of p on the line a-b lies between a and b
+ if (ba*pa >= 0.0f && ba*bp >= 0.0f) {
+ // If yes, return the (squared) distance of p to the line a-b:
+ // translate a to origin, project p and subtract
+ float linedist = (ba*((ba*pa)/(ba*ba)) - pa).norm();
+
+ return linedist;
+ } else {
+ // If no, return the (squared) distance to either a or b, whichever
+ // is closest.
+
+ // distance to a:
+ float adist = pa.norm();
+ // distance to b:
+ float bdist = FloatPoint(p-b).norm();
+
+ return MIN(adist, bdist);
+ }
+}
+
+// find intersection between edges of two polygons.
+// endpoints count, except v2->_next
+static bool segSegIntersect(const Vertex *v1, const Vertex *v2, Common::Point &intp) {
+ const Common::Point &a = v1->v;
+ const Common::Point &b = v1->_next->v;
+ const Common::Point &c = v2->v;
+ const Common::Point &d = v2->_next->v;
+
+ // First handle the endpoint cases manually
+
+ if (collinear(a, b, c) && collinear(a, b, d))
+ return false;
+
+ if (collinear(a, b, c)) {
+ // a, b, c collinear
+ // return true/c if c is between a and b
+ intp = c;
+ if (a.x != b.x) {
+ if ((a.x <= c.x && c.x <= b.x) || (b.x <= c.x && c.x <= a.x))
+ return true;
+ } else {
+ if ((a.y <= c.y && c.y <= b.y) || (b.y <= c.y && c.y <= a.y))
+ return true;
+ }
+ }
+
+ if (collinear(a, b, d)) {
+ intp = d;
+ // a, b, d collinear
+ // return false/d if d is between a and b
+ if (a.x != b.x) {
+ if ((a.x <= d.x && d.x <= b.x) || (b.x <= d.x && d.x <= a.x))
+ return false;
+ } else {
+ if ((a.y <= d.y && d.y <= b.y) || (b.y <= d.y && d.y <= a.y))
+ return false;
+ }
+ }
+
+ int len_dc = c.sqrDist(d);
+
+ if (!len_dc) error("zero length edge in polygon");
+
+ if (pointSegDistance(c, d, a) <= 2.0f) {
+ intp = a;
+ return true;
+ }
+
+ if (pointSegDistance(c, d, b) <= 2.0f) {
+ intp = b;
+ return true;
+ }
+
+ // If not an endpoint, call the generic intersection function
+
+ FloatPoint p;
+ if (intersection(a, b, v2, &p) == PF_OK) {
+ intp = p.toPoint();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+// For intersecting polygon segments, determine if
+// * the v2 edge enters polygon 1 at this intersection: positive return value
+// * the v2 edge and the v1 edges are parallel: zero return value
+// * the v2 edge exits polygon 1 at this intersection: negative return value
+static int intersectDir(const Vertex *v1, const Vertex *v2) {
+ Common::Point p1 = v1->_next->v - v1->v;
+ Common::Point p2 = v2->_next->v - v2->v;
+ return (p1.x*p2.y - p2.x*p1.y);
+}
+
+// Direction of edge in degrees from pos. x-axis, between -180 and 180
+static int edgeDir(const Vertex *v) {
+ Common::Point p = v->_next->v - v->v;
+ int deg = (int)Common::rad2deg(atan2((double)p.y, (double)p.x));
+ if (deg < -180) deg += 360;
+ if (deg > 180) deg -= 360;
+ return deg;
+}
+
+// For points p1, p2 on the polygon segment v, determine if
+// * p1 lies before p2: negative return value
+// * p1 and p2 are the same: zero return value
+// * p1 lies after p2: positive return value
+static int liesBefore(const Vertex *v, const Common::Point &p1, const Common::Point &p2) {
+ return v->v.sqrDist(p1) - v->v.sqrDist(p2);
+}
+
+// Structure describing an "extension" to the work polygon following edges
+// of the polygon being merged.
+
+// The patch begins on the point intersection1, being the intersection
+// of the edges starting at indexw1/vertexw1 on the work polygon, and at
+// indexp1/vertexp1 on the polygon being merged.
+// It ends with the point intersection2, being the analogous intersection.
+struct Patch {
+ unsigned int indexw1;
+ unsigned int indexp1;
+ const Vertex *vertexw1;
+ const Vertex *vertexp1;
+ Common::Point intersection1;
+
+ unsigned int indexw2;
+ unsigned int indexp2;
+ const Vertex *vertexw2;
+ const Vertex *vertexp2;
+ Common::Point intersection2;
+
+ bool disabled; // If true, this Patch was made superfluous by another Patch
+};
+
+
+// Check if the given vertex on the work polygon is bypassed by this patch.
+static bool isVertexCovered(const Patch &p, unsigned int wi) {
+
+ // / v (outside)
+ // ---w1--1----p----w2--2----
+ // ^ \ (inside)
+ if (wi > p.indexw1 && wi <= p.indexw2)
+ return true;
+
+ // v / (outside)
+ // ---w2--2----p----w1--1----
+ // \ ^ (inside)
+ if (p.indexw1 > p.indexw2 && (wi <= p.indexw2 || wi > p.indexw1))
+ return true;
+
+ // v / (outside)
+ // ---w1--2--1-------p-----
+ // w2 \ ^ (inside)
+ if (p.indexw1 == p.indexw2 && liesBefore(p.vertexw1, p.intersection1, p.intersection2) > 0)
+ return true; // This patch actually covers _all_ vertices on work
+
+ return false;
+}
+
+// Check if patch p1 makes patch p2 superfluous.
+static bool isPatchCovered(const Patch &p1, const Patch &p2) {
+
+ // Same exit and entry points
+ if (p1.intersection1 == p2.intersection1 && p1.intersection2 == p2.intersection2)
+ return true;
+
+ // / * v (outside)
+ // ---p1w1--1----p2w1-1---p1w2--2----
+ // ^ * \ (inside)
+ if (p1.indexw1 < p2.indexw1 && p2.indexw1 < p1.indexw2)
+ return true;
+ if (p1.indexw1 > p1.indexw2 && (p2.indexw1 > p1.indexw1 || p2.indexw1 < p1.indexw2))
+ return true;
+
+
+ // / * v (outside)
+ // ---p1w1--11----p2w2-2---p1w2--12----
+ // ^ * \ (inside)
+ if (p1.indexw1 < p2.indexw2 && p2.indexw2 < p1.indexw2)
+ return true;
+ if (p1.indexw1 > p1.indexw2 && (p2.indexw2 > p1.indexw1 || p2.indexw2 < p1.indexw2))
+ return true;
+
+ // Opposite of two above situations
+ if (p2.indexw1 < p1.indexw1 && p1.indexw1 < p2.indexw2)
+ return false;
+ if (p2.indexw1 > p2.indexw2 && (p1.indexw1 > p2.indexw1 || p1.indexw1 < p2.indexw2))
+ return false;
+
+ if (p2.indexw1 < p1.indexw2 && p1.indexw2 < p2.indexw2)
+ return false;
+ if (p2.indexw1 > p2.indexw2 && (p1.indexw2 > p2.indexw1 || p1.indexw2 < p2.indexw2))
+ return false;
+
+
+ // The above checks covered the cases where one patch covers the other and
+ // the intersections of the patches are on different edges.
+
+ // So, if we passed the above checks, we have to check the order of
+ // intersections on edges.
+
+
+ if (p1.indexw1 != p1.indexw2) {
+
+ // / * v (outside)
+ // ---p1w1--11---21--------p1w2--2----
+ // p2w1 ^ * \ (inside)
+ if (p1.indexw1 == p2.indexw1)
+ return (liesBefore(p1.vertexw1, p1.intersection1, p2.intersection1) < 0);
+
+ // / * v (outside)
+ // ---p1w1--11---------p1w2--21---12----
+ // ^ p2w1 * \ (inside)
+ if (p1.indexw2 == p2.indexw1)
+ return (liesBefore(p1.vertexw2, p1.intersection2, p2.intersection1) > 0);
+
+ // If neither of the above, then the intervals of the polygon
+ // covered by patch1 and patch2 are disjoint
+ return false;
+ }
+
+ // p1w1 == p1w2
+ // Also, p1w1/p1w2 isn't strictly between p2
+
+
+ // v / * (outside)
+ // ---p1w1--12--11-------p2w1-21----
+ // p1w2 \ ^ * (inside)
+
+ // v / / (outside)
+ // ---p1w1--12--21--11---------
+ // p1w2 \ ^ ^ (inside)
+ // p2w1
+ if (liesBefore(p1.vertexw1, p1.intersection1, p1.intersection2) > 0)
+ return (p1.indexw1 != p2.indexw1);
+
+ // CHECKME: This is meaningless if p2w1 != p2w2 ??
+ if (liesBefore(p2.vertexw1, p2.intersection1, p2.intersection2) > 0)
+ return false;
+
+ // CHECKME: This is meaningless if p1w1 != p2w1 ??
+ if (liesBefore(p2.vertexw1, p2.intersection1, p1.intersection1) <= 0)
+ return false;
+
+ // CHECKME: This is meaningless if p1w2 != p2w1 ??
+ if (liesBefore(p2.vertexw1, p2.intersection1, p1.intersection2) >= 0)
+ return false;
+
+ return true;
+}
+
+// Merge a single polygon into the work polygon.
+// If there is an intersection between work and polygon, this function
+// returns true, and replaces the vertex list of work by an extended version,
+// that covers polygon.
+//
+// NOTE: The strategy used matches qfg1new closely, and is a bit error-prone.
+// A more robust strategy would be inserting all intersection points directly
+// into both vertex lists as a first pass. This would make finding the merged
+// polygon a much more straightforward edge-walk, and avoid cases where SSCI's
+// algorithm mixes up the order of multiple intersections on a single edge.
+bool mergeSinglePolygon(Polygon &work, const Polygon &polygon) {
+#ifdef DEBUG_MERGEPOLY
+ const Vertex *vertex;
+ debugN("work:");
+ CLIST_FOREACH(vertex, &(work.vertices)) {
+ debugN(" (%d,%d) ", vertex->v.x, vertex->v.y);
+ }
+ debugN("\n");
+ debugN("poly:");
+ CLIST_FOREACH(vertex, &(polygon.vertices)) {
+ debugN(" (%d,%d) ", vertex->v.x, vertex->v.y);
+ }
+ debugN("\n");
+#endif
+ uint workSize = work.vertices.size();
+ uint polygonSize = polygon.vertices.size();
+
+ int patchCount = 0;
+ Patch patchList[8];
+
+ const Vertex *workv = work.vertices._head;
+ const Vertex *polyv = polygon.vertices._head;
+ for (uint wi = 0; wi < workSize; ++wi, workv = workv->_next) {
+ for (uint pi = 0; pi < polygonSize; ++pi, polyv = polyv->_next) {
+ Common::Point intersection1;
+ Common::Point intersection2;
+
+ bool intersects = segSegIntersect(workv, polyv, intersection1);
+ if (!intersects)
+ continue;
+
+#ifdef DEBUG_MERGEPOLY
+ debug("mergePoly: intersection at work %d, poly %d", wi, pi);
+#endif
+
+ if (intersectDir(workv, polyv) >= 0)
+ continue;
+
+#ifdef DEBUG_MERGEPOLY
+ debug("mergePoly: intersection in right direction");
+#endif
+
+ int angle = 0;
+ int baseAngle = edgeDir(workv);
+
+ // We now found the point where an edge of 'polygon' left 'work'.
+ // Now find the re-entry point.
+
+ // NOTE: The order in which this searches does not always work
+ // properly if the correct patch would only use a single partial
+ // edge of poly. Because it starts at polyv->_next, it will skip
+ // the correct re-entry and proceed to the next.
+
+ const Vertex *workv2;
+ const Vertex *polyv2 = polyv->_next;
+
+ intersects = false;
+
+ uint pi2, wi2;
+ for (pi2 = 0; pi2 < polygonSize; ++pi2, polyv2 = polyv2->_next) {
+
+ int newAngle = edgeDir(polyv2);
+
+ int relAngle = newAngle - baseAngle;
+ if (relAngle > 180) relAngle -= 360;
+ if (relAngle < -180) relAngle += 360;
+
+ angle += relAngle;
+ baseAngle = newAngle;
+
+ workv2 = workv;
+ for (wi2 = 0; wi2 < workSize; ++wi2, workv2 = workv2->_next) {
+ intersects = segSegIntersect(workv2, polyv2, intersection2);
+ if (!intersects)
+ continue;
+#ifdef DEBUG_MERGEPOLY
+ debug("mergePoly: re-entry intersection at work %d, poly %d", (wi + wi2) % workSize, (pi + 1 + pi2) % polygonSize);
+#endif
+
+ if (intersectDir(workv2, polyv2) > 0) {
+#ifdef DEBUG_MERGEPOLY
+ debug("mergePoly: re-entry intersection in right direction, angle = %d", angle);
+#endif
+ break; // found re-entry point
+ }
+
+ }
+
+ if (intersects)
+ break;
+
+ }
+
+ if (!intersects || angle < 0)
+ continue;
+
+
+ if (patchCount >= 8)
+ error("kMergePoly: Too many patches");
+
+ // convert relative to absolute vertex indices
+ pi2 = (pi + 1 + pi2) % polygonSize;
+ wi2 = (wi + wi2) % workSize;
+
+ Patch &newPatch = patchList[patchCount];
+ newPatch.indexw1 = wi;
+ newPatch.vertexw1 = workv;
+ newPatch.indexp1 = pi;
+ newPatch.vertexp1 = polyv;
+ newPatch.intersection1 = intersection1;
+
+ newPatch.indexw2 = wi2;
+ newPatch.vertexw2 = workv2;
+ newPatch.indexp2 = pi2;
+ newPatch.vertexp2 = polyv2;
+ newPatch.intersection2 = intersection2;
+ newPatch.disabled = false;
+
+#ifdef DEBUG_MERGEPOLY
+ debug("mergePoly: adding patch at work %d, poly %d", wi, pi);
+#endif
+
+ if (patchCount == 0) {
+ patchCount++;
+ continue;
+ }
+
+ bool necessary = true;
+ for (int i = 0; i < patchCount; ++i) {
+ if (isPatchCovered(patchList[i], newPatch)) {
+ necessary = false;
+ break;
+ }
+ }
+
+ if (!necessary)
+ continue;
+
+ patchCount++;
+
+ if (patchCount > 1) {
+ // check if this patch makes other patches superfluous
+ for (int i = 0; i < patchCount-1; ++i)
+ if (isPatchCovered(newPatch, patchList[i]))
+ patchList[i].disabled = true;
+ }
+ }
+ }
+
+
+ if (patchCount == 0)
+ return false; // nothing changed
+
+
+ // Determine merged work by doing a walk over the edges
+ // of work, crossing over to polygon when encountering a patch.
+
+ Polygon output(0);
+
+ workv = work.vertices._head;
+ for (uint wi = 0; wi < workSize; ++wi, workv = workv->_next) {
+
+ bool covered = false;
+ for (int p = 0; p < patchCount; ++p) {
+ if (patchList[p].disabled) continue;
+ if (isVertexCovered(patchList[p], wi)) {
+ covered = true;
+ break;
+ }
+ }
+
+ if (!covered) {
+ // Add vertex to output
+ output.vertices.insertAtEnd(new Vertex(workv->v));
+ }
+
+
+ // CHECKME: Why is this the correct order in which to process
+ // the patches? (What if two of them start on this line segment
+ // in the opposite order?)
+
+ for (int p = 0; p < patchCount; ++p) {
+
+ const Patch &patch = patchList[p];
+ if (patch.disabled) continue;
+ if (patch.indexw1 != wi) continue;
+ if (patch.intersection1 != workv->v) {
+ // Add intersection point to output
+ output.vertices.insertAtEnd(new Vertex(patch.intersection1));
+ }
+
+ // Add vertices from polygon between vertexp1 (excl) and vertexp2 (incl)
+ for (polyv = patch.vertexp1->_next; polyv != patch.vertexp2; polyv = polyv->_next)
+ output.vertices.insertAtEnd(new Vertex(polyv->v));
+
+ output.vertices.insertAtEnd(new Vertex(patch.vertexp2->v));
+
+ if (patch.intersection2 != patch.vertexp2->v) {
+ // Add intersection point to output
+ output.vertices.insertAtEnd(new Vertex(patch.intersection2));
+ }
+
+ // TODO: We could continue after the re-entry point here?
+ }
+ }
+ // Remove last vertex if it's the same as the first vertex
+ if (output.vertices._head->v == output.vertices._head->_prev->v)
+ output.vertices.remove(output.vertices._head->_prev);
+
+
+ // Slight hack: swap vertex lists of output and work polygons.
+ SWAP(output.vertices._head, work.vertices._head);
+
+ return true;
+}
+
+
/**
* This is a quite rare kernel function. An example of when it's called
* is in QFG1VGA, after killing any monster.
+ *
+ * It takes a polygon, and extends it to also cover any polygons from the
+ * input list with which it intersects. Any of those polygons so covered
+ * from the input list are marked by adding 0x10 to their type field.
*/
reg_t kMergePoly(EngineState *s, int argc, reg_t *argv) {
-#if 0
// 3 parameters: raw polygon data, polygon list, list size
reg_t polygonData = argv[0];
List *list = s->_segMan->lookupList(argv[1]);
- Node *node = s->_segMan->lookupNode(list->first);
- // List size is not needed
- Polygon *polygon;
- int count = 0;
+ // The size of the "work" point list SSCI uses. We use a dynamic one instead
+ //reg_t listSize = argv[2];
+
+ SegmentRef pointList = s->_segMan->dereference(polygonData);
+ if (!pointList.isValid() || pointList.skipByte) {
+ warning("kMergePoly: Polygon data pointer is invalid");
+ return make_reg(0, 0);
+ }
+
+ Node *node;
+
+#ifdef DEBUG_MERGEPOLY
+ node = s->_segMan->lookupNode(list->first);
+ while (node) {
+ draw_polygon(s, node->value, 320, 190);
+ node = s->_segMan->lookupNode(node->succ);
+ }
+ Common::Point prev, first;
+ prev = first = readPoint(pointList, 0);
+ for (int i = 1; readPoint(pointList, i).x != 0x7777; i++) {
+ Common::Point point = readPoint(pointList, i);
+ draw_line(s, prev, point, 1, 320, 190);
+ prev = point;
+ }
+ draw_line(s, prev, first, 1, 320, 190);
+ // Update the whole screen
+ g_sci->_gfxScreen->copyToScreen();
+ g_system->updateScreen();
+ g_system->delayMillis(1000);
+#endif
+
+ // The work polygon which we're going to merge with the polygons in list
+ Polygon work(0);
+
+ for (int i = 0; true; ++i) {
+ Common::Point p = readPoint(pointList, i);
+ if (p.x == POLY_LAST_POINT)
+ break;
+ Vertex *vertex = new Vertex(p);
+ work.vertices.insertAtEnd(vertex);
+ }
+
+ // TODO: Check behaviour for single-vertex polygons
+ node = s->_segMan->lookupNode(list->first);
while (node) {
- polygon = convert_polygon(s, node->value);
+ Polygon *polygon = convert_polygon(s, node->value);
if (polygon) {
- count += readSelectorValue(s->_segMan, node->value, SELECTOR(size));
+ // CHECKME: Confirm vertex order that convert_polygon and
+ // fix_vertex_order output. For now, we re-reverse the order since
+ // convert_polygon reads the vertices reversed, and fix up head.
+ polygon->vertices.reverse();
+ polygon->vertices._head = polygon->vertices._head->_next;
+
+ // Merge this polygon into the work polygon if there is an
+ // intersection.
+ bool intersected = mergeSinglePolygon(work, *polygon);
+
+ // If so, flag it
+ if (intersected) {
+ writeSelectorValue(s->_segMan, node->value,
+ SELECTOR(type), polygon->type + 0x10);
+#ifdef DEBUG_MERGEPOLY
+ debugN("Merged polygon: ");
+ // Iterate over edges
+ Vertex *vertex;
+ CLIST_FOREACH(vertex, &(work.vertices)) {
+ debugN(" (%d,%d) ", vertex->v.x, vertex->v.y);
+ }
+ debugN("\n");
+#endif
+ }
}
node = s->_segMan->lookupNode(node->succ);
}
-#endif
- // TODO: actually merge the polygon. We return an empty polygon for now.
- // In QFG1VGA, you can walk over enemy bodies after killing them, since
- // this is a stub.
- reg_t output = allocateOutputArray(s->_segMan, 1);
+
+ // Allocate output array
+ reg_t output = allocateOutputArray(s->_segMan, work.vertices.size()+1);
SegmentRef arrayRef = s->_segMan->dereference(output);
- writePoint(arrayRef, 0, Common::Point(POLY_LAST_POINT, POLY_LAST_POINT));
- warning("Stub: kMergePoly");
+
+ // Copy work.vertices into arrayRef
+ Vertex *vertex;
+ unsigned int n = 0;
+ CLIST_FOREACH(vertex, &work.vertices) {
+ if (vertex == work.vertices._head || vertex->v != vertex->_prev->v)
+ writePoint(arrayRef, n++, vertex->v);
+ }
+
+ writePoint(arrayRef, n, Common::Point(POLY_LAST_POINT, POLY_LAST_POINT));
+
+#ifdef DEBUG_MERGEPOLY
+ prev = first = readPoint(arrayRef, 0);
+ for (int i = 1; readPoint(arrayRef, i).x != 0x7777; i++) {
+ Common::Point point = readPoint(arrayRef, i);
+ draw_line(s, prev, point, 3, 320, 190);
+ prev = point;
+ }
+
+ draw_line(s, prev, first, 3, 320, 190);
+
+ // Update the whole screen
+ g_sci->_gfxScreen->copyToScreen();
+ g_system->updateScreen();
+ if (!g_sci->_gfxPaint16)
+ g_system->delayMillis(1000);
+
+ debug("kMergePoly done");
+#endif
+
return output;
}
diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp
index c22d7c7b1e..c4db0b891c 100644
--- a/engines/sci/engine/kstring.cpp
+++ b/engines/sci/engine/kstring.cpp
@@ -165,6 +165,7 @@ reg_t kReadNumber(EngineState *s, int argc, reg_t *argv) {
// do clipping. In SQ4 we get the door code in here and that's even
// larger than uint32!
if (*source == '-') {
+ // FIXME: Setting result to -1 does _not_ negate the output.
result = -1;
source++;
}
diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp
index 6bf9aff2fe..9b0cb38f51 100644
--- a/engines/sci/engine/kvideo.cpp
+++ b/engines/sci/engine/kvideo.cpp
@@ -275,7 +275,7 @@ reg_t kRobot(EngineState *s, int argc, reg_t *argv) {
// 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);
+ writeSelector(s->_segMan, argv[1], SELECTOR(signal), NULL_REG);
}
break;
default:
diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp
index 037f4ab700..36d2841b07 100644
--- a/engines/sci/engine/script.cpp
+++ b/engines/sci/engine/script.cpp
@@ -144,7 +144,7 @@ void Script::load(int script_nr, ResourceManager *resMan) {
_heapStart = _buf + _scriptSize;
- assert(_bufSize - _scriptSize <= heap->size);
+ assert(_bufSize - _scriptSize >= heap->size);
memcpy(_heapStart, heap->data, heap->size);
}
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index 659c13b13e..8639b6ef71 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -848,10 +848,47 @@ const uint16 qfg1vgaPatchFightEvents[] = {
PATCH_END
};
+// Script 814 of QFG1VGA is responsible for showing dialogs. However, the death
+// screen message shown when the hero dies in room 64 (ghost room) is too large
+// (254 chars long). Since the window header and main text are both stored in
+// temp space, this is an issue, as the scripts read the window header, then the
+// window text, which erases the window header text because of its length. To
+// fix that, we allocate more temp space and move the pointer used for the
+// window header a little bit, wherever it's used in script 814.
+// Fixes bug #3568431.
+
+// Patch 1: Increase temp space
+const byte qfg1vgaSignatureTempSpace[] = {
+ 4,
+ 0x3f, 0xba, // link 0xba
+ 0x87, 0x00, // lap 0
+ 0
+};
+
+const uint16 qfg1vgaPatchTempSpace[] = {
+ 0x3f, 0xca, // link 0xca
+ PATCH_END
+};
+
+// Patch 2: Move the pointer used for the window header a little bit
+const byte qfg1vgaSignatureDialogHeader[] = {
+ 4,
+ 0x5b, 0x04, 0x80, // lea temp[0x80]
+ 0x36, // push
+ 0
+};
+
+const uint16 qfg1vgaPatchDialogHeader[] = {
+ 0x5b, 0x04, 0x90, // lea temp[0x90]
+ PATCH_END
+};
+
// script, description, magic DWORD, adjust
const SciScriptSignature qfg1vgaSignatures[] = {
{ 215, "fight event issue", 1, PATCH_MAGICDWORD(0x6d, 0x76, 0x51, 0x07), -1, qfg1vgaSignatureFightEvents, qfg1vgaPatchFightEvents },
{ 216, "weapon master event issue", 1, PATCH_MAGICDWORD(0x6d, 0x76, 0x51, 0x07), -1, qfg1vgaSignatureFightEvents, qfg1vgaPatchFightEvents },
+ { 814, "window text temp space", 1, PATCH_MAGICDWORD(0x3f, 0xba, 0x87, 0x00), 0, qfg1vgaSignatureTempSpace, qfg1vgaPatchTempSpace },
+ { 814, "dialog header offset", 3, PATCH_MAGICDWORD(0x5b, 0x04, 0x80, 0x36), 0, qfg1vgaSignatureDialogHeader, qfg1vgaPatchDialogHeader },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -915,9 +952,53 @@ const uint16 qfg3PatchImportDialog[] = {
PATCH_END
};
+
+
+// ===========================================================================
+// Patch for the Woo dialog option in Uhura's conversation. Bug #3040722
+// Problem: The Woo dialog option (0xffb5) is negative, and therefore
+// treated as an option opening a submenu. This leads to uhuraTell::doChild
+// being called, which calls hero::solvePuzzle and then proceeds with
+// Teller::doChild to open the submenu. However, there is no actual submenu
+// defined for option -75 since -75 does not show up in uhuraTell::keys.
+// This will cause Teller::doChild to run out of bounds while scanning through
+// uhuraTell::keys.
+// Strategy: there is another conversation option in uhuraTell::doChild calling
+// hero::solvePuzzle (0xfffc) which does a ret afterwards without going to
+// Teller::doChild. We jump to this call of hero::solvePuzzle to get that same
+// behaviour.
+
+const byte qfg3SignatureWooDialog[] = {
+ 30,
+ 0x67, 0x12, // pTos 12 (query)
+ 0x35, 0xb6, // ldi b6
+ 0x1a, // eq?
+ 0x2f, 0x05, // bt 05
+ 0x67, 0x12, // pTos 12 (query)
+ 0x35, 0x9b, // ldi 9b
+ 0x1a, // eq?
+ 0x31, 0x0c, // bnt 0c
+ 0x38, 0x97, 0x02, // pushi 0297
+ 0x7a, // push2
+ 0x38, 0x0c, 0x01, // pushi 010c
+ 0x7a, // push2
+ 0x81, 0x00, // lag 00
+ 0x4a, 0x08, // send 08
+ 0x67, 0x12, // pTos 12 (query)
+ 0x35, 0xb5, // ldi b5
+ 0
+};
+
+const uint16 qfg3PatchWooDialog[] = {
+ PATCH_ADDTOOFFSET | +0x29,
+ 0x33, 0x11, // jmp to 0x6a2, the call to hero::solvePuzzle for 0xFFFC
+ PATCH_END
+};
+
// script, description, magic DWORD, adjust
const SciScriptSignature qfg3Signatures[] = {
{ 944, "import dialog continuous calls", 1, PATCH_MAGICDWORD(0x2a, 0x31, 0x0b, 0x7a), -1, qfg3SignatureImportDialog, qfg3PatchImportDialog },
+ { 440, "dialog crash when asking about Woo", 1, PATCH_MAGICDWORD(0x67, 0x12, 0x35, 0xb5), -26, qfg3SignatureWooDialog, qfg3PatchWooDialog },
SCI_SIGNATUREENTRY_TERMINATOR
};
diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp
index d3abb9ff41..b2f22aa985 100644
--- a/engines/sci/engine/scriptdebug.cpp
+++ b/engines/sci/engine/scriptdebug.cpp
@@ -514,7 +514,7 @@ void Kernel::dissectScript(int scriptNumber, Vocabulary *vocab) {
if (!objType) {
debugN("End of script object (#0) encountered.\n");
- debugN("Classes: %i, Objects: %i, Export: %i,\n Var: %i (all base 10)",
+ debugN("Classes: %i, Objects: %i, Export: %i,\n Var: %i (all base 10)\n",
objectctr[6], objectctr[1], objectctr[7], objectctr[10]);
return;
}
@@ -527,7 +527,8 @@ void Kernel::dissectScript(int scriptNumber, Vocabulary *vocab) {
_seeker += objsize;
- objectctr[objType]++;
+ if (objType >= 0 && objType < ARRAYSIZE(objectctr))
+ objectctr[objType]++;
switch (objType) {
case SCI_OBJ_OBJECT:
diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp
index 951fc7c363..04c1dab158 100644
--- a/engines/sci/engine/seg_manager.cpp
+++ b/engines/sci/engine/seg_manager.cpp
@@ -825,7 +825,7 @@ byte *SegManager::allocDynmem(int size, const char *descr, reg_t *addr) {
}
bool SegManager::freeDynmem(reg_t addr) {
- if (addr.getSegment() < 1 || addr.getSegment() >= _heap.size() ||
+ if (addr.getSegment() < 1 || addr.getSegment() >= _heap.size() ||
!_heap[addr.getSegment()] || _heap[addr.getSegment()]->getType() != SEG_TYPE_DYNMEM)
return false; // error
diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp
index 3f43966976..ef8f165084 100644
--- a/engines/sci/engine/vm.cpp
+++ b/engines/sci/engine/vm.cpp
@@ -228,7 +228,7 @@ ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackP
uint32 exportAddr = scr->validateExportFunc(pubfunct, false);
if (!exportAddr)
return NULL;
-
+
// Check if a breakpoint is set on this method
g_sci->checkExportBreakpoint(script, pubfunct);
diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index 9fa0368784..db510c2545 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -243,9 +243,6 @@ const SciWorkaroundEntry kDisposeScript_workarounds[] = {
// gameID, room,script,lvl, object-name, method-name, call,index, workaround
const SciWorkaroundEntry kDoSoundFade_workarounds[] = {
- { GID_CAMELOT, -1, 989, 0, "rmMusic", "fade", -1, 0, { WORKAROUND_IGNORE, 0 } }, // gets called frequently with a NULL reference (i.e. 0:0) - bug #3035149
- { GID_KQ1, -1, 989, 0, "gameSound", "fade", -1, 0, { WORKAROUND_IGNORE, 0 } }, // gets called in several scenes (e.g. graham cracker) with 0:0
- { GID_KQ4, -1, 989, 0, "mySound", "", -1, 0, { WORKAROUND_IGNORE, 0 } }, // gets called in the demo when trying to open the non-existent menu with 0:0 - bug #3036942
{ GID_KQ5, 213, 989, 0, "globalSound3", "fade", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // english floppy: when bandits leave the secret temple, parameter 4 is an object - bug #3037594
{ GID_KQ6, 105, 989, 0, "globalSound", "fade", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // floppy: during intro, parameter 4 is an object
{ GID_KQ6, 460, 989, 0, "globalSound2", "fade", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // after pulling the black widow's web on the isle of wonder, parameter 4 is an object - bug #3034567
diff --git a/engines/sci/graphics/controls32.cpp b/engines/sci/graphics/controls32.cpp
index ad1d9e8623..5535a7408a 100644
--- a/engines/sci/graphics/controls32.cpp
+++ b/engines/sci/graphics/controls32.cpp
@@ -68,7 +68,7 @@ void GfxControls32::kernelTexteditChange(reg_t controlObject) {
while (captureEvents) {
curEvent = g_sci->getEventManager()->getSciEvent(SCI_EVENT_KEYBOARD | SCI_EVENT_PEEK);
-
+
if (curEvent.type == SCI_EVENT_NONE) {
eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event
} else {
@@ -170,11 +170,11 @@ void GfxControls32::kernelTexteditChange(reg_t controlObject) {
// Note: the following checkAltInput call might make the text
// too wide to fit, but SSCI fails to check that too.
}
-
+
reg_t hunkId = readSelector(_segMan, controlObject, SELECTOR(bitmap));
Common::Rect nsRect = g_sci->_gfxCompare->getNSRect(controlObject);
//texteditCursorErase(); // TODO: Cursor
-
+
// Write back string
_segMan->strcpy(textReference, text.c_str());
// Modify the buffer and show it
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index 968014c032..8b7fa2c384 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -197,7 +197,7 @@ void GfxFrameout::kernelUpdatePlane(reg_t object) {
} else {
it->planeOffsetX = 0;
}
-
+
if (it->planeRect.top < 0) {
it->planeOffsetY = -it->planeRect.top;
it->planeRect.top = 0;
@@ -420,7 +420,7 @@ void GfxFrameout::deletePlaneItems(reg_t planeObject) {
} else {
objectMatches = true;
}
-
+
if (objectMatches) {
FrameoutEntry *itemEntry = *listIterator;
listIterator = _screenItems.erase(listIterator);
@@ -661,7 +661,7 @@ void GfxFrameout::kernelFrameout() {
if (!itemEntry->visible)
continue;
-
+
if (itemEntry->object.isNull()) {
// Picture cel data
_coordAdjuster->fromScriptToDisplay(itemEntry->y, itemEntry->x);
@@ -703,7 +703,7 @@ void GfxFrameout::kernelFrameout() {
view->getCelRect(itemEntry->loopNo, itemEntry->celNo,
itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->celRect);
else
- view->getCelScaledRect(itemEntry->loopNo, itemEntry->celNo,
+ view->getCelScaledRect(itemEntry->loopNo, itemEntry->celNo,
itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->scaleX,
itemEntry->scaleY, itemEntry->celRect);
@@ -755,10 +755,10 @@ void GfxFrameout::kernelFrameout() {
if (view) {
if (!clipRect.isEmpty()) {
if ((itemEntry->scaleX == 128) && (itemEntry->scaleY == 128))
- view->draw(itemEntry->celRect, clipRect, translatedClipRect,
+ view->draw(itemEntry->celRect, clipRect, translatedClipRect,
itemEntry->loopNo, itemEntry->celNo, 255, 0, view->isSci2Hires());
else
- view->drawScaled(itemEntry->celRect, clipRect, translatedClipRect,
+ view->drawScaled(itemEntry->celRect, clipRect, translatedClipRect,
itemEntry->loopNo, itemEntry->celNo, 255, itemEntry->scaleX, itemEntry->scaleY);
}
}
@@ -817,7 +817,7 @@ void GfxFrameout::printPlaneItemList(Console *con, reg_t planeObject) {
for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) {
FrameoutEntry *e = *listIterator;
reg_t itemPlane = readSelector(_segMan, e->object, SELECTOR(plane));
-
+
if (planeObject == itemPlane) {
Common::String curItemName = _segMan->getObjectName(e->object);
Common::Rect icr = e->celRect;
diff --git a/engines/sci/graphics/paint16.cpp b/engines/sci/graphics/paint16.cpp
index 89f3625e2c..d20aa80c77 100644
--- a/engines/sci/graphics/paint16.cpp
+++ b/engines/sci/graphics/paint16.cpp
@@ -559,8 +559,8 @@ reg_t GfxPaint16::kernelDisplay(const char *text, int argc, reg_t *argv) {
SciTrackOriginReply originReply;
SciWorkaroundSolution solution = trackOriginAndFindWorkaround(0, kDisplay_workarounds, &originReply);
if (solution.type == WORKAROUND_NONE)
- error("Unknown kDisplay argument (%04x:%04x) from method %s::%s (script %d, localCall %x)",
- PRINT_REG(displayArg), originReply.objectName.c_str(), originReply.methodName.c_str(),
+ error("Unknown kDisplay argument (%04x:%04x) from method %s::%s (script %d, localCall %x)",
+ PRINT_REG(displayArg), originReply.objectName.c_str(), originReply.methodName.c_str(),
originReply.scriptNr, originReply.localCallOffset);
assert(solution.type == WORKAROUND_IGNORE);
break;
diff --git a/engines/sci/graphics/ports.cpp b/engines/sci/graphics/ports.cpp
index 6b4c8180bf..8acdeed763 100644
--- a/engines/sci/graphics/ports.cpp
+++ b/engines/sci/graphics/ports.cpp
@@ -380,17 +380,50 @@ Window *GfxPorts::addWindow(const Common::Rect &dims, const Common::Rect *restor
int16 oldtop = pwnd->dims.top;
int16 oldleft = pwnd->dims.left;
- if (wmprect.top > pwnd->dims.top)
+ // WORKAROUND: We also adjust the restore rect when adjusting the window
+ // rect.
+ // SSCI does not do this. It wasn't necessary in the original interpreter,
+ // but it is needed for Freddy Pharkas CD. This version does not normally
+ // have text, but we allow this by modifying the text/speech setting
+ // according to what is set in the ScummVM GUI (refer to syncIngameAudioOptions()
+ // in sci.cpp). Since the text used in Freddy Pharkas CD is quite large in
+ // some cases, it ends up being offset in order to fit inside the screen,
+ // but the associated restore rect isn't adjusted accordingly, leading to
+ // artifacts being left on screen when some text boxes are removed. The
+ // fact that the restore rect wasn't ever adjusted doesn't make sense, and
+ // adjusting it shouldn't have any negative side-effects (it *should* be
+ // adjusted, normally, but SCI doesn't do it). The big text boxes are still
+ // odd-looking, because the text rect is drawn outside the text window rect,
+ // but at least there aren't any leftover textbox artifacts left when the
+ // boxes are removed. Adjusting the text window rect would require more
+ // invasive changes than this one, thus it's not really worth the effort
+ // for a feature that was not present in the original game, and its
+ // implementation is buggy in the first place.
+ // Adjusting the restore rect properly fixes bug #3575276.
+
+ if (wmprect.top > pwnd->dims.top) {
pwnd->dims.moveTo(pwnd->dims.left, wmprect.top);
+ if (restoreRect)
+ pwnd->restoreRect.moveTo(pwnd->restoreRect.left, wmprect.top);
+ }
- if (wmprect.bottom < pwnd->dims.bottom)
+ if (wmprect.bottom < pwnd->dims.bottom) {
pwnd->dims.moveTo(pwnd->dims.left, wmprect.bottom - pwnd->dims.bottom + pwnd->dims.top);
+ if (restoreRect)
+ pwnd->restoreRect.moveTo(pwnd->restoreRect.left, wmprect.bottom - pwnd->restoreRect.bottom + pwnd->restoreRect.top);
+ }
- if (wmprect.right < pwnd->dims.right)
+ if (wmprect.right < pwnd->dims.right) {
pwnd->dims.moveTo(wmprect.right + pwnd->dims.left - pwnd->dims.right, pwnd->dims.top);
+ if (restoreRect)
+ pwnd->restoreRect.moveTo(wmprect.right + pwnd->restoreRect.left - pwnd->restoreRect.right, pwnd->restoreRect.top);
+ }
- if (wmprect.left > pwnd->dims.left)
+ if (wmprect.left > pwnd->dims.left) {
pwnd->dims.moveTo(wmprect.left, pwnd->dims.top);
+ if (restoreRect)
+ pwnd->restoreRect.moveTo(wmprect.left, pwnd->restoreRect.top);
+ }
pwnd->rect.moveTo(pwnd->rect.left + pwnd->dims.left - oldleft, pwnd->rect.top + pwnd->dims.top - oldtop);
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index 42ae00b525..15b18ce8e6 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -876,6 +876,7 @@ void SciEngine::syncIngameAudioOptions() {
if (getGameId() == GID_SQ4
|| getGameId() == GID_FREDDYPHARKAS
|| getGameId() == GID_ECOQUEST
+ || getGameId() == GID_LSL6
// TODO: The following need script patches for simultaneous speech and subtitles
//|| getGameId() == GID_KQ6
//|| getGameId() == GID_LAURABOW2
diff --git a/engines/sci/sci.h b/engines/sci/sci.h
index 9f18219cb7..3b9844b326 100644
--- a/engines/sci/sci.h
+++ b/engines/sci/sci.h
@@ -110,6 +110,7 @@ enum SciGameId {
GID_ASTROCHICKEN,
GID_CAMELOT,
GID_CASTLEBRAIN,
+ GID_CHEST,
GID_CHRISTMAS1988,
GID_CHRISTMAS1990,
GID_CHRISTMAS1992,
@@ -228,6 +229,26 @@ public:
bool canLoadGameStateCurrently();
bool canSaveGameStateCurrently();
void syncSoundSettings();
+
+ /**
+ * Syncs the audio options of the ScummVM launcher (speech, subtitles or
+ * both) with the in-game audio options of certain CD game versions. For
+ * some games, this allows simultaneous playing of speech and subtitles,
+ * even if the original games didn't support this feature.
+ *
+ * SCI1.1 games which support simultaneous speech and subtitles:
+ * - EcoQuest 1 CD
+ * - Leisure Suit Larry 6 CD
+ * SCI1.1 games which don't support simultaneous speech and subtitles,
+ * and we add this functionality in ScummVM:
+ * - Space Quest 4 CD
+ * - Freddy Pharkas CD
+ * SCI1.1 games which don't support simultaneous speech and subtitles,
+ * and we haven't added any extra functionality in ScummVM because extra
+ * script patches are needed:
+ * - Laura Bow 2 CD
+ * - King's Quest 6 CD
+ */
void syncIngameAudioOptions();
const SciGameId &getGameId() const { return _gameId; }
diff --git a/engines/sci/sound/drivers/fmtowns.cpp b/engines/sci/sound/drivers/fmtowns.cpp
index 6d8bb2e525..21cb2f1e43 100644
--- a/engines/sci/sound/drivers/fmtowns.cpp
+++ b/engines/sci/sound/drivers/fmtowns.cpp
@@ -52,8 +52,8 @@ public:
uint16 _duration;
private:
- uint8 _id;
- uint8 _velo;
+ uint8 _id;
+ uint8 _velo;
uint8 _program;
MidiDriver_FMTowns *_drv;
@@ -76,7 +76,7 @@ public:
void addChannels(int num);
void dropChannels(int num);
-
+
uint8 currentProgram() const;
private:
@@ -132,7 +132,7 @@ private:
TownsMidiPart **_parts;
TownsChannel **_out;
-
+
uint8 _masterVolume;
bool _soundOn;
@@ -590,7 +590,7 @@ void MidiDriver_FMTowns::addMissingChannels() {
avlChan -= _parts[i]->_chanMissing;
uint8 m = _parts[i]->_chanMissing;
_parts[i]->_chanMissing = 0;
- _parts[i]->addChannels(m);
+ _parts[i]->addChannels(m);
} else {
_parts[i]->_chanMissing -= avlChan;
_parts[i]->addChannels(avlChan);
@@ -601,7 +601,7 @@ void MidiDriver_FMTowns::addMissingChannels() {
void MidiDriver_FMTowns::updateParser() {
if (_timerProc)
- _timerProc(_timerProcPara);
+ _timerProc(_timerProcPara);
}
void MidiDriver_FMTowns::updateChannels() {
diff --git a/engines/sci/sound/midiparser_sci.cpp b/engines/sci/sound/midiparser_sci.cpp
index 422948f975..4e54797960 100644
--- a/engines/sci/sound/midiparser_sci.cpp
+++ b/engines/sci/sound/midiparser_sci.cpp
@@ -98,7 +98,7 @@ bool MidiParser_SCI::loadMusic(SoundResource::Track *track, MusicEntry *psnd, in
midiMixChannels();
}
- _num_tracks = 1;
+ _numTracks = 1;
_tracks[0] = _mixedData;
if (_pSnd)
setTrack(0);
@@ -144,7 +144,7 @@ byte *MidiParser_SCI::midiMixChannels() {
_mixedData = outData;
long ticker = 0;
byte channelNr, curDelta;
- byte midiCommand = 0, midiParam, global_prev = 0;
+ byte midiCommand = 0, midiParam, globalPrev = 0;
long newDelta;
SoundResource::Channel *channel;
@@ -190,13 +190,13 @@ byte *MidiParser_SCI::midiMixChannels() {
byte midiChannel = midiCommand & 0xF;
_channelUsed[midiChannel] = true;
- if (midiCommand != global_prev)
+ if (midiCommand != globalPrev)
*outData++ = midiCommand;
*outData++ = midiParam;
if (nMidiParams[(midiCommand >> 4) - 8] == 2)
*outData++ = channel->data[channel->curPos++];
channel->prev = midiCommand;
- global_prev = midiCommand;
+ globalPrev = midiCommand;
}
}
@@ -372,8 +372,8 @@ void MidiParser_SCI::unloadMusic() {
resetTracking();
allNotesOff();
}
- _num_tracks = 0;
- _active_track = 255;
+ _numTracks = 0;
+ _activeTrack = 255;
_resetOnPause = false;
if (_mixedData) {
@@ -454,26 +454,26 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) {
debugC(4, kDebugLevelSound, "signal %04x", _signalToSet);
}
- info.start = _position._play_pos;
+ info.start = _position._playPos;
info.delta = 0;
- while (*_position._play_pos == 0xF8) {
+ while (*_position._playPos == 0xF8) {
info.delta += 240;
- _position._play_pos++;
+ _position._playPos++;
}
- info.delta += *(_position._play_pos++);
+ info.delta += *(_position._playPos++);
// Process the next info.
- if ((_position._play_pos[0] & 0xF0) >= 0x80)
- info.event = *(_position._play_pos++);
+ if ((_position._playPos[0] & 0xF0) >= 0x80)
+ info.event = *(_position._playPos++);
else
- info.event = _position._running_status;
+ info.event = _position._runningStatus;
if (info.event < 0x80)
return;
- _position._running_status = info.event;
+ _position._runningStatus = info.event;
switch (info.command()) {
case 0xC:
- info.basic.param1 = *(_position._play_pos++);
+ info.basic.param1 = *(_position._playPos++);
info.basic.param2 = 0;
if (info.channel() == 0xF) {// SCI special case
if (info.basic.param1 != kSetSignalLoop) {
@@ -488,23 +488,23 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) {
// in glitches (e.g. the intro of LB1 Amiga gets stuck - bug
// #3297883). Refer to MusicEntry::setSignal() in sound/music.cpp.
if (_soundVersion <= SCI_VERSION_0_LATE ||
- _position._play_tick || info.delta) {
+ _position._playTick || info.delta) {
_signalSet = true;
_signalToSet = info.basic.param1;
}
} else {
- _loopTick = _position._play_tick + info.delta;
+ _loopTick = _position._playTick + info.delta;
}
}
break;
case 0xD:
- info.basic.param1 = *(_position._play_pos++);
+ info.basic.param1 = *(_position._playPos++);
info.basic.param2 = 0;
break;
case 0xB:
- info.basic.param1 = *(_position._play_pos++);
- info.basic.param2 = *(_position._play_pos++);
+ info.basic.param1 = *(_position._playPos++);
+ info.basic.param2 = *(_position._playPos++);
// Reference for some events:
// http://wiki.scummvm.org/index.php/SCI/Specifications/Sound/SCI0_Resource_Format#Status_Reference
@@ -588,8 +588,8 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) {
case 0x9:
case 0xA:
case 0xE:
- info.basic.param1 = *(_position._play_pos++);
- info.basic.param2 = *(_position._play_pos++);
+ info.basic.param1 = *(_position._playPos++);
+ info.basic.param2 = *(_position._playPos++);
if (info.command() == 0x9 && info.basic.param2 == 0)
info.event = info.channel() | 0x80;
info.length = 0;
@@ -598,12 +598,12 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) {
case 0xF: // System Common, Meta or SysEx event
switch (info.event & 0x0F) {
case 0x2: // Song Position Pointer
- info.basic.param1 = *(_position._play_pos++);
- info.basic.param2 = *(_position._play_pos++);
+ info.basic.param1 = *(_position._playPos++);
+ info.basic.param2 = *(_position._playPos++);
break;
case 0x3: // Song Select
- info.basic.param1 = *(_position._play_pos++);
+ info.basic.param1 = *(_position._playPos++);
info.basic.param2 = 0;
break;
@@ -617,16 +617,16 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) {
break;
case 0x0: // SysEx
- info.length = readVLQ(_position._play_pos);
- info.ext.data = _position._play_pos;
- _position._play_pos += info.length;
+ info.length = readVLQ(_position._playPos);
+ info.ext.data = _position._playPos;
+ _position._playPos += info.length;
break;
case 0xF: // META event
- info.ext.type = *(_position._play_pos++);
- info.length = readVLQ(_position._play_pos);
- info.ext.data = _position._play_pos;
- _position._play_pos += info.length;
+ info.ext.type = *(_position._playPos++);
+ info.length = readVLQ(_position._playPos);
+ info.ext.data = _position._playPos;
+ _position._playPos += info.length;
if (info.ext.type == 0x2F) {// end of track reached
if (_pSnd->loop)
_pSnd->loop--;
@@ -677,21 +677,21 @@ void MidiParser_SCI::allNotesOff() {
// Turn off all active notes
for (i = 0; i < 128; ++i) {
for (j = 0; j < 16; ++j) {
- if ((_active_notes[i] & (1 << j)) && (_channelRemap[j] != -1)){
+ if ((_activeNotes[i] & (1 << j)) && (_channelRemap[j] != -1)){
sendToDriver(0x80 | j, i, 0);
}
}
}
// Turn off all hanging notes
- for (i = 0; i < ARRAYSIZE(_hanging_notes); i++) {
- byte midiChannel = _hanging_notes[i].channel;
- if ((_hanging_notes[i].time_left) && (_channelRemap[midiChannel] != -1)) {
- sendToDriver(0x80 | midiChannel, _hanging_notes[i].note, 0);
- _hanging_notes[i].time_left = 0;
+ for (i = 0; i < ARRAYSIZE(_hangingNotes); i++) {
+ byte midiChannel = _hangingNotes[i].channel;
+ if ((_hangingNotes[i].timeLeft) && (_channelRemap[midiChannel] != -1)) {
+ sendToDriver(0x80 | midiChannel, _hangingNotes[i].note, 0);
+ _hangingNotes[i].timeLeft = 0;
}
}
- _hanging_notes_count = 0;
+ _hangingNotesCount = 0;
// To be sure, send an "All Note Off" event (but not all MIDI devices
// support this...).
@@ -703,7 +703,7 @@ void MidiParser_SCI::allNotesOff() {
}
}
- memset(_active_notes, 0, sizeof(_active_notes));
+ memset(_activeNotes, 0, sizeof(_activeNotes));
}
void MidiParser_SCI::setMasterVolume(byte masterVolume) {
diff --git a/engines/sci/sound/midiparser_sci.h b/engines/sci/sound/midiparser_sci.h
index 82f34070a4..d3fd337644 100644
--- a/engines/sci/sound/midiparser_sci.h
+++ b/engines/sci/sound/midiparser_sci.h
@@ -65,7 +65,7 @@ public:
void setMasterVolume(byte masterVolume);
void setVolume(byte volume);
void stop() {
- _abort_parse = true;
+ _abortParse = true;
allNotesOff();
}
void pause() {
diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp
index 5d32f40f18..7782ab4e48 100644
--- a/engines/sci/sound/soundcmd.cpp
+++ b/engines/sci/sound/soundcmd.cpp
@@ -340,6 +340,12 @@ reg_t SoundCommandParser::kDoSoundMasterVolume(int argc, reg_t *argv, reg_t acc)
reg_t SoundCommandParser::kDoSoundFade(int argc, reg_t *argv, reg_t acc) {
reg_t obj = argv[0];
+ // The object can be null in several SCI0 games (e.g. Camelot, KQ1, KQ4, MUMG).
+ // Check bugs #3035149, #3036942 and #3578335.
+ // In this case, we just ignore the call.
+ if (obj.isNull() && argc == 1)
+ return acc;
+
MusicEntry *musicSlot = _music->getSlot(obj);
if (!musicSlot) {
debugC(kDebugLevelSound, "kDoSound(fade): Slot not found (%04x:%04x)", PRINT_REG(obj));
diff --git a/engines/sci/video/robot_decoder.cpp b/engines/sci/video/robot_decoder.cpp
index 608c77136f..0337a8d306 100644
--- a/engines/sci/video/robot_decoder.cpp
+++ b/engines/sci/video/robot_decoder.cpp
@@ -109,13 +109,13 @@ bool RobotDecoder::loadStream(Common::SeekableReadStream *stream) {
}
bool RobotDecoder::load(GuiResourceId id) {
- // TODO: RAMA's robot 1003 cannot be played (shown at the menu screen) -
+ // 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;
@@ -247,7 +247,7 @@ void RobotDecoder::readNextPacket() {
audioTrack->queueBuffer(g_sci->_audio->getDecodedRobotAudioFrame(_fileStream, audioChunkSize), audioChunkSize * 2);
} else {
_fileStream->skip(audioChunkSize);
- }
+ }
}
void RobotDecoder::readHeaderChunk() {
diff --git a/engines/sci/video/robot_decoder.h b/engines/sci/video/robot_decoder.h
index ebc3262939..437954f7fb 100644
--- a/engines/sci/video/robot_decoder.h
+++ b/engines/sci/video/robot_decoder.h
@@ -45,13 +45,13 @@ public:
bool loadStream(Common::SeekableReadStream *stream);
bool load(GuiResourceId id);
void close();
-
+
void setPos(uint16 x, uint16 y) { _pos = Common::Point(x, y); }
Common::Point getPos() const { return _pos; }
protected:
void readNextPacket();
-
+
private:
class RobotVideoTrack : public FixedRateVideoTrack {
public:
diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp
index b8722b6963..0c375efcdd 100644
--- a/engines/scumm/actor.cpp
+++ b/engines/scumm/actor.cpp
@@ -573,19 +573,19 @@ bool Actor_v2::checkWalkboxesHaveDirectPath(Common::Point &foundPath) {
return false;
}
-bool Actor_v0::intersectLineSegments(const Common::Point &line1Start, const Common::Point &line1End,
- const Common::Point &line2Start, const Common::Point &line2End, Common::Point &result)
+bool Actor_v0::intersectLineSegments(const Common::Point &line1Start, const Common::Point &line1End,
+ const Common::Point &line2Start, const Common::Point &line2End, Common::Point &result)
{
const Common::Point v1 = line1End - line1Start; // line1(n1) = line1Start + n1 * v1
const Common::Point v2 = line2End - line2Start; // line2(n2) = line2Start + n2 * v2
-
+
double det = v2.x * v1.y - v1.x * v2.y;
if (det == 0)
return false;
- double n1 = ((double)v2.x * (line2Start.y - line1Start.y) -
+ double n1 = ((double)v2.x * (line2Start.y - line1Start.y) -
(double)v2.y * (line2Start.x - line1Start.x)) / det;
- double n2 = ((double)v1.x * (line2Start.y - line1Start.y) -
+ double n2 = ((double)v1.x * (line2Start.y - line1Start.y) -
(double)v1.y * (line2Start.x - line1Start.x)) / det;
// both coefficients have to be in [0, 1], otherwise the intersection is
@@ -599,16 +599,16 @@ bool Actor_v0::intersectLineSegments(const Common::Point &line1Start, const Comm
}
/*
- * MM v0 allows the actor to walk in a direct line between boxes to the target
+ * MM v0 allows the actor to walk in a direct line between boxes to the target
* if actor and target share a horizontal or vertical corridor.
- * If such a corridor is found the actor is not forced to go horizontally or
+ * If such a corridor is found the actor is not forced to go horizontally or
* vertically from one box to the next but can also walk diagonally.
*
- * Note: the original v0 interpreter sets the target destination for diagonal
+ * Note: the original v0 interpreter sets the target destination for diagonal
* walking only once and then rechecks whenever the actor reaches a new box if the
- * walk destination is still suitable for the current box.
- * ScummVM does not perform such a check, so it is possible to leave the walkboxes
- * in some cases, for example L-shaped rooms like the swimming pool (actor walks over water)
+ * walk destination is still suitable for the current box.
+ * ScummVM does not perform such a check, so it is possible to leave the walkboxes
+ * in some cases, for example L-shaped rooms like the swimming pool (actor walks over water)
* or the medical room (actor walks over examination table).
* To solve this we intersect the new walk destination with the actor's walkbox borders,
* so a recheck is done when the actor leaves his box. This is done by the
@@ -992,7 +992,7 @@ void Actor_v0::setDirection(int direction) {
res = 7; // Face Camera
break;
}
-
+
_animFrameRepeat = -1;
animateActor(res);
if (_moving)
@@ -1408,7 +1408,7 @@ void Actor::showActor() {
if (_vm->_game.version == 0) {
Actor_v0 *a = ((Actor_v0 *)this);
-
+
a->_costCommand = a->_costCommandNew = 0xFF;
for (int i = 0; i < 8; ++i) {
@@ -2056,7 +2056,7 @@ void Actor_v0::animateCostume() {
void Actor_v0::speakCheck() {
if (v0ActorTalkArray[_number] & 0x80)
return;
-
+
int cmd = newDirToOldDir(_facing);
if (_speaking & 0x80)
@@ -2884,7 +2884,7 @@ void Actor_v0::animateActor(int anim) {
_costCommandNew = anim;
_vm->_costumeLoader->costumeDecodeData(this, 0, 0);
-
+
if (dir == -1)
return;
diff --git a/engines/scumm/actor.h b/engines/scumm/actor.h
index 0ed239d005..a733fdb4ed 100644
--- a/engines/scumm/actor.h
+++ b/engines/scumm/actor.h
@@ -377,7 +377,7 @@ public:
virtual void saveLoadWithSerializer(Serializer *ser);
protected:
- bool intersectLineSegments(const Common::Point &line1Start, const Common::Point &line1End,
+ bool intersectLineSegments(const Common::Point &line1Start, const Common::Point &line1End,
const Common::Point &line2Start, const Common::Point &line2End, Common::Point &result);
virtual bool checkWalkboxesHaveDirectPath(Common::Point &foundPath);
};
diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp
index 4064853b6b..9ae75b6683 100644
--- a/engines/scumm/charset.cpp
+++ b/engines/scumm/charset.cpp
@@ -69,7 +69,7 @@ void ScummEngine::loadCJKFont() {
_cjkFont->setDrawingMode(Graphics::FontSJIS::kShadowMode);
_2byteWidth = _2byteHeight = 12;
- _useCJKMode = true;
+ _useCJKMode = true;
#endif
} else if (_game.id == GID_MONKEY && _game.platform == Common::kPlatformSegaCD && _language == Common::JA_JPN) {
int numChar = 1413;
@@ -499,7 +499,7 @@ int CharsetRendererV3::getCharWidth(uint16 chr) {
if (_vm->_useCJKMode && (chr & 0x80))
spacing = _vm->_2byteWidth / 2;
-
+
if (!spacing)
spacing = *(_widthTable + chr);
@@ -644,7 +644,7 @@ void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) {
drawBits1(*vs, _left + vs->xstart, drawTop, charPtr, drawTop, origWidth, origHeight);
else
drawBits1(_vm->_textSurface, _left * _vm->_textSurfaceMultiplier, _top * _vm->_textSurfaceMultiplier, charPtr, drawTop, origWidth, origHeight);
-
+
if (is2byte) {
origWidth /= _vm->_textSurfaceMultiplier;
height /= _vm->_textSurfaceMultiplier;
@@ -1399,7 +1399,7 @@ void CharsetRendererTownsClassic::drawBitsN(const Graphics::Surface&, byte *dst,
_vm->_cjkFont->drawChar(_vm->_textSurface, _sjisCurChar, _left * _vm->_textSurfaceMultiplier, (_top - _vm->_screenTop) * _vm->_textSurfaceMultiplier, _vm->_townsCharsetColorMap[1], _shadowColor);
return;
}
-
+
bool scale2x = (_vm->_textSurfaceMultiplier == 2);
dst = (byte *)_vm->_textSurface.pixels + (_top - _vm->_screenTop) * _vm->_textSurface.pitch * _vm->_textSurfaceMultiplier + _left * _vm->_textSurfaceMultiplier;
diff --git a/engines/scumm/charset.h b/engines/scumm/charset.h
index b8f1d84045..1c1df51921 100644
--- a/engines/scumm/charset.h
+++ b/engines/scumm/charset.h
@@ -112,7 +112,7 @@ public:
class CharsetRendererClassic : public CharsetRendererCommon {
protected:
virtual void drawBitsN(const Graphics::Surface &s, byte *dst, const byte *src, byte bpp, int drawTop, int width, int height);
- void printCharIntern(bool is2byte, const byte *charPtr, int origWidth, int origHeight, int width, int height, VirtScreen *vs, bool ignoreCharsetMask);
+ void printCharIntern(bool is2byte, const byte *charPtr, int origWidth, int origHeight, int width, int height, VirtScreen *vs, bool ignoreCharsetMask);
virtual bool prepareDraw(uint16 chr);
int _width, _height, _origWidth, _origHeight;
@@ -195,7 +195,7 @@ public:
int getCharWidth(uint16 chr);
int getFontHeight();
-
+
private:
void enableShadow(bool enable);
void drawBits1(Graphics::Surface &dest, int x, int y, const byte *src, int drawTop, int width, int height);
diff --git a/engines/scumm/costume.cpp b/engines/scumm/costume.cpp
index 3f89bc9611..4ebdd00fdc 100644
--- a/engines/scumm/costume.cpp
+++ b/engines/scumm/costume.cpp
@@ -1188,7 +1188,7 @@ byte V0CostumeRenderer::drawLimb(const Actor *a, int limb) {
_draw_top = 200;
_draw_bottom = 0;
}
-
+
// Invalid current position?
if (a->_cost.curpos[limb] == 0xFFFF)
return 0;
@@ -1377,7 +1377,7 @@ byte V0CostumeLoader::increaseAnim(Actor *a, int limb) {
// Reset the comstume command
a0->_costCommandNew = 0xFF;
a0->_costCommand = 0xFF;
-
+
// Set the frame/start to invalid
a0->_cost.frame[limb] = 0xFFFF;
a0->_cost.start[limb] = 0xFFFF;
diff --git a/engines/scumm/cursor.cpp b/engines/scumm/cursor.cpp
index 88681898f5..269ae9e10a 100644
--- a/engines/scumm/cursor.cpp
+++ b/engines/scumm/cursor.cpp
@@ -180,7 +180,7 @@ void ScummEngine_v70he::setDefaultCursor() {
0xff, 0xff, 0xff,
0, 0, 0, };
-
+
memset(_grabbedCursor, 5, sizeof(_grabbedCursor));
_cursor.hotspotX = _cursor.hotspotY = 2;
diff --git a/engines/scumm/debugger.cpp b/engines/scumm/debugger.cpp
index edcf2e6fea..dc5acbdb7d 100644
--- a/engines/scumm/debugger.cpp
+++ b/engines/scumm/debugger.cpp
@@ -382,7 +382,7 @@ bool ScummDebugger::Cmd_Actor(int argc, const char **argv) {
DebugPrintf("Actor[%d].costume = %d\n", actnum, a->_costume);
}
} else if (!strcmp(argv[2], "name")) {
- DebugPrintf("Name of actor %d: %s\n", actnum,
+ DebugPrintf("Name of actor %d: %s\n", actnum,
_vm->getObjOrActorName(_vm->actorToObj(actnum)));
} else if (!strcmp(argv[2], "condmask")) {
if (argc > 3) {
diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp
index 5404c7f8b1..e5c3023380 100644
--- a/engines/scumm/detection.cpp
+++ b/engines/scumm/detection.cpp
@@ -242,6 +242,10 @@ static Common::String generateFilenameForDetection(const char *pattern, Filename
return result;
}
+bool ScummEngine::isMacM68kIMuse() const {
+ return _game.platform == Common::kPlatformMacintosh && (_game.id == GID_MONKEY2 || _game.id == GID_INDY4) && !(_game.features & GF_MAC_CONTAINER);
+}
+
struct DetectorDesc {
Common::FSNode node;
Common::String md5;
@@ -473,6 +477,11 @@ static void computeGameSettingsFromMD5(const Common::FSList &fslist, const GameF
if (dr.language == UNK_LANG) {
dr.language = detectLanguage(fslist, dr.game.id);
}
+
+ // HACK: Detect between 68k and PPC versions
+ if (dr.game.platform == Common::kPlatformMacintosh && dr.game.version >= 5 && dr.game.heversion == 0 && strstr(gfp->pattern, "Data"))
+ dr.game.features |= GF_MAC_CONTAINER;
+
break;
}
}
diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h
index be1b90e356..3120017db6 100644
--- a/engines/scumm/detection_tables.h
+++ b/engines/scumm/detection_tables.h
@@ -236,7 +236,7 @@ static const GameSettings gameVariantsTable[] = {
{"monkey", "VGA", "vga", GID_MONKEY_VGA, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO1(GUIO_NOSPEECH)},
{"monkey", "EGA", "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, GF_16COLOR, Common::kPlatformPC, GUIO1(GUIO_NOSPEECH)},
{"monkey", "No AdLib", "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_PCJR, GF_16COLOR, Common::kPlatformAtariST, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)},
- {"monkey", "Demo", "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_ADLIB, GF_16COLOR, Common::kPlatformPC, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)},
+ {"monkey", "Demo", "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, GF_16COLOR, Common::kPlatformPC, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)},
{"monkey", "CD", 0, GID_MONKEY, 5, 0, MDT_ADLIB, GF_AUDIOTRACKS, UNK, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)},
{"monkey", "FM-TOWNS", 0, GID_MONKEY, 5, 0, MDT_TOWNS, GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_MIDITOWNS, GUIO_NOASPECT)},
{"monkey", "SEGA", 0, GID_MONKEY, 5, 0, MDT_NONE, GF_AUDIOTRACKS, Common::kPlatformSegaCD, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)},
diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index 0e531daf73..945c5b6611 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -180,7 +180,7 @@ static const ResString string_map_table_v345[] = {
// "Moechten Sie wirklich neu starten? (J/N)J"
// Will react to J as 'Yes'
{5, _s("Are you sure you want to restart? (Y/N)")},
- // I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
+ // I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
{6, _s("Are you sure you want to quit? (Y/N)")},
// Added in SCUMM4
diff --git a/engines/scumm/he/logic/soccer.cpp b/engines/scumm/he/logic/soccer.cpp
index 05f377a736..2b29f93173 100644
--- a/engines/scumm/he/logic/soccer.cpp
+++ b/engines/scumm/he/logic/soccer.cpp
@@ -303,7 +303,7 @@ int LogicHEsoccer::op_1008(int outArray, int srcX, int srcY, int srcZ, int vecX,
putInArray(outArray, segmentsSoFar, 5, vecX);
putInArray(outArray, segmentsSoFar, 6, vecY);
putInArray(outArray, segmentsSoFar++, 7, vecZ);
- }
+ }
} else {
srcY = 0;
int thisVecX = vecX;
@@ -628,7 +628,7 @@ int LogicHEsoccer::op_1014(int32 srcX, int32 srcY, int32 srcZ, int32 velX, int32
adjustedVelZ = ((double)srcZ - 3869.0) / 100.0;
break;
}
-
+
int foundCollision = 0;
// work out which collision objects we might collide with (if any)
diff --git a/engines/scumm/he/wiz_he.cpp b/engines/scumm/he/wiz_he.cpp
index 47b4b8ad33..798f703db6 100644
--- a/engines/scumm/he/wiz_he.cpp
+++ b/engines/scumm/he/wiz_he.cpp
@@ -2286,8 +2286,7 @@ void Wiz::fillWizLine(const WizParameters *params) {
lineP.depth = bitDepth;
if (params->processFlags & kWPFParams) {
- assert (params->params2 == 1); // Catch untested usage
- Graphics::drawThickLine(x1, y1, x2, y2, params->params1, color, drawProc, &lineP);
+ Graphics::drawThickLine(x1, y1, x2, y2, params->params1, params->params2, color, drawProc, &lineP);
} else {
Graphics::drawLine(x1, y1, x2, y2, color, drawProc, &lineP);
}
diff --git a/engines/scumm/imuse/imuse.cpp b/engines/scumm/imuse/imuse.cpp
index 27a72c2afe..016ba89e7b 100644
--- a/engines/scumm/imuse/imuse.cpp
+++ b/engines/scumm/imuse/imuse.cpp
@@ -164,7 +164,7 @@ bool IMuseInternal::isMT32(int sound) {
return true;
case MKTAG('M', 'A', 'C', ' '): // Occurs in the Mac version of FOA and MI2
- return true;
+ return false;
case MKTAG('G', 'M', 'D', ' '):
return false;
@@ -226,6 +226,45 @@ bool IMuseInternal::isMIDI(int sound) {
return false;
}
+bool IMuseInternal::supportsPercussion(int sound) {
+ byte *ptr = g_scumm->_res->_types[rtSound][sound]._address;
+ if (ptr == NULL)
+ return false;
+
+ uint32 tag = READ_BE_UINT32(ptr);
+ switch (tag) {
+ case MKTAG('A', 'D', 'L', ' '):
+ case MKTAG('A', 'S', 'F', 'X'): // Special AD class for old AdLib sound effects
+ case MKTAG('S', 'P', 'K', ' '):
+ return false;
+
+ case MKTAG('A', 'M', 'I', ' '):
+ case MKTAG('R', 'O', 'L', ' '):
+ return true;
+
+ case MKTAG('M', 'A', 'C', ' '): // Occurs in the Mac version of FOA and MI2
+ // This is MIDI, i.e. uses MIDI style program changes, but without a
+ // special percussion channel.
+ return false;
+
+ case MKTAG('G', 'M', 'D', ' '):
+ case MKTAG('M', 'I', 'D', 'I'): // Occurs in Sam & Max
+ return true;
+ }
+
+ // Old style 'RO' has equivalent properties to 'ROL'
+ if (ptr[0] == 'R' && ptr[1] == 'O')
+ return true;
+ // Euphony tracks show as 'SO' and have equivalent properties to 'ADL'
+ // FIXME: Right now we're pretending it's GM.
+ if (ptr[4] == 'S' && ptr[5] == 'O')
+ return true;
+
+ error("Unknown music type: '%c%c%c%c'", (char)tag >> 24, (char)tag >> 16, (char)tag >> 8, (char)tag);
+
+ return false;
+}
+
MidiDriver *IMuseInternal::getBestMidiDriver(int sound) {
MidiDriver *driver = NULL;
diff --git a/engines/scumm/imuse/imuse_internal.h b/engines/scumm/imuse/imuse_internal.h
index 3b0d36e119..846e2d7545 100644
--- a/engines/scumm/imuse/imuse_internal.h
+++ b/engines/scumm/imuse/imuse_internal.h
@@ -204,6 +204,7 @@ protected:
bool _isMT32;
bool _isMIDI;
+ bool _supportsPercussion;
protected:
// Player part
@@ -458,6 +459,7 @@ protected:
byte *findStartOfSound(int sound, int ct = (kMThd | kFORM));
bool isMT32(int sound);
bool isMIDI(int sound);
+ bool supportsPercussion(int sound);
int get_queue_sound_status(int sound) const;
void handle_marker(uint id, byte data);
int get_channel_volume(uint a);
diff --git a/engines/scumm/imuse/imuse_part.cpp b/engines/scumm/imuse/imuse_part.cpp
index 73e7704469..89c16a8bb5 100644
--- a/engines/scumm/imuse/imuse_part.cpp
+++ b/engines/scumm/imuse/imuse_part.cpp
@@ -27,6 +27,7 @@
#include "common/util.h"
#include "scumm/imuse/imuse_internal.h"
#include "scumm/saveload.h"
+#include "scumm/scumm.h"
namespace Scumm {
@@ -365,7 +366,17 @@ void Part::set_instrument(uint b) {
_bank = (byte)(b >> 8);
if (_bank)
error("Non-zero instrument bank selection. Please report this");
- _instrument.program((byte)b, _player->isMT32());
+ // HACK: Horrible hack to allow tracing of program change source.
+ // The Mac m68k versions of MI2 and Indy4 use a different program "bank"
+ // when it gets program change events through the iMuse SysEx handler.
+ // We emulate this by introducing a special instrument, which sets
+ // the instrument via sysEx_customInstrument. This seems to be
+ // exclusively used for special sound effects like the "spit" sound.
+ if (g_scumm->isMacM68kIMuse()) {
+ _instrument.macSfx(b);
+ } else {
+ _instrument.program((byte)b, _player->isMT32());
+ }
if (clearToTransmit())
_instrument.send(_mc);
}
diff --git a/engines/scumm/imuse/imuse_player.cpp b/engines/scumm/imuse/imuse_player.cpp
index 53ccfb3734..3a9c42a920 100644
--- a/engines/scumm/imuse/imuse_player.cpp
+++ b/engines/scumm/imuse/imuse_player.cpp
@@ -78,6 +78,7 @@ Player::Player() :
_speed(128),
_isMT32(false),
_isMIDI(false),
+ _supportsPercussion(false),
_se(0),
_vol_chan(0) {
}
@@ -103,6 +104,7 @@ bool Player::startSound(int sound, MidiDriver *midi) {
_isMT32 = _se->isMT32(sound);
_isMIDI = _se->isMIDI(sound);
+ _supportsPercussion = _se->supportsPercussion(sound);
_parts = NULL;
_active = true;
@@ -386,6 +388,8 @@ void Player::sysEx(const byte *p, uint16 len) {
// SysEx manufacturer 0x97 has been spotted in the
// Monkey Island 2 AdLib music, so don't make this a
// fatal error. See bug #1481383.
+ // The Macintosh version of Monkey Island 2 simply
+ // ignores these SysEx events too.
if (a == 0)
warning("Unknown SysEx manufacturer 0x00 0x%02X 0x%02X", p[0], p[1]);
else
@@ -1009,6 +1013,7 @@ void Player::fixAfterLoad() {
_parser->jumpToTick(_music_tick); // start_seq_sound already switched tracks
_isMT32 = _se->isMT32(_id);
_isMIDI = _se->isMIDI(_id);
+ _supportsPercussion = _se->supportsPercussion(_id);
}
}
diff --git a/engines/scumm/imuse/instrument.cpp b/engines/scumm/imuse/instrument.cpp
index 11bb4e7605..61c73b1e2d 100644
--- a/engines/scumm/imuse/instrument.cpp
+++ b/engines/scumm/imuse/instrument.cpp
@@ -278,6 +278,21 @@ private:
byte _instrument[23];
};
+class Instrument_MacSfx : public InstrumentInternal {
+private:
+ byte _program;
+
+public:
+ Instrument_MacSfx(byte program);
+ Instrument_MacSfx(Serializer *s);
+ void saveOrLoad(Serializer *s);
+ void send(MidiChannel *mc);
+ void copy_to(Instrument *dest) { dest->macSfx(_program); }
+ bool is_valid() {
+ return (_program < 128);
+ }
+};
+
////////////////////////////////////////
//
// Instrument class members
@@ -326,6 +341,14 @@ void Instrument::pcspk(const byte *instrument) {
_instrument = new Instrument_PcSpk(instrument);
}
+void Instrument::macSfx(byte prog) {
+ clear();
+ if (prog > 127)
+ return;
+ _type = itMacSfx;
+ _instrument = new Instrument_MacSfx(prog);
+}
+
void Instrument::saveOrLoad(Serializer *s) {
if (s->isSaving()) {
s->saveByte(_type);
@@ -349,6 +372,9 @@ void Instrument::saveOrLoad(Serializer *s) {
case itPcSpk:
_instrument = new Instrument_PcSpk(s);
break;
+ case itMacSfx:
+ _instrument = new Instrument_MacSfx(s);
+ break;
default:
warning("No known instrument classification #%d", (int)_type);
_type = itNone;
@@ -528,4 +554,38 @@ void Instrument_PcSpk::send(MidiChannel *mc) {
mc->sysEx_customInstrument('SPK ', (byte *)&_instrument);
}
+////////////////////////////////////////
+//
+// Instrument_MacSfx class members
+//
+////////////////////////////////////////
+
+Instrument_MacSfx::Instrument_MacSfx(byte program) :
+ _program(program) {
+ if (program > 127) {
+ _program = 255;
+ }
+}
+
+Instrument_MacSfx::Instrument_MacSfx(Serializer *s) {
+ _program = 255;
+ if (!s->isSaving()) {
+ saveOrLoad(s);
+ }
+}
+
+void Instrument_MacSfx::saveOrLoad(Serializer *s) {
+ if (s->isSaving()) {
+ s->saveByte(_program);
+ } else {
+ _program = s->loadByte();
+ }
+}
+
+void Instrument_MacSfx::send(MidiChannel *mc) {
+ if (_program > 127) {
+ return;
+ }
+ mc->sysEx_customInstrument('MAC ', &_program);
+}
} // End of namespace Scumm
diff --git a/engines/scumm/imuse/instrument.h b/engines/scumm/imuse/instrument.h
index a855c64155..7e09e86fa5 100644
--- a/engines/scumm/imuse/instrument.h
+++ b/engines/scumm/imuse/instrument.h
@@ -52,7 +52,8 @@ public:
itProgram = 1,
itAdLib = 2,
itRoland = 3,
- itPcSpk = 4
+ itPcSpk = 4,
+ itMacSfx = 5
};
Instrument() : _type(0), _instrument(0) { }
@@ -72,6 +73,7 @@ public:
void adlib(const byte *instrument);
void roland(const byte *instrument);
void pcspk(const byte *instrument);
+ void macSfx(byte program);
byte getType() { return _type; }
bool isValid() { return (_instrument ? _instrument->is_valid() : false); }
diff --git a/engines/scumm/imuse/mac_m68k.cpp b/engines/scumm/imuse/mac_m68k.cpp
new file mode 100644
index 0000000000..0980ef1fd2
--- /dev/null
+++ b/engines/scumm/imuse/mac_m68k.cpp
@@ -0,0 +1,514 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "scumm/imuse/mac_m68k.h"
+
+#include "common/util.h"
+#include "common/macresman.h"
+#include "common/stream.h"
+
+namespace Scumm {
+
+MacM68kDriver::MacM68kDriver(Audio::Mixer *mixer)
+ : MidiDriver_Emulated(mixer) {
+}
+
+MacM68kDriver::~MacM68kDriver() {
+}
+
+int MacM68kDriver::open() {
+ if (_isOpen) {
+ return MERR_ALREADY_OPEN;
+ }
+
+ const int error = MidiDriver_Emulated::open();
+ if (error) {
+ return error;
+ }
+
+ for (uint i = 0; i < ARRAYSIZE(_channels); ++i) {
+ _channels[i].init(this, i);
+ }
+
+ memset(_voiceChannels, 0, sizeof(_voiceChannels));
+ _lastUsedVoiceChannel = 0;
+
+ loadAllInstruments();
+
+ _pitchTable[116] = 1664510;
+ _pitchTable[117] = 1763487;
+ _pitchTable[118] = 1868350;
+ _pitchTable[119] = 1979447;
+ _pitchTable[120] = 2097152;
+ _pitchTable[121] = 2221855;
+ _pitchTable[122] = 2353973;
+ _pitchTable[123] = 2493948;
+ _pitchTable[124] = 2642246;
+ _pitchTable[125] = 2799362;
+ _pitchTable[126] = 2965820;
+ _pitchTable[127] = 3142177;
+ for (int i = 115; i >= 0; --i) {
+ _pitchTable[i] = _pitchTable[i + 12] / 2;
+ }
+
+ _volumeTable = new byte[8192];
+ for (int i = 0; i < 32; ++i) {
+ for (int j = 0; j < 256; ++j) {
+ _volumeTable[i * 256 + j] = ((-128 + j) * _volumeBaseTable[i]) / 127 - 128;
+ }
+ }
+
+ _mixBuffer = 0;
+ _mixBufferLength = 0;
+
+ // We set the output sound type to music here to allow sound volume
+ // adjustment. The drawback here is that we can not control the music and
+ // sfx separately here. But the AdLib output has the same issue so it
+ // should not be that bad.
+ _mixer->playStream(Audio::Mixer::kMusicSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+
+ return 0;
+}
+
+void MacM68kDriver::close() {
+ if (!_isOpen) {
+ return;
+ }
+
+ _mixer->stopHandle(_mixerSoundHandle);
+ _isOpen = false;
+ for (InstrumentMap::iterator i = _instruments.begin(); i != _instruments.end(); ++i) {
+ delete[] i->_value.data;
+ }
+ _instruments.clear();
+ delete[] _volumeTable;
+ _volumeTable = 0;
+ delete[] _mixBuffer;
+ _mixBuffer = 0;
+ _mixBufferLength = 0;
+}
+
+void MacM68kDriver::send(uint32 d) {
+ assert(false);
+}
+
+void MacM68kDriver::sysEx_customInstrument(byte channel, uint32 type, const byte *instr) {
+ assert(false);
+}
+
+MidiChannel *MacM68kDriver::allocateChannel() {
+ for (uint i = 0; i < ARRAYSIZE(_channels); ++i) {
+ if (_channels[i].allocate()) {
+ return &_channels[i];
+ }
+ }
+
+ return 0;
+}
+
+MacM68kDriver::Instrument MacM68kDriver::getInstrument(int idx) const {
+ InstrumentMap::const_iterator i = _instruments.find(idx);
+ if (i != _instruments.end()) {
+ return i->_value;
+ } else {
+ return _defaultInstrument;
+ }
+}
+
+void MacM68kDriver::generateSamples(int16 *buf, int len) {
+ int silentChannels = 0;
+
+ if (_mixBufferLength < len) {
+ delete[] _mixBuffer;
+
+ _mixBufferLength = len;
+ _mixBuffer = new int[_mixBufferLength];
+ assert(_mixBuffer);
+ }
+ memset(_mixBuffer, 0, sizeof(int) * _mixBufferLength);
+
+ for (int i = 0; i < kChannelCount; ++i) {
+ OutputChannel &out = _voiceChannels[i].out;
+ if (out.isFinished) {
+ ++silentChannels;
+ continue;
+ }
+
+ byte *volumeTable = &_volumeTable[(out.volume / 4) * 256];
+ int *buffer = _mixBuffer;
+
+ int samplesLeft = len;
+ while (samplesLeft) {
+ out.subPos += out.pitchModifier;
+ while (out.subPos >= 0x10000) {
+ out.subPos -= 0x10000;
+ out.instrument++;
+ }
+
+ if (out.instrument >= out.end) {
+ if (!out.start) {
+ break;
+ }
+
+ out.instrument = out.start;
+ out.subPos = 0;
+ }
+
+ *buffer++ += volumeTable[*out.instrument];
+ --samplesLeft;
+ }
+
+ if (samplesLeft) {
+ out.isFinished = true;
+ while (samplesLeft--) {
+ *buffer++ += 0x80;
+ }
+ }
+ }
+
+ const int *buffer = _mixBuffer;
+ const int silenceAdd = silentChannels << 7;
+ while (len--) {
+ *buf++ = (((*buffer++ + silenceAdd) >> 3) << 8) ^ 0x8000;
+ }
+}
+
+void MacM68kDriver::loadAllInstruments() {
+ Common::MacResManager resource;
+ if (resource.open("iMUSE Setups")) {
+ if (!resource.hasResFork()) {
+ error("MacM68kDriver::loadAllInstruments: \"iMUSE Setups\" loaded, but no resource fork present");
+ }
+
+ for (int i = 0x3E7; i < 0x468; ++i) {
+ Common::SeekableReadStream *stream = resource.getResource(MKTAG('s', 'n', 'd', ' '), i);
+ if (stream) {
+ addInstrument(i, stream);
+ delete stream;
+ }
+ }
+
+ for (int i = 0x7D0; i < 0x8D0; ++i) {
+ Common::SeekableReadStream *stream = resource.getResource(MKTAG('s', 'n', 'd', ' '), i);
+ if (stream) {
+ addInstrument(i, stream);
+ delete stream;
+ }
+ }
+
+ InstrumentMap::iterator inst = _instruments.find(kDefaultInstrument);
+ if (inst != _instruments.end()) {
+ _defaultInstrument = inst->_value;
+ } else {
+ error("MacM68kDriver::loadAllInstruments: Could not load default instrument");
+ }
+ } else {
+ error("MacM68kDriver::loadAllInstruments: Could not load \"iMUSE Setups\"");
+ }
+}
+
+void MacM68kDriver::addInstrument(int idx, Common::SeekableReadStream *data) {
+ // We parse the "SND" files manually here, since we need special data
+ // from their header and need to work on them raw while mixing.
+ data->skip(2);
+ int count = data->readUint16BE();
+ data->skip(2 * (3 * count));
+ count = data->readUint16BE();
+ data->skip(2 * (4 * count));
+
+ Instrument inst;
+ // Skip (optional) pointer to data
+ data->skip(4);
+ inst.length = data->readUint32BE();
+ inst.sampleRate = data->readUint32BE();
+ inst.loopStart = data->readUint32BE();
+ inst.loopEnd = data->readUint32BE();
+ // Skip encoding
+ data->skip(1);
+ inst.baseFrequency = data->readByte();
+
+ inst.data = new byte[inst.length];
+ assert(inst.data);
+ data->read(inst.data, inst.length);
+ _instruments[idx] = inst;
+}
+
+void MacM68kDriver::setPitch(OutputChannel *out, int frequency) {
+ out->frequency = frequency;
+ out->isFinished = false;
+
+ const int pitchIdx = (frequency >> 7) + 60 - out->baseFrequency;
+ assert(pitchIdx >= 0);
+
+ const int low7Bits = frequency & 0x7F;
+ if (low7Bits) {
+ out->pitchModifier = _pitchTable[pitchIdx] + (((_pitchTable[pitchIdx + 1] - _pitchTable[pitchIdx]) * low7Bits) >> 7);
+ } else {
+ out->pitchModifier = _pitchTable[pitchIdx];
+ }
+}
+
+void MacM68kDriver::VoiceChannel::off() {
+ if (out.start) {
+ out.isFinished = true;
+ }
+
+ part->removeVoice(this);
+ part = 0;
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::release() {
+ _allocated = false;
+ while (_voice) {
+ _voice->off();
+ }
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::send(uint32 b) {
+ uint8 type = b & 0xF0;
+ uint8 p1 = (b >> 8) & 0xFF;
+ uint8 p2 = (b >> 16) & 0xFF;
+
+ switch (type) {
+ case 0x80:
+ noteOff(p1);
+ break;
+
+ case 0x90:
+ if (p2) {
+ noteOn(p1, p2);
+ } else {
+ noteOff(p1);
+ }
+ break;
+
+ case 0xB0:
+ controlChange(p1, p2);
+ break;
+
+ case 0xE0:
+ pitchBend((p1 | (p2 << 7)) - 0x2000);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::noteOff(byte note) {
+ for (VoiceChannel *i = _voice; i; i = i->next) {
+ if (i->note == note) {
+ if (_sustain) {
+ i->sustainNoteOff = true;
+ } else {
+ i->off();
+ }
+ }
+ }
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::noteOn(byte note, byte velocity) {
+ // Do not start a not unless there is an instrument set up
+ if (!_instrument.data) {
+ return;
+ }
+
+ // Allocate a voice channel
+ VoiceChannel *voice = _owner->allocateVoice(_priority);
+ if (!voice) {
+ return;
+ }
+ addVoice(voice);
+
+ voice->note = note;
+ // This completly ignores the note's volume, but is in accordance
+ // to the original.
+ voice->out.volume = _volume;
+
+ // Set up the instrument data
+ voice->out.baseFrequency = _instrument.baseFrequency;
+ voice->out.soundStart = _instrument.data;
+ voice->out.soundEnd = _instrument.data + _instrument.length;
+ if (_instrument.loopEnd && _instrument.loopEnd - 12 > _instrument.loopStart) {
+ voice->out.loopStart = _instrument.data + _instrument.loopStart;
+ voice->out.loopEnd = _instrument.data + _instrument.loopEnd;
+ } else {
+ voice->out.loopStart = 0;
+ voice->out.loopEnd = voice->out.soundEnd;
+ }
+
+ voice->out.start = voice->out.loopStart;
+ voice->out.end = voice->out.loopEnd;
+
+ // Set up the pitch
+ _owner->setPitch(&voice->out, (note << 7) + _pitchBend);
+
+ // Set up the sample position
+ voice->out.instrument = voice->out.soundStart;
+ voice->out.subPos = 0;
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::programChange(byte program) {
+ _instrument = _owner->getInstrument(program + kProgramChangeBase);
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::pitchBend(int16 bend) {
+ _pitchBend = (bend * _pitchBendFactor) >> 6;
+ for (VoiceChannel *i = _voice; i; i = i->next) {
+ _owner->setPitch(&i->out, (i->note << 7) + _pitchBend);
+ }
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::controlChange(byte control, byte value) {
+ switch (control) {
+ // volume change
+ case 7:
+ _volume = value;
+ for (VoiceChannel *i = _voice; i; i = i->next) {
+ i->out.volume = value;
+ i->out.isFinished = false;
+ }
+ break;
+
+ // sustain
+ case 64:
+ _sustain = value;
+ if (!_sustain) {
+ for (VoiceChannel *i = _voice; i; i = i->next) {
+ if (i->sustainNoteOff) {
+ i->off();
+ }
+ }
+ }
+ break;
+
+ // all notes off
+ case 123:
+ for (VoiceChannel *i = _voice; i; i = i->next) {
+ i->off();
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::pitchBendFactor(byte value) {
+ _pitchBendFactor = value;
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::priority(byte value) {
+ _priority = value;
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::sysEx_customInstrument(uint32 type, const byte *instr) {
+ assert(instr);
+ if (type == 'MAC ') {
+ _instrument = _owner->getInstrument(*instr + kSysExBase);
+ }
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::init(MacM68kDriver *owner, byte channel) {
+ _owner = owner;
+ _number = channel;
+ _allocated = false;
+}
+
+bool MacM68kDriver::MidiChannel_MacM68k::allocate() {
+ if (_allocated) {
+ return false;
+ }
+
+ _allocated = true;
+ _voice = 0;
+ _priority = 0;
+ memset(&_instrument, 0, sizeof(_instrument));
+ _pitchBend = 0;
+ _pitchBendFactor = 0;
+ _volume = 0;
+ return true;
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::addVoice(VoiceChannel *voice) {
+ voice->next = _voice;
+ voice->prev = 0;
+ voice->part = this;
+ if (_voice) {
+ _voice->prev = voice;
+ }
+ _voice = voice;
+}
+
+void MacM68kDriver::MidiChannel_MacM68k::removeVoice(VoiceChannel *voice) {
+ VoiceChannel *i = _voice;
+ while (i && i != voice) {
+ i = i->next;
+ }
+
+ if (i) {
+ if (i->next) {
+ i->next->prev = i->prev;
+ }
+
+ if (i->prev) {
+ i->prev->next = i->next;
+ } else {
+ _voice = i->next;
+ }
+ }
+}
+
+MacM68kDriver::VoiceChannel *MacM68kDriver::allocateVoice(int priority) {
+ VoiceChannel *channel = 0;
+ for (int i = 0; i < kChannelCount; ++i) {
+ if (++_lastUsedVoiceChannel == kChannelCount) {
+ _lastUsedVoiceChannel = 0;
+ }
+
+ VoiceChannel *cur = &_voiceChannels[_lastUsedVoiceChannel];
+ if (!cur->part) {
+ memset(cur, 0, sizeof(*cur));
+ return cur;
+ } else if (!cur->next) {
+ if (cur->part->_priority <= priority) {
+ priority = cur->part->_priority;
+ channel = cur;
+ }
+ }
+ }
+
+ if (channel) {
+ channel->off();
+ memset(channel, 0, sizeof(*channel));
+ }
+
+ return channel;
+}
+
+const int MacM68kDriver::_volumeBaseTable[32] = {
+ 0, 0, 1, 1, 2, 3, 5, 6,
+ 8, 11, 13, 16, 19, 22, 26, 30,
+ 34, 38, 43, 48, 53, 58, 64, 70,
+ 76, 83, 89, 96, 104, 111, 119, 127
+};
+
+} // End of namespace Scumm
diff --git a/engines/scumm/imuse/mac_m68k.h b/engines/scumm/imuse/mac_m68k.h
new file mode 100644
index 0000000000..59e2f68b9b
--- /dev/null
+++ b/engines/scumm/imuse/mac_m68k.h
@@ -0,0 +1,177 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef SCUMM_IMUSE_MAC_M68K_H
+#define SCUMM_IMUSE_MAC_M68K_H
+
+#include "audio/softsynth/emumidi.h"
+
+#include "common/hashmap.h"
+
+namespace Common {
+class SeekableReadStream;
+}
+
+namespace Scumm {
+
+class MacM68kDriver : public MidiDriver_Emulated {
+ friend class MidiChannel_MacM68k;
+public:
+ MacM68kDriver(Audio::Mixer *mixer);
+ ~MacM68kDriver();
+
+ virtual int open();
+ virtual void close();
+
+ virtual void send(uint32 d);
+ virtual void sysEx_customInstrument(byte channel, uint32 type, const byte *instr);
+
+ virtual MidiChannel *allocateChannel();
+ virtual MidiChannel *getPercussionChannel() { return 0; }
+
+ virtual bool isStereo() const { return false; }
+ virtual int getRate() const {
+ // The original is using a frequency of approx. 22254.54546 here.
+ // To be precise it uses the 16.16 fixed point value 0x56EE8BA3.
+ return 22254;
+ }
+
+protected:
+ virtual void generateSamples(int16 *buf, int len);
+ virtual void onTimer() {}
+
+private:
+ int *_mixBuffer;
+ int _mixBufferLength;
+
+ struct Instrument {
+ uint length;
+ uint sampleRate;
+ uint loopStart;
+ uint loopEnd;
+ int baseFrequency;
+
+ byte *data;
+ };
+
+ enum {
+ kDefaultInstrument = 0x3E7,
+ kProgramChangeBase = 0x3E8,
+ kSysExBase = 0x7D0
+ };
+
+ Instrument getInstrument(int idx) const;
+ typedef Common::HashMap<int, Instrument> InstrumentMap;
+ InstrumentMap _instruments;
+ Instrument _defaultInstrument;
+ void loadAllInstruments();
+ void addInstrument(int idx, Common::SeekableReadStream *data);
+
+ struct OutputChannel {
+ int pitchModifier;
+
+ const byte *instrument;
+ uint subPos;
+
+ const byte *start;
+ const byte *end;
+
+ const byte *soundStart;
+ const byte *soundEnd;
+ const byte *loopStart;
+ const byte *loopEnd;
+
+ int frequency;
+ int volume;
+
+ bool isFinished;
+
+ int baseFrequency;
+ };
+
+ void setPitch(OutputChannel *out, int frequency);
+ int _pitchTable[128];
+
+ byte *_volumeTable;
+ static const int _volumeBaseTable[32];
+
+ class MidiChannel_MacM68k;
+
+ struct VoiceChannel {
+ MidiChannel_MacM68k *part;
+ VoiceChannel *prev, *next;
+ int channel;
+ int note;
+ bool sustainNoteOff;
+ OutputChannel out;
+
+ void off();
+ };
+
+ class MidiChannel_MacM68k : public MidiChannel {
+ friend class MacM68kDriver;
+ public:
+ virtual MidiDriver *device() { return _owner; }
+ virtual byte getNumber() { return _number; }
+ virtual void release();
+
+ virtual void send(uint32 b);
+ virtual void noteOff(byte note);
+ virtual void noteOn(byte note, byte velocity);
+ virtual void programChange(byte program);
+ virtual void pitchBend(int16 bend);
+ virtual void controlChange(byte control, byte value);
+ virtual void pitchBendFactor(byte value);
+ virtual void priority(byte value);
+ virtual void sysEx_customInstrument(uint32 type, const byte *instr);
+
+ void init(MacM68kDriver *owner, byte channel);
+ bool allocate();
+
+ void addVoice(VoiceChannel *voice);
+ void removeVoice(VoiceChannel *voice);
+ private:
+ MacM68kDriver *_owner;
+ bool _allocated;
+ int _number;
+
+ VoiceChannel *_voice;
+ int _priority;
+ int _sustain;
+ Instrument _instrument;
+ int _pitchBend;
+ int _pitchBendFactor;
+ int _volume;
+ };
+
+ MidiChannel_MacM68k _channels[32];
+
+ enum {
+ kChannelCount = 8
+ };
+ VoiceChannel _voiceChannels[kChannelCount];
+ int _lastUsedVoiceChannel;
+ VoiceChannel *allocateVoice(int priority);
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/imuse/sysex_scumm.cpp b/engines/scumm/imuse/sysex_scumm.cpp
index 85ffc86f47..8f230ebac3 100644
--- a/engines/scumm/imuse/sysex_scumm.cpp
+++ b/engines/scumm/imuse/sysex_scumm.cpp
@@ -71,7 +71,7 @@ void sysexHandler_Scumm(Player *player, const byte *msg, uint16 len) {
part->set_pri(buf[2]);
part->volume(buf[3]);
part->set_pan(buf[4]);
- part->_percussion = player->_isMIDI ? ((buf[5] & 0x80) > 0) : false;
+ part->_percussion = player->_supportsPercussion ? ((buf[5] & 0x80) > 0) : false;
part->set_transpose(buf[5]);
part->set_detune(buf[6]);
part->pitchBendFactor(buf[7]);
diff --git a/engines/scumm/midiparser_ro.cpp b/engines/scumm/midiparser_ro.cpp
index 1a31d1ca82..8549a9262d 100644
--- a/engines/scumm/midiparser_ro.cpp
+++ b/engines/scumm/midiparser_ro.cpp
@@ -62,13 +62,13 @@ void MidiParser_RO::parseNextEvent (EventInfo &info) {
info.delta = 0;
do {
- info.start = _position._play_pos;
- info.event = *(_position._play_pos++);
+ info.start = _position._playPos;
+ info.event = *(_position._playPos++);
if (info.command() == 0xA) {
++_lastMarkerCount;
info.event = 0xF0;
} else if (info.event == 0xF0 || info.event == 0xF1) {
- byte delay = *(_position._play_pos++);
+ byte delay = *(_position._playPos++);
info.delta += delay;
if (info.event == 0xF1) {
// This event is, as far as we have been able
@@ -95,16 +95,16 @@ void MidiParser_RO::parseNextEvent (EventInfo &info) {
if (info.event < 0x80)
return;
- _position._running_status = info.event;
+ _position._runningStatus = info.event;
switch (info.command()) {
case 0xC:
- info.basic.param1 = *(_position._play_pos++);
+ info.basic.param1 = *(_position._playPos++);
info.basic.param2 = 0;
break;
case 0x8: case 0x9: case 0xB:
- info.basic.param1 = *(_position._play_pos++);
- info.basic.param2 = *(_position._play_pos++);
+ info.basic.param1 = *(_position._playPos++);
+ info.basic.param2 = *(_position._playPos++);
if (info.command() == 0x9 && info.basic.param2 == 0)
info.event = info.channel() | 0x80;
info.length = 0;
@@ -133,7 +133,7 @@ bool MidiParser_RO::loadMusic (byte *data, uint32 size) {
return false;
}
- _num_tracks = 1;
+ _numTracks = 1;
_ppqn = 120;
_tracks[0] = pos + 2;
_markerCount = _lastMarkerCount = 0;
diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk
index 1f219f5187..8499c9bad3 100644
--- a/engines/scumm/module.mk
+++ b/engines/scumm/module.mk
@@ -27,6 +27,7 @@ MODULE_OBJS := \
imuse/imuse_part.o \
imuse/imuse_player.o \
imuse/instrument.o \
+ imuse/mac_m68k.o \
imuse/pcspk.o \
imuse/sysex_samnmax.o \
imuse/sysex_scumm.o \
diff --git a/engines/scumm/object.cpp b/engines/scumm/object.cpp
index 399cd91324..77c75c4ad6 100644
--- a/engines/scumm/object.cpp
+++ b/engines/scumm/object.cpp
@@ -335,7 +335,7 @@ int ScummEngine::whereIsObject(int object) const {
return WIO_NOT_FOUND;
if ((_game.version != 0 || OBJECT_V0_TYPE(object) == 0) &&
- _objectOwnerTable[object] != OF_OWNER_ROOM)
+ _objectOwnerTable[object] != OF_OWNER_ROOM)
{
for (i = 0; i < _numInventory; i++)
if (_inventory[i] == object)
@@ -1225,7 +1225,7 @@ byte *ScummEngine::getOBCDFromObject(int obj, bool v0CheckInventory) {
byte *ptr;
if ((_game.version != 0 || OBJECT_V0_TYPE(obj) == 0) &&
- _objectOwnerTable[obj] != OF_OWNER_ROOM)
+ _objectOwnerTable[obj] != OF_OWNER_ROOM)
{
if (_game.version == 0 && !v0CheckInventory)
return 0;
diff --git a/engines/scumm/player_apple2.cpp b/engines/scumm/player_apple2.cpp
index a8e150caa9..58e4f78a94 100644
--- a/engines/scumm/player_apple2.cpp
+++ b/engines/scumm/player_apple2.cpp
@@ -61,8 +61,8 @@ public:
private:
void _update(int interval /*a*/, int count /*y*/) { // D076
- assert(interval > 0); // 0 == 256?
- assert(count > 0); // 0 == 256?
+ assert(interval > 0); // 0 == 256?
+ assert(count > 0); // 0 == 256?
for (; count >= 0; --count) {
_player->speakerToggle();
@@ -99,7 +99,7 @@ public:
++_pos;
return false;
- }
+ }
return true;
}
@@ -112,7 +112,7 @@ private:
assert(interval > 0); // 0 == 256?
int a = (interval >> 3) + count;
- for (int y = a; y > 0; --y) {
+ for (int y = a; y > 0; --y) {
_player->generateSamples(1292 - 5*interval);
_player->speakerToggle();
@@ -206,7 +206,7 @@ private:
_bitmask1 = 0x3;
_bitmask2 = 0x3;
-
+
_updateInterval2 = param0;
if (_updateInterval2 == 0)
_bitmask2 = 0x0;
@@ -234,9 +234,9 @@ private:
if (_updateRemain2 == 0) {
_updateRemain2 = _updateInterval2;
- // use only first voice's data (bitmask1) if both voices are triggered
+ // use only first voice's data (bitmask1) if both voices are triggered
if (_updateRemain1 != 0) {
- _speakerShiftReg ^= _bitmask2;
+ _speakerShiftReg ^= _bitmask2;
}
}
@@ -256,7 +256,7 @@ private:
protected:
const byte *_params;
-
+
byte _updateRemain1;
byte _updateRemain2;
@@ -309,7 +309,7 @@ private:
for (int i = count; i > 0; --i) {
_player->generateSamples(10 + 5*interval);
_player->speakerToggle();
-
+
_player->generateSamples(5 + 5*interval);
_player->speakerToggle();
}
@@ -332,20 +332,20 @@ private:
// LD000[loc] ^ LD00A[loc]
const byte AppleII_SoundFunction5_Noise::_noiseTable[256] = {
- 0x65, 0x1b, 0xda, 0x11, 0x61, 0xe5, 0x77, 0x57, 0x92, 0xc8, 0x51, 0x1c, 0xd4, 0x91, 0x62, 0x63,
- 0x00, 0x38, 0x57, 0xd5, 0x18, 0xd8, 0xdc, 0x40, 0x03, 0x86, 0xd3, 0x2f, 0x10, 0x11, 0xd8, 0x3c,
- 0xbe, 0x00, 0x19, 0xc5, 0xd2, 0xc3, 0xca, 0x34, 0x00, 0x28, 0xbf, 0xb9, 0x18, 0x20, 0x01, 0xcc,
- 0xda, 0x08, 0xbc, 0x75, 0x7c, 0xb0, 0x8d, 0xe0, 0x09, 0x18, 0xbf, 0x5d, 0xe9, 0x8c, 0x75, 0x64,
+ 0x65, 0x1b, 0xda, 0x11, 0x61, 0xe5, 0x77, 0x57, 0x92, 0xc8, 0x51, 0x1c, 0xd4, 0x91, 0x62, 0x63,
+ 0x00, 0x38, 0x57, 0xd5, 0x18, 0xd8, 0xdc, 0x40, 0x03, 0x86, 0xd3, 0x2f, 0x10, 0x11, 0xd8, 0x3c,
+ 0xbe, 0x00, 0x19, 0xc5, 0xd2, 0xc3, 0xca, 0x34, 0x00, 0x28, 0xbf, 0xb9, 0x18, 0x20, 0x01, 0xcc,
+ 0xda, 0x08, 0xbc, 0x75, 0x7c, 0xb0, 0x8d, 0xe0, 0x09, 0x18, 0xbf, 0x5d, 0xe9, 0x8c, 0x75, 0x64,
0xe5, 0xb5, 0x5d, 0xe0, 0xb7, 0x7d, 0xe9, 0x8c, 0x55, 0x65, 0xc5, 0xb5, 0x5d, 0xd8, 0x09, 0x0d,
- 0x64, 0xf0, 0xf0, 0x08, 0x63, 0x03, 0x00, 0x55, 0x35, 0xc0, 0x00, 0x20, 0x74, 0xa5, 0x1e, 0xe3,
- 0x00, 0x06, 0x3c, 0x52, 0xd1, 0x70, 0xd0, 0x57, 0x02, 0xf0, 0x00, 0xb6, 0xfc, 0x02, 0x11, 0x9a,
- 0x3b, 0xc8, 0x38, 0xdf, 0x1a, 0xb0, 0xd1, 0xb8, 0xd0, 0x18, 0x8a, 0x4a, 0xea, 0x1b, 0x12, 0x5d,
- 0x29, 0x58, 0xd8, 0x43, 0xb8, 0x2d, 0xd2, 0x61, 0x10, 0x3c, 0x0c, 0x5d, 0x1b, 0x61, 0x10, 0x3c,
+ 0x64, 0xf0, 0xf0, 0x08, 0x63, 0x03, 0x00, 0x55, 0x35, 0xc0, 0x00, 0x20, 0x74, 0xa5, 0x1e, 0xe3,
+ 0x00, 0x06, 0x3c, 0x52, 0xd1, 0x70, 0xd0, 0x57, 0x02, 0xf0, 0x00, 0xb6, 0xfc, 0x02, 0x11, 0x9a,
+ 0x3b, 0xc8, 0x38, 0xdf, 0x1a, 0xb0, 0xd1, 0xb8, 0xd0, 0x18, 0x8a, 0x4a, 0xea, 0x1b, 0x12, 0x5d,
+ 0x29, 0x58, 0xd8, 0x43, 0xb8, 0x2d, 0xd2, 0x61, 0x10, 0x3c, 0x0c, 0x5d, 0x1b, 0x61, 0x10, 0x3c,
0x0a, 0x5d, 0x1d, 0x61, 0x10, 0x3c, 0x0b, 0x19, 0x88, 0x21, 0xc0, 0x21, 0x07, 0x00, 0x65, 0x62,
- 0x08, 0xe9, 0x36, 0x40, 0x20, 0x41, 0x06, 0x00, 0x20, 0x00, 0x00, 0xed, 0xa3, 0x00, 0x88, 0x06,
- 0x98, 0x01, 0x5d, 0x7f, 0x02, 0x1d, 0x78, 0x03, 0x60, 0xcb, 0x3a, 0x01, 0xbd, 0x78, 0x02, 0x5d,
- 0x7e, 0x03, 0x1d, 0xf5, 0xa6, 0x40, 0x81, 0xb4, 0xd0, 0x8d, 0xd3, 0xd0, 0x6d, 0xd5, 0x61, 0x48,
- 0x61, 0x4d, 0xd1, 0xc8, 0xb1, 0xd8, 0x69, 0xff, 0x61, 0xd9, 0xed, 0xa0, 0xfe, 0x19, 0x91, 0x37,
+ 0x08, 0xe9, 0x36, 0x40, 0x20, 0x41, 0x06, 0x00, 0x20, 0x00, 0x00, 0xed, 0xa3, 0x00, 0x88, 0x06,
+ 0x98, 0x01, 0x5d, 0x7f, 0x02, 0x1d, 0x78, 0x03, 0x60, 0xcb, 0x3a, 0x01, 0xbd, 0x78, 0x02, 0x5d,
+ 0x7e, 0x03, 0x1d, 0xf5, 0xa6, 0x40, 0x81, 0xb4, 0xd0, 0x8d, 0xd3, 0xd0, 0x6d, 0xd5, 0x61, 0x48,
+ 0x61, 0x4d, 0xd1, 0xc8, 0xb1, 0xd8, 0x69, 0xff, 0x61, 0xd9, 0xed, 0xa0, 0xfe, 0x19, 0x91, 0x37,
0x19, 0x37, 0x00, 0xf1, 0x00, 0x01, 0x1f, 0x00, 0xad, 0xc1, 0x01, 0x01, 0x2e, 0x00, 0x40, 0xc6,
0x7a, 0x9b, 0x95, 0x43, 0xfc, 0x18, 0xd2, 0x9e, 0x2a, 0x5a, 0x4b, 0x2a, 0xb6, 0x87, 0x30, 0x6c
};
@@ -394,20 +394,20 @@ void Player_AppleII::startSound(int nr) {
case 0: // empty (nothing to play)
resetState();
return;
- case 1:
- _soundFunc = new AppleII_SoundFunction1_FreqUpDown();
+ case 1:
+ _soundFunc = new AppleII_SoundFunction1_FreqUpDown();
break;
- case 2:
- _soundFunc = new AppleII_SoundFunction2_SymmetricWave();
+ case 2:
+ _soundFunc = new AppleII_SoundFunction2_SymmetricWave();
break;
- case 3:
- _soundFunc = new AppleII_SoundFunction3_AsymmetricWave();
+ case 3:
+ _soundFunc = new AppleII_SoundFunction3_AsymmetricWave();
break;
- case 4:
- _soundFunc = new AppleII_SoundFunction4_Polyphone();
+ case 4:
+ _soundFunc = new AppleII_SoundFunction4_Polyphone();
break;
- case 5:
- _soundFunc = new AppleII_SoundFunction5_Noise();
+ case 5:
+ _soundFunc = new AppleII_SoundFunction5_Noise();
break;
}
_soundFunc->init(this, _params);
@@ -484,7 +484,7 @@ int Player_AppleII::readBuffer(int16 *buffer, const int numSamples) {
// toggle speaker on/off
void Player_AppleII::speakerToggle() {
- _speakerState ^= 0x1;
+ _speakerState ^= 0x1;
}
void Player_AppleII::generateSamples(int cycles) {
@@ -492,8 +492,8 @@ void Player_AppleII::generateSamples(int cycles) {
}
void Player_AppleII::wait(int interval, int count /*y*/) {
- assert(count > 0); // 0 == 256?
- assert(interval > 0); // 0 == 256?
+ assert(count > 0); // 0 == 256?
+ assert(interval > 0); // 0 == 256?
generateSamples(11 + count*(8 + 5 * interval));
}
diff --git a/engines/scumm/player_apple2.h b/engines/scumm/player_apple2.h
index b4a7d409fb..e1ec9d8946 100644
--- a/engines/scumm/player_apple2.h
+++ b/engines/scumm/player_apple2.h
@@ -36,7 +36,7 @@ namespace Scumm {
class ScummEngine;
/*
- * Optimized for use with periodical read/write phases when the buffer
+ * Optimized for use with periodical read/write phases when the buffer
* is filled in a write phase and completely read in a read phase.
* The growing strategy is optimized for repeated small (e.g. 2 bytes)
* single writes resulting in large buffers
@@ -133,7 +133,7 @@ static const double APPLEII_CPU_CLOCK = 1020484.5; // ~ 1.02 MHz
/*
* Converts the 1-bit speaker state values into audio samples.
- * This is done by aggregation of the speaker states at each
+ * This is done by aggregation of the speaker states at each
* CPU cycle in a sampling period into an audio sample.
*/
class SampleConverter {
@@ -144,7 +144,7 @@ private:
}
public:
- SampleConverter() :
+ SampleConverter() :
_cyclesPerSampleFP(0),
_missingCyclesFP(0),
_sampleCyclesSumFP(0),
@@ -156,7 +156,7 @@ public:
void reset() {
_missingCyclesFP = 0;
_sampleCyclesSumFP = 0;
- _buffer.clear();
+ _buffer.clear();
}
uint32 availableSize() const {
@@ -245,7 +245,7 @@ public:
virtual void setMusicVolume(int vol) { _sampleConverter.setMusicVolume(vol); }
void setSampleRate(int rate) {
_sampleRate = rate;
- _sampleConverter.setSampleRate(rate);
+ _sampleConverter.setSampleRate(rate);
}
virtual void startSound(int sound);
virtual void stopSound(int sound);
diff --git a/engines/scumm/player_towns.cpp b/engines/scumm/player_towns.cpp
index 2588026e59..33e3e40e39 100644
--- a/engines/scumm/player_towns.cpp
+++ b/engines/scumm/player_towns.cpp
@@ -87,7 +87,7 @@ void Player_Towns::restoreAfterLoad() {
if (!_v2)
restoredSounds.push_back(_pcmCurrentSound[i].index);
-
+
uint8 *ptr = _vm->getResourceAddress(rtSound, _pcmCurrentSound[i].index);
if (!ptr)
continue;
diff --git a/engines/scumm/player_v2cms.cpp b/engines/scumm/player_v2cms.cpp
index d4b21774ed..c1242e0645 100644
--- a/engines/scumm/player_v2cms.cpp
+++ b/engines/scumm/player_v2cms.cpp
@@ -718,38 +718,38 @@ void Player_V2CMS::playMusicChips(const MusicChip *table) {
}
const Player_V2CMS::MidiNote Player_V2CMS::_midiNotes[132] = {
- { 3, 0 }, { 31, 0 }, { 58, 0 }, { 83, 0 },
- { 107, 0 }, { 130, 0 }, { 151, 0 }, { 172, 0 },
- { 191, 0 }, { 209, 0 }, { 226, 0 }, { 242, 0 },
- { 3, 1 }, { 31, 1 }, { 58, 1 }, { 83, 1 },
- { 107, 1 }, { 130, 1 }, { 151, 1 }, { 172, 1 },
- { 191, 1 }, { 209, 1 }, { 226, 1 }, { 242, 1 },
- { 3, 2 }, { 31, 2 }, { 58, 2 }, { 83, 2 },
- { 107, 2 }, { 130, 2 }, { 151, 2 }, { 172, 2 },
- { 191, 2 }, { 209, 2 }, { 226, 2 }, { 242, 2 },
- { 3, 3 }, { 31, 3 }, { 58, 3 }, { 83, 3 },
- { 107, 3 }, { 130, 3 }, { 151, 3 }, { 172, 3 },
- { 191, 3 }, { 209, 3 }, { 226, 3 }, { 242, 3 },
- { 3, 4 }, { 31, 4 }, { 58, 4 }, { 83, 4 },
- { 107, 4 }, { 130, 4 }, { 151, 4 }, { 172, 4 },
- { 191, 4 }, { 209, 4 }, { 226, 4 }, { 242, 4 },
- { 3, 5 }, { 31, 5 }, { 58, 5 }, { 83, 5 },
- { 107, 5 }, { 130, 5 }, { 151, 5 }, { 172, 5 },
- { 191, 5 }, { 209, 5 }, { 226, 5 }, { 242, 5 },
- { 3, 6 }, { 31, 6 }, { 58, 6 }, { 83, 6 },
- { 107, 6 }, { 130, 6 }, { 151, 6 }, { 172, 6 },
- { 191, 6 }, { 209, 6 }, { 226, 6 }, { 242, 6 },
- { 3, 7 }, { 31, 7 }, { 58, 7 }, { 83, 7 },
- { 107, 7 }, { 130, 7 }, { 151, 7 }, { 172, 7 },
- { 191, 7 }, { 209, 7 }, { 226, 7 }, { 242, 7 },
- { 3, 8 }, { 31, 8 }, { 58, 8 }, { 83, 8 },
- { 107, 8 }, { 130, 8 }, { 151, 8 }, { 172, 8 },
- { 191, 8 }, { 209, 8 }, { 226, 8 }, { 242, 8 },
- { 3, 9 }, { 31, 9 }, { 58, 9 }, { 83, 9 },
- { 107, 9 }, { 130, 9 }, { 151, 9 }, { 172, 9 },
- { 191, 9 }, { 209, 9 }, { 226, 9 }, { 242, 9 },
- { 3, 10 }, { 31, 10 }, { 58, 10 }, { 83, 10 },
- { 107, 10 }, { 130, 10 }, { 151, 10 }, { 172, 10 },
+ { 3, 0 }, { 31, 0 }, { 58, 0 }, { 83, 0 },
+ { 107, 0 }, { 130, 0 }, { 151, 0 }, { 172, 0 },
+ { 191, 0 }, { 209, 0 }, { 226, 0 }, { 242, 0 },
+ { 3, 1 }, { 31, 1 }, { 58, 1 }, { 83, 1 },
+ { 107, 1 }, { 130, 1 }, { 151, 1 }, { 172, 1 },
+ { 191, 1 }, { 209, 1 }, { 226, 1 }, { 242, 1 },
+ { 3, 2 }, { 31, 2 }, { 58, 2 }, { 83, 2 },
+ { 107, 2 }, { 130, 2 }, { 151, 2 }, { 172, 2 },
+ { 191, 2 }, { 209, 2 }, { 226, 2 }, { 242, 2 },
+ { 3, 3 }, { 31, 3 }, { 58, 3 }, { 83, 3 },
+ { 107, 3 }, { 130, 3 }, { 151, 3 }, { 172, 3 },
+ { 191, 3 }, { 209, 3 }, { 226, 3 }, { 242, 3 },
+ { 3, 4 }, { 31, 4 }, { 58, 4 }, { 83, 4 },
+ { 107, 4 }, { 130, 4 }, { 151, 4 }, { 172, 4 },
+ { 191, 4 }, { 209, 4 }, { 226, 4 }, { 242, 4 },
+ { 3, 5 }, { 31, 5 }, { 58, 5 }, { 83, 5 },
+ { 107, 5 }, { 130, 5 }, { 151, 5 }, { 172, 5 },
+ { 191, 5 }, { 209, 5 }, { 226, 5 }, { 242, 5 },
+ { 3, 6 }, { 31, 6 }, { 58, 6 }, { 83, 6 },
+ { 107, 6 }, { 130, 6 }, { 151, 6 }, { 172, 6 },
+ { 191, 6 }, { 209, 6 }, { 226, 6 }, { 242, 6 },
+ { 3, 7 }, { 31, 7 }, { 58, 7 }, { 83, 7 },
+ { 107, 7 }, { 130, 7 }, { 151, 7 }, { 172, 7 },
+ { 191, 7 }, { 209, 7 }, { 226, 7 }, { 242, 7 },
+ { 3, 8 }, { 31, 8 }, { 58, 8 }, { 83, 8 },
+ { 107, 8 }, { 130, 8 }, { 151, 8 }, { 172, 8 },
+ { 191, 8 }, { 209, 8 }, { 226, 8 }, { 242, 8 },
+ { 3, 9 }, { 31, 9 }, { 58, 9 }, { 83, 9 },
+ { 107, 9 }, { 130, 9 }, { 151, 9 }, { 172, 9 },
+ { 191, 9 }, { 209, 9 }, { 226, 9 }, { 242, 9 },
+ { 3, 10 }, { 31, 10 }, { 58, 10 }, { 83, 10 },
+ { 107, 10 }, { 130, 10 }, { 151, 10 }, { 172, 10 },
{ 191, 10 }, { 209, 10 }, { 226, 10 }, { 242, 10 }
};
diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index beac077fd1..72896e097a 100644
--- a/engines/scumm/saveload.cpp
+++ b/engines/scumm/saveload.cpp
@@ -1298,7 +1298,7 @@ void ScummEngine::saveOrLoad(Serializer *s) {
s->saveLoadArrayOf(_16BitPalette, 512, sizeof(_16BitPalette[0]), sleUint16);
}
-
+
// FM-Towns specific (extra palette data, color cycle data, etc.)
// In earlier save game versions (below 87) the FM-Towns specific data would get saved (and loaded) even in non FM-Towns games.
// This would cause an unnecessary save file incompatibility between DS (which uses the DISABLE_TOWNS_DUAL_LAYER_MODE setting)
diff --git a/engines/scumm/saveload.h b/engines/scumm/saveload.h
index d5f7ea526e..a640bc1e17 100644
--- a/engines/scumm/saveload.h
+++ b/engines/scumm/saveload.h
@@ -47,7 +47,7 @@ namespace Scumm {
* only saves/loads those which are valid for the version of the savegame
* which is being loaded/saved currently.
*/
-#define CURRENT_VER 92
+#define CURRENT_VER 93
/**
* An auxillary macro, used to specify savegame versions. We use this instead
diff --git a/engines/scumm/script_v0.cpp b/engines/scumm/script_v0.cpp
index 44b77f1d18..361287d29f 100644
--- a/engines/scumm/script_v0.cpp
+++ b/engines/scumm/script_v0.cpp
@@ -602,7 +602,7 @@ void ScummEngine_v0::o_loadRoomWithEgo() {
x = r.x;
y = r.y;
a->putActor(x, y, _currentRoom);
-
+
camera._dest.x = camera._cur.x = a->getPos().x;
setCameraAt(a->getPos().x, a->getPos().y);
setCameraFollows(a);
@@ -635,18 +635,18 @@ void ScummEngine_v0::setMode(byte mode) {
case kModeCutscene:
_redrawSentenceLine = false;
// Note: do not change freeze state here
- state = USERSTATE_SET_IFACE |
+ state = USERSTATE_SET_IFACE |
USERSTATE_SET_CURSOR;
break;
case kModeKeypad:
_redrawSentenceLine = false;
- state = USERSTATE_SET_IFACE |
+ state = USERSTATE_SET_IFACE |
USERSTATE_SET_CURSOR | USERSTATE_CURSOR_ON |
USERSTATE_SET_FREEZE | USERSTATE_FREEZE_ON;
break;
case kModeNormal:
case kModeNoNewKid:
- state = USERSTATE_SET_IFACE | USERSTATE_IFACE_ALL |
+ state = USERSTATE_SET_IFACE | USERSTATE_IFACE_ALL |
USERSTATE_SET_CURSOR | USERSTATE_CURSOR_ON |
USERSTATE_SET_FREEZE;
break;
@@ -688,7 +688,7 @@ void ScummEngine_v0::o_animateActor() {
Actor_v0 *a = (Actor_v0*) derefActor(act, "o_animateActor");
a->_animFrameRepeat = repeat;
-
+
switch (anim) {
case 0xFE:
@@ -700,7 +700,7 @@ void ScummEngine_v0::o_animateActor() {
// 0x69A3
a->_speaking = 0x00;
return;
-
+
case 0xFF:
a->stopActorMoving();
return;
diff --git a/engines/scumm/script_v2.cpp b/engines/scumm/script_v2.cpp
index ce162b4a6a..96d422d5bb 100644
--- a/engines/scumm/script_v2.cpp
+++ b/engines/scumm/script_v2.cpp
@@ -993,7 +993,7 @@ void ScummEngine_v2::o2_drawSentence() {
const byte *temp;
int slot = getVerbSlot(VAR(VAR_SENTENCE_VERB), 0);
- if (!((_userState & USERSTATE_IFACE_SENTENCE) ||
+ if (!((_userState & USERSTATE_IFACE_SENTENCE) ||
(_game.platform == Common::kPlatformNES && (_userState & USERSTATE_IFACE_ALL))))
return;
@@ -1486,8 +1486,8 @@ void ScummEngine_v2::o2_cutscene() {
VAR(VAR_CURSORSTATE) = 200;
// Hide inventory, freeze scripts, hide cursor
- setUserState(USERSTATE_SET_IFACE |
- USERSTATE_SET_CURSOR |
+ setUserState(USERSTATE_SET_IFACE |
+ USERSTATE_SET_CURSOR |
USERSTATE_SET_FREEZE | USERSTATE_FREEZE_ON);
_sentenceNum = 0;
diff --git a/engines/scumm/script_v5.cpp b/engines/scumm/script_v5.cpp
index a5591b701f..0bf51a2816 100644
--- a/engines/scumm/script_v5.cpp
+++ b/engines/scumm/script_v5.cpp
@@ -1097,7 +1097,7 @@ void ScummEngine_v5::o5_getDist() {
int r;
getResultPos();
-
+
o1 = getVarOrDirectWord(PARAM_1);
o2 = getVarOrDirectWord(PARAM_2);
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index d0f46f3e56..2c79fb8de0 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -73,6 +73,7 @@
#include "scumm/util.h"
#include "scumm/verbs.h"
#include "scumm/imuse/pcspk.h"
+#include "scumm/imuse/mac_m68k.h"
#include "backends/audiocd/audiocd.h"
@@ -1835,17 +1836,31 @@ void ScummEngine::setupMusic(int midi) {
} else if (_game.version >= 3 && _game.heversion <= 62) {
MidiDriver *nativeMidiDriver = 0;
MidiDriver *adlibMidiDriver = 0;
-
- if (_sound->_musicType != MDT_ADLIB && _sound->_musicType != MDT_TOWNS && _sound->_musicType != MDT_PCSPK)
+ bool multi_midi = ConfMan.getBool("multi_midi") && _sound->_musicType != MDT_NONE && _sound->_musicType != MDT_PCSPK && (midi & MDT_ADLIB);
+ bool useOnlyNative = false;
+
+ if (isMacM68kIMuse()) {
+ // We setup this driver as native MIDI driver to avoid playback
+ // of the Mac music via a selected MIDI device.
+ nativeMidiDriver = new MacM68kDriver(_mixer);
+ // The Mac driver is never MT-32.
+ _native_mt32 = false;
+ // Ignore non-native drivers. This also ignores the multi MIDI setting.
+ useOnlyNative = true;
+ } else if (_sound->_musicType != MDT_ADLIB && _sound->_musicType != MDT_TOWNS && _sound->_musicType != MDT_PCSPK) {
nativeMidiDriver = MidiDriver::createMidi(dev);
+ }
+
if (nativeMidiDriver != NULL && _native_mt32)
nativeMidiDriver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
- bool multi_midi = ConfMan.getBool("multi_midi") && _sound->_musicType != MDT_NONE && _sound->_musicType != MDT_PCSPK && (midi & MDT_ADLIB);
- if (_sound->_musicType == MDT_ADLIB || _sound->_musicType == MDT_TOWNS || multi_midi) {
- adlibMidiDriver = MidiDriver::createMidi(MidiDriver::detectDevice(_sound->_musicType == MDT_TOWNS ? MDT_TOWNS : MDT_ADLIB));
- adlibMidiDriver->property(MidiDriver::PROP_OLD_ADLIB, (_game.features & GF_SMALL_HEADER) ? 1 : 0);
- } else if (_sound->_musicType == MDT_PCSPK) {
- adlibMidiDriver = new PcSpkDriver(_mixer);
+
+ if (!useOnlyNative) {
+ if (_sound->_musicType == MDT_ADLIB || _sound->_musicType == MDT_TOWNS || multi_midi) {
+ adlibMidiDriver = MidiDriver::createMidi(MidiDriver::detectDevice(_sound->_musicType == MDT_TOWNS ? MDT_TOWNS : MDT_ADLIB));
+ adlibMidiDriver->property(MidiDriver::PROP_OLD_ADLIB, (_game.features & GF_SMALL_HEADER) ? 1 : 0);
+ } else if (_sound->_musicType == MDT_PCSPK) {
+ adlibMidiDriver = new PcSpkDriver(_mixer);
+ }
}
_imuse = IMuse::create(_system, nativeMidiDriver, adlibMidiDriver);
@@ -1971,11 +1986,11 @@ Common::Error ScummEngine::go() {
if (delta < 1) // Ensure we don't get into an endless loop
delta = 1; // by not decreasing sleepers.
- // WORKAROUND: walking speed in the original v0/v1 interpreter
+ // WORKAROUND: walking speed in the original v0/v1 interpreter
// is sometimes slower (e.g. during scrolling) than in ScummVM.
// This is important for the door-closing action in the dungeon,
- // otherwise (delta < 6) a single kid is able to escape.
- if ((_game.version == 0 && isScriptRunning(132)) ||
+ // otherwise (delta < 6) a single kid is able to escape.
+ if ((_game.version == 0 && isScriptRunning(132)) ||
(_game.version == 1 && isScriptRunning(137)))
delta = 6;
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index c8cf096a19..a77c1c0141 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -150,7 +150,13 @@ enum GameFeatures {
GF_HE_985 = 1 << 14,
/** HE games with 16 bit color */
- GF_16BIT_COLOR = 1 << 15
+ GF_16BIT_COLOR = 1 << 15,
+
+ /**
+ * SCUMM v5-v7 Mac games stored in a container file
+ * Used to differentiate between m68k and PPC versions of Indy4
+ */
+ GF_MAC_CONTAINER = 1 << 16
};
/* SCUMM Debug Channels */
@@ -713,6 +719,9 @@ public:
bool openFile(BaseScummFile &file, const Common::String &filename, bool resourceFile = false);
+ /** Is this game a Mac m68k v5 game with iMuse? */
+ bool isMacM68kIMuse() const;
+
protected:
int _resourceHeaderSize;
byte _resourceMapper[128];
@@ -1363,7 +1372,7 @@ public:
public:
bool towns_isRectInStringBox(int x1, int y1, int x2, int y2);
byte _townsPaletteFlags;
- byte _townsCharsetColorMap[16];
+ byte _townsCharsetColorMap[16];
protected:
void towns_drawStripToScreen(VirtScreen *vs, int dstX, int dstY, int srcX, int srcY, int w, int h);
diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp
index 1dc026ad52..a1cecfa0b3 100644
--- a/engines/scumm/sound.cpp
+++ b/engines/scumm/sound.cpp
@@ -248,7 +248,10 @@ void Sound::playSound(int soundID) {
_mixer->playStream(Audio::Mixer::kSFXSoundType, NULL, stream, soundID);
}
// Support for sampled sound effects in Monkey Island 1 and 2
- else if (_vm->_game.platform != Common::kPlatformFMTowns && READ_BE_UINT32(ptr) == MKTAG('S','B','L',' ')) {
+ else if (_vm->_game.platform != Common::kPlatformFMTowns
+ // The Macintosh m68k versions of MI2/Indy4 just ignore SBL effects.
+ && !_vm->isMacM68kIMuse()
+ && READ_BE_UINT32(ptr) == MKTAG('S','B','L',' ')) {
debugC(DEBUG_SOUND, "Using SBL sound effect");
// SBL resources essentially contain VOC sound data.
@@ -954,7 +957,7 @@ void Sound::setupSfxFile() {
if (file.open(tmp))
_sfxFilename = tmp;
-
+
if (_vm->_game.heversion <= 74)
_sfxFileEncByte = 0x69;
@@ -1179,7 +1182,7 @@ int ScummEngine::readSoundResource(ResId idx) {
// its sound resources, and Amiga games, which feature only ROL
// resources, since we are a doing Midi -> AdLib conversion for
// these.
- if ((_sound->_musicType == MDT_ADLIB || _sound->_musicType == MDT_TOWNS) && pri != 16
+ if ((_sound->_musicType == MDT_ADLIB || _sound->_musicType == MDT_TOWNS) && pri != 16
&& pri != 15 && pri != 10 && pri != 2 && _game.platform != Common::kPlatformAmiga)
pri = -1;
diff --git a/engines/scumm/verbs.cpp b/engines/scumm/verbs.cpp
index 567ca31485..0d0f6cdb95 100644
--- a/engines/scumm/verbs.cpp
+++ b/engines/scumm/verbs.cpp
@@ -84,7 +84,7 @@ int ScummEngine_v0::verbPrepIdType(int verbid) {
switch (verbid) {
case kVerbUse: // depends on object1
return kVerbPrepObject;
- case kVerbGive:
+ case kVerbGive:
return kVerbPrepTo;
case kVerbUnlock: case kVerbFix:
return kVerbPrepWith;
@@ -693,7 +693,7 @@ void ScummEngine_v0::verbExec() {
if (_activeVerb == kVerbWhatIs)
return;
-
+
if (!(_activeVerb == kVerbWalkTo && _activeObject == 0)) {
doSentence(_activeVerb, _activeObject, _activeObject2);
if (_activeVerb != kVerbWalkTo) {
diff --git a/engines/sky/detection.cpp b/engines/sky/detection.cpp
index dfa3ded50b..8f6c2bb6a2 100644
--- a/engines/sky/detection.cpp
+++ b/engines/sky/detection.cpp
@@ -119,12 +119,12 @@ GameList SkyMetaEngine::getSupportedGames() const {
const ExtraGuiOptions SkyMetaEngine::getExtraGuiOptions(const Common::String &target) const {
Common::String guiOptions;
ExtraGuiOptions options;
-
+
if (target.empty()) {
options.push_back(skyExtraGuiOption);
return options;
}
-
+
if (ConfMan.hasKey("guioptions", target)) {
guiOptions = ConfMan.get("guioptions", target);
guiOptions = parseGameGUIOptions(guiOptions);
diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp
index f7add4eed2..ff3c897dba 100644
--- a/engines/sword1/animation.cpp
+++ b/engines/sword1/animation.cpp
@@ -69,7 +69,7 @@ static const char *const sequenceList[20] = {
};
// This is the list of the names of the PlayStation videos
-// TODO: fight.str, flashy.str,
+// TODO: fight.str, flashy.str,
static const char *const sequenceListPSX[20] = {
"e_ferr1",
"ladder1",
@@ -152,14 +152,14 @@ bool MoviePlayer::load(uint32 id) {
warning("%s:%d startFrame (%d) <= lastEnd (%d)", filename.c_str(), lineNo, startFrame, lastEnd);
continue;
}
-
+
int color = 0;
if (*ptr == '@') {
++ptr;
color = strtoul(ptr, const_cast<char **>(&ptr), 10);
while (*ptr && Common::isSpace(*ptr))
ptr++;
- }
+ }
_movieTexts.push_back(MovieText(startFrame, endFrame, ptr, color));
lastEnd = endFrame;
diff --git a/engines/sword1/control.cpp b/engines/sword1/control.cpp
index 6e395116f9..7cd85dff54 100644
--- a/engines/sword1/control.cpp
+++ b/engines/sword1/control.cpp
@@ -541,7 +541,9 @@ void Control::setupMainPanel() {
if (SwordEngine::_systemVars.controlPanelMode == CP_DEATHSCREEN)
panelId = SR_DEATHPANEL;
else {
- if (SwordEngine::_systemVars.language <= BS1_SPANISH)
+ if (SwordEngine::_systemVars.realLanguage == Common::EN_USA)
+ panelId = SR_PANEL_AMERICAN;
+ else if (SwordEngine::_systemVars.language <= BS1_SPANISH)
panelId = SR_PANEL_ENGLISH + SwordEngine::_systemVars.language;
else
panelId = SR_PANEL_ENGLISH;
diff --git a/engines/sword1/objectman.cpp b/engines/sword1/objectman.cpp
index 5d1864d58d..3e70a95699 100644
--- a/engines/sword1/objectman.cpp
+++ b/engines/sword1/objectman.cpp
@@ -107,7 +107,7 @@ char *ObjectMan::lockText(uint32 textId) {
warning("Missing translation for textId %u (\"%s\")", textId, text);
unlockText(textId, BS1_ENGLISH);
}
-
+
return _missingSubTitleStr;
}
return text;
@@ -164,7 +164,7 @@ char *ObjectMan::lockText(uint32 textId, uint8 lang) {
// 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 NULL;
}
diff --git a/engines/sword1/sword1.cpp b/engines/sword1/sword1.cpp
index 75e8f72d9d..fa593b8df4 100644
--- a/engines/sword1/sword1.cpp
+++ b/engines/sword1/sword1.cpp
@@ -116,8 +116,9 @@ Common::Error SwordEngine::init() {
_systemVars.controlPanelMode = CP_NEWGAME;
_systemVars.forceRestart = false;
_systemVars.wantFade = true;
+ _systemVars.realLanguage = Common::parseLanguage(ConfMan.get("language"));
- switch (Common::parseLanguage(ConfMan.get("language"))) {
+ switch (_systemVars.realLanguage) {
case Common::DE_DEU:
_systemVars.language = BS1_GERMAN;
break;
@@ -138,6 +139,7 @@ Common::Error SwordEngine::init() {
break;
default:
_systemVars.language = BS1_ENGLISH;
+ break;
}
_systemVars.showText = ConfMan.getBool("subtitles");
diff --git a/engines/sword1/sword1.h b/engines/sword1/sword1.h
index ccdc2d3a59..ec6555b4b3 100644
--- a/engines/sword1/sword1.h
+++ b/engines/sword1/sword1.h
@@ -75,6 +75,7 @@ struct SystemVars {
uint8 language;
bool isDemo;
Common::Platform platform;
+ Common::Language realLanguage;
};
class SwordEngine : public Engine {
diff --git a/engines/sword2/sprite.cpp b/engines/sword2/sprite.cpp
index cb0923cc2f..91a5e2e86b 100644
--- a/engines/sword2/sprite.cpp
+++ b/engines/sword2/sprite.cpp
@@ -772,7 +772,7 @@ int32 Screen::drawSprite(SpriteInfo *s) {
src = sprite + rs.top * srcPitch + rs.left;
dst = _buffer + _screenWide * rd.top + rd.left;
- if (s->type & RDSPR_BLEND) {
+ if (s->type & RDSPR_BLEND) {
// The original code had two different blending cases. One for
// s->blend & 0x01 and one for s->blend & 0x02. However, the
// only values that actually appear in the cluster files are
@@ -783,7 +783,7 @@ int32 Screen::drawSprite(SpriteInfo *s) {
// The only correct way to simulate this would be using 16-bit mode.
// As this is not yet available for this engine, fake transparency is used
// as placeholder.
- if (!(_renderCaps & RDBLTFX_SPRITEBLEND) || Sword2Engine::isPsx()) {
+ if (!(_renderCaps & RDBLTFX_SPRITEBLEND) || Sword2Engine::isPsx()) {
for (i = 0; i < rs.height(); i++) {
for (j = 0; j < rs.width(); j++) {
if (src[j] && ((i & 1) == (j & 1)))
diff --git a/engines/sword25/sfx/soundengine.cpp b/engines/sword25/sfx/soundengine.cpp
index 69fae3dc4e..61d53c89a7 100644
--- a/engines/sword25/sfx/soundengine.cpp
+++ b/engines/sword25/sfx/soundengine.cpp
@@ -370,7 +370,7 @@ bool SoundEngine::unpersist(InputPersistenceBlock &reader) {
int loopStart;
int loopEnd;
uint layer;
-
+
reader.readString(fileName);
reader.read(sndType);
reader.read(volume);
diff --git a/engines/teenagent/actor.cpp b/engines/teenagent/actor.cpp
index cb8c798fb6..d65a367309 100644
--- a/engines/teenagent/actor.cpp
+++ b/engines/teenagent/actor.cpp
@@ -22,47 +22,46 @@
#include "teenagent/actor.h"
#include "teenagent/objects.h"
#include "teenagent/resources.h"
+#include "teenagent/teenagent.h"
#include "common/random.h"
#include "common/textconsole.h"
namespace TeenAgent {
-Actor::Actor() : head_index(0), idle_type(0) {}
+Actor::Actor(TeenAgentEngine *vm) : _vm(vm), headIndex(0), idleType(0) {}
-//idle animation lists at dseg: 0x6540
-Common::Rect Actor::renderIdle(Graphics::Surface *surface, const Common::Point &position, uint8 orientation, int delta_frame, uint zoom, Common::RandomSource &rnd) {
+Common::Rect Actor::renderIdle(Graphics::Surface *surface, const Common::Point &position, uint8 orientation, int deltaFrame, uint zoom, Common::RandomSource &rnd) {
if (index == 0) {
- idle_type = rnd.getRandomNumber(2);
- debug(0, "switched to idle animation %u", idle_type);
+ idleType = rnd.getRandomNumber(2);
+ debugC(kDebugActor, "switched to idle animation %u", idleType);
}
- Resources *res = Resources::instance();
- byte *frames_idle;
+ byte *framesIdle;
do {
- frames_idle = res->dseg.ptr(res->dseg.get_word(0x6540 + idle_type * 2)) + index;
- index += delta_frame;
- if (*frames_idle == 0) {
- idle_type = rnd.getRandomNumber(2);
- debug(0, "switched to idle animation %u[loop]", idle_type);
+ framesIdle = _vm->res->dseg.ptr(_vm->res->dseg.get_word(dsAddr_idleAnimationListPtr + idleType * 2)) + index;
+ index += deltaFrame;
+ if (*framesIdle == 0) {
+ idleType = rnd.getRandomNumber(2);
+ debugC(kDebugActor, "switched to idle animation %u[loop]", idleType);
index = 3; //put 4th frame (base 1) if idle animation loops
}
- } while (*frames_idle == 0);
+ } while (*framesIdle == 0);
bool mirror = orientation == kActorLeft;
- Surface *s = frames + *frames_idle - 1;
+ Surface *s = frames + *framesIdle - 1;
- ///\todo remove copy-paste here and below
+ //TODO: remove copy-paste here and below
int xp = position.x - s->w * zoom / 512 - s->x, yp = position.y - 62 * zoom / 256 - s->y; //hardcoded in original game
return s->render(surface, xp, yp, mirror, Common::Rect(), zoom);
}
-Common::Rect Actor::render(Graphics::Surface *surface, const Common::Point &position, uint8 orientation, int delta_frame, bool render_head, uint zoom) {
- const uint8 frames_left_right[] = {0, 1, 2, 3, 4, 5, /* step */ 6, 7, 8, 9};
- const uint8 frames_up[] = {18, 19, 20, 21, 22, 23, 24, 25, };
- const uint8 frames_down[] = {10, 11, 12, 13, 14, 15, 16, 17, };
+Common::Rect Actor::render(Graphics::Surface *surface, const Common::Point &position, uint8 orientation, int deltaFrame, bool renderHead, uint zoom) {
+ const uint8 framesLeftRight[] = {0, 1, 2, 3, 4, 5, /* step */ 6, 7, 8, 9};
+ const uint8 framesUp[] = {18, 19, 20, 21, 22, 23, 24, 25, };
+ const uint8 framesDown[] = {10, 11, 12, 13, 14, 15, 16, 17, };
- const uint8 frames_head_left_right[] = {
+ const uint8 framesHeadLeftRight[] = {
0x27, 0x1a, 0x1b,
0x27, 0x1c, 0x1d,
0x27, 0x1a,
@@ -73,14 +72,14 @@ Common::Rect Actor::render(Graphics::Surface *surface, const Common::Point &posi
0x27, 0x1a,
};
- const uint8 frames_head_up[] = {
+ const uint8 framesHeadUp[] = {
0x29, 0x25, 0x29, 0x29,
0x26, 0x29, 0x26, 0x29,
0x29, 0x25, 0x29, 0x25,
0x29, 0x29, 0x29, 0x25,
0x25, 0x29, 0x29, 0x26
};
- const uint8 frames_head_down[] = {
+ const uint8 framesHeadDown[] = {
0x20, 0x21, 0x22, 0x23,
0x28, 0x24, 0x28, 0x28,
0x24, 0x28, 0x20, 0x21,
@@ -91,45 +90,45 @@ Common::Rect Actor::render(Graphics::Surface *surface, const Common::Point &posi
Surface *s = NULL, *head = NULL;
bool mirror = orientation == kActorLeft;
- index += delta_frame;
+ index += deltaFrame;
switch (orientation) {
case kActorLeft:
case kActorRight:
- if (render_head) {
- if (head_index >= ARRAYSIZE(frames_head_left_right))
- head_index = 0;
- head = frames + frames_head_left_right[head_index];
- ++head_index;
+ if (renderHead) {
+ if (headIndex >= ARRAYSIZE(framesHeadLeftRight))
+ headIndex = 0;
+ head = frames + framesHeadLeftRight[headIndex];
+ ++headIndex;
}
- if (index >= ARRAYSIZE(frames_left_right))
+ if (index >= ARRAYSIZE(framesLeftRight))
index = 1;
- s = frames + frames_left_right[index];
+ s = frames + framesLeftRight[index];
break;
case kActorUp:
- if (render_head) {
- if (head_index >= ARRAYSIZE(frames_head_up))
- head_index = 0;
- head = frames + frames_head_up[head_index];
- ++head_index;
+ if (renderHead) {
+ if (headIndex >= ARRAYSIZE(framesHeadUp))
+ headIndex = 0;
+ head = frames + framesHeadUp[headIndex];
+ ++headIndex;
}
- if (index >= ARRAYSIZE(frames_up))
+ if (index >= ARRAYSIZE(framesUp))
index = 1;
- s = frames + frames_up[index];
+ s = frames + framesUp[index];
break;
case kActorDown:
- if (render_head) {
- if (head_index >= ARRAYSIZE(frames_head_down))
- head_index = 0;
- head = frames + frames_head_down[head_index];
- ++head_index;
+ if (renderHead) {
+ if (headIndex >= ARRAYSIZE(framesHeadDown))
+ headIndex = 0;
+ head = frames + framesHeadDown[headIndex];
+ ++headIndex;
}
- if (index >= ARRAYSIZE(frames_down))
+ if (index >= ARRAYSIZE(framesDown))
index = 1;
- s = frames + frames_down[index];
+ s = frames + framesDown[index];
break;
default:
return Common::Rect();
diff --git a/engines/teenagent/actor.h b/engines/teenagent/actor.h
index 9a7d395547..942397c636 100644
--- a/engines/teenagent/actor.h
+++ b/engines/teenagent/actor.h
@@ -28,13 +28,20 @@ class RandomSource;
namespace TeenAgent {
+class TeenAgentEngine;
+
class Actor : public Animation {
- uint head_index;
- uint idle_type;
+private:
+ TeenAgentEngine *_vm;
+
+ uint headIndex;
+ uint idleType;
+
public:
- Actor();
- Common::Rect render(Graphics::Surface *surface, const Common::Point &position, uint8 orientation, int delta_frame, bool head, uint zoom);
- Common::Rect renderIdle(Graphics::Surface *surface, const Common::Point &position, uint8 orientation, int delta_frame, uint zoom, Common::RandomSource &rnd);
+ Actor(TeenAgentEngine *vm);
+
+ Common::Rect render(Graphics::Surface *surface, const Common::Point &position, uint8 orientation, int deltaFrame, bool renderHead, uint zoom);
+ Common::Rect renderIdle(Graphics::Surface *surface, const Common::Point &position, uint8 orientation, int deltaFrame, uint zoom, Common::RandomSource &rnd);
};
} // End of namespace TeenAgent
diff --git a/engines/teenagent/animation.cpp b/engines/teenagent/animation.cpp
index 56107b67ca..effafcaac6 100644
--- a/engines/teenagent/animation.cpp
+++ b/engines/teenagent/animation.cpp
@@ -19,24 +19,30 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "teenagent/teenagent.h"
#include "teenagent/animation.h"
+
#include "common/endian.h"
#include "common/textconsole.h"
namespace TeenAgent {
-Animation::Animation() : id(0), x(0), y(0), loop(true), paused(false), ignore(false), data(0), data_size(0), frames_count(0), frames(0), index(0) {
+Animation::Animation() : id(0), x(0), y(0), loop(true), paused(false), ignore(false), data(0), dataSize(0), framesCount(0), frames(0), index(0) {
+}
+
+Animation::~Animation() {
+ free();
}
Surface *Animation::firstFrame() {
- if (frames == NULL || frames_count == 0)
+ if (frames == NULL || framesCount == 0)
return NULL;
Surface *r = frames;
uint16 pos = READ_LE_UINT16(data + 1);
if (pos != 0) {
- r->x = pos % 320;
- r->y = pos / 320;
+ r->x = pos % kScreenWidth;
+ r->y = pos / kScreenWidth;
}
return r;
}
@@ -45,38 +51,38 @@ Surface *Animation::currentFrame(int dt) {
if (paused)
return firstFrame();
- if (frames == NULL || frames_count == 0)
+ if (frames == NULL || framesCount == 0)
return NULL;
Surface *r;
if (data != NULL) {
uint32 frame = 3 * index;
- //debug(0, "%u/%u", index, data_size / 3);
+ debugC(2, kDebugAnimation, "%u/%u", index, dataSize / 3);
index += dt;
- if (!loop && index >= data_size / 3) {
+ if (!loop && index >= dataSize / 3) {
return NULL;
}
- if (data[frame] - 1 >= frames_count) {
- warning("invalid frame %u(0x%x) (max %u) index %u, mod %u", frame, frame, frames_count, index - 1, data_size / 3);
+ if (data[frame] - 1 >= framesCount) {
+ warning("invalid frame %u(0x%x) (max %u) index %u, mod %u", frame, frame, framesCount, index - 1, dataSize / 3);
return NULL;
}
r = frames + data[frame] - 1;
uint16 pos = READ_LE_UINT16(data + frame + 1);
- index %= (data_size / 3);
+ index %= (dataSize / 3);
if (pos != 0) {
- x = r->x = pos % 320;
- y = r->y = pos / 320;
+ x = r->x = pos % kScreenWidth;
+ y = r->y = pos / kScreenWidth;
}
} else {
- //debug(0, "index %u", index);
+ debugC(2, kDebugAnimation, "index %u", index);
r = frames + index;
index += dt;
- index %= frames_count;
+ index %= framesCount;
}
return r;
@@ -97,9 +103,9 @@ void Animation::free() {
delete[] data;
data = NULL;
- data_size = 0;
+ dataSize = 0;
- frames_count = 0;
+ framesCount = 0;
delete[] frames;
frames = NULL;
@@ -107,44 +113,42 @@ void Animation::free() {
}
void Animation::load(Common::SeekableReadStream &s, Type type) {
- //fixme: do not reload the same animation each time
+ //FIXME: do not reload the same animation each time
free();
if (s.size() <= 1) {
- debug(1, "empty animation");
+ debugC(1, kDebugAnimation, "empty animation");
return;
}
- //uint16 pos = 0;
+ uint16 pos = 0;
int off = 0;
switch (type) {
case kTypeLan:
- data_size = s.readUint16LE();
+ dataSize = s.readUint16LE();
if (s.eos()) {
- debug(1, "empty animation");
+ debugC(1, kDebugAnimation, "empty animation");
return;
}
- data_size -= 2;
- data = new byte[data_size];
- data_size = s.read(data, data_size);
- /* for (int i = 0; i < data_size; ++i) {
- debug(0, "%02x ", data[i]);
- }
- debug(0, ", %u frames", data_size / 3);
- */
- frames_count = s.readByte();
- debug(1, "%u physical frames", frames_count);
- if (frames_count == 0)
+ dataSize -= 2;
+ data = new byte[dataSize];
+ dataSize = s.read(data, dataSize);
+ for (int i = 0; i < dataSize; ++i)
+ debugC(2, kDebugAnimation, "%02x ", data[i]);
+ debugC(2, kDebugAnimation, ", %u frames", dataSize / 3);
+ framesCount = s.readByte();
+ debugC(1, kDebugAnimation, "%u physical frames", framesCount);
+ if (framesCount == 0)
return;
- frames = new Surface[frames_count];
+ frames = new Surface[framesCount];
- s.skip(frames_count * 2 - 2); //sizes
- /*pos = */s.readUint16LE();
- //debug(0, "pos?: %04x", pos);
+ s.skip(framesCount * 2 - 2); //sizes
+ pos = s.readUint16LE();
+ debugC(3, kDebugAnimation, "pos?: 0x%04x", pos);
- for (uint16 i = 0; i < frames_count; ++i) {
+ for (uint16 i = 0; i < framesCount; ++i) {
frames[i].load(s, Surface::kTypeLan);
frames[i].x = 0;
frames[i].y = 0;
@@ -152,43 +156,43 @@ void Animation::load(Common::SeekableReadStream &s, Type type) {
break;
case kTypeInventory: {
- data_size = 3 * s.readByte();
- data = new byte[data_size];
+ dataSize = 3 * s.readByte();
+ data = new byte[dataSize];
- frames_count = 0;
- for (byte i = 0; i < data_size / 3; ++i) {
+ framesCount = 0;
+ for (byte i = 0; i < dataSize / 3; ++i) {
int idx = i * 3;
- /* byte unk = */
- s.readByte();
+ byte unk = s.readByte();
+ debugC(3, kDebugAnimation, "unk?: 0x%02x", unk);
data[idx] = s.readByte();
if (data[idx] == 0)
data[idx] = 1; //fixme: investigate
- if (data[idx] > frames_count)
- frames_count = data[idx];
+ if (data[idx] > framesCount)
+ framesCount = data[idx];
data[idx + 1] = 0;
data[idx + 2] = 0;
- //debug(0, "frame #%u", data[idx]);
+ debugC(2, kDebugAnimation, "frame #%u", data[idx]);
}
- frames = new Surface[frames_count];
+ frames = new Surface[framesCount];
- for (uint16 i = 0; i < frames_count; ++i) {
+ for (uint16 i = 0; i < framesCount; ++i) {
frames[i].load(s, Surface::kTypeOns);
}
}
break;
case kTypeVaria:
- frames_count = s.readByte();
- debug(1, "loading varia resource, %u physical frames", frames_count);
+ framesCount = s.readByte();
+ debugC(1, kDebugAnimation, "loading varia resource, %u physical frames", framesCount);
uint16 offset[255];
- for (byte i = 0; i < frames_count; ++i) {
+ for (byte i = 0; i < framesCount; ++i) {
offset[i] = s.readUint16LE();
- //debug(0, "%u: %04x", i, offset[i]);
+ debugC(0, kDebugAnimation, "%u: %04x", i, offset[i]);
}
- frames = new Surface[frames_count];
- for (uint16 i = 0; i < frames_count; ++i) {
- //debug(0, "%04x", offset[i]);
+ frames = new Surface[framesCount];
+ for (uint16 i = 0; i < framesCount; ++i) {
+ debugC(0, kDebugAnimation, "%04x", offset[i]);
s.seek(offset[i] + off);
frames[i].load(s, Surface::kTypeOns);
}
@@ -196,11 +200,7 @@ void Animation::load(Common::SeekableReadStream &s, Type type) {
break;
}
- debug(0, "%u frames", data_size / 3);
-}
-
-Animation::~Animation() {
- free();
+ debugC(2, kDebugAnimation, "%u frames", dataSize / 3);
}
} // End of namespace TeenAgent
diff --git a/engines/teenagent/animation.h b/engines/teenagent/animation.h
index 6942cc74eb..9be21a4c3d 100644
--- a/engines/teenagent/animation.h
+++ b/engines/teenagent/animation.h
@@ -35,6 +35,8 @@ public:
enum Type {kTypeLan, kTypeVaria, kTypeInventory};
Animation();
+ ~Animation();
+
void load(Common::SeekableReadStream &, Type type = kTypeLan);
void free();
@@ -43,8 +45,6 @@ public:
uint16 currentIndex() const { return index; }
void resetIndex() { index = 0; }
- ~Animation();
-
bool empty() const { return frames == NULL; }
void restart();
@@ -53,9 +53,9 @@ public:
protected:
byte *data;
- uint16 data_size;
+ uint16 dataSize;
- uint16 frames_count;
+ uint16 framesCount;
Surface *frames;
uint16 index;
};
diff --git a/engines/teenagent/callbacks.cpp b/engines/teenagent/callbacks.cpp
index 934727a478..2de81abb37 100644
--- a/engines/teenagent/callbacks.cpp
+++ b/engines/teenagent/callbacks.cpp
@@ -19,8 +19,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "teenagent/scene.h"
#include "teenagent/teenagent.h"
+#include "teenagent/scene.h"
+#include "teenagent/inventory.h"
#include "teenagent/resources.h"
#include "teenagent/dialog.h"
@@ -33,159 +34,536 @@ namespace TeenAgent {
#define GET_FLAG(addr) (res->dseg.get_byte(addr))
#define INC_FLAG(addr) (++*res->dseg.ptr(addr))
-void TeenAgentEngine::rejectMessage() {
- Resources *res = Resources::instance();
- //random reject message:
- uint i = _rnd.getRandomNumber(3);
- //debug(0, "reject message: %s", (const char *)res->dseg.ptr(res->dseg.get_word(0x339e + 2 * i)));
- displayMessage(res->dseg.get_word(0x339e + 2 * i));
+void TeenAgentEngine::fnIntro() {
+ hideActor();
+
+ loadScene(41, 139, 156, 3);
+ playSound(41, 12);
+ playAnimation(912, 1);
+ setOns(0, 108);
+ playSound(62, 8);
+ playSound(58, 40);
+ playAnimation(913, 1);
+ setOns(1, 109);
+ setLan(2, 1);
+ dialog->show(192, scene, 914, 915, textColorGoldDriver, textColorBankGuard, 2, 1);
+ displayCredits(dsAddr_introCredits1);
+
+ loadScene(42, 139, 156, 3);
+ playSound(15, 20);
+ playAnimation(916, 1);
+ playSound(40, 18);
+ playSound(40, 22);
+ for (byte i = 27; i < 37; i += 2)
+ playSound(40, i);
+ playSound(29, 44);
+ playAnimation(918, 0, true);
+ playAnimation(917, 1, true);
+ waitAnimation();
+ displayCredits(dsAddr_introCredits2);
+
+ loadScene(40, 139, 156, 3);
+ playMusic(3);
+ dialog->show(193, scene, 920, 924, textColorRGBBoss, textColorFortuneTeller, 1, 2);
+ playSound(26, 50);
+ playAnimation(925, 0, true);
+ playAnimation(926, 1, true);
+ waitAnimation();
+ dialog->show(194, scene, 927, 920, textColorFortuneTeller, textColorRGBBoss, 2, 1);
+ displayCredits(dsAddr_introCredits3);
+
+ loadScene(39, 139, 156, 3);
+ playMusic(11);
+ playSound(81, 2);
+ playSound(81, 8);
+ playSound(81, 11);
+ playSound(81, 14);
+ playSound(81, 16);
+ playSound(81, 18);
+ playSound(81, 20);
+ playSound(81, 21);
+ playAnimation(928, 1);
+ setOns(0, 112);
+ dialog->showMono(195, scene, 929, textColorMark, 1);
+ showActor();
+ moveTo(319, 150, 1, true);
+ moveTo(63, 150, 1);
+ displayAsyncMessage(dsAddr_HeyWtmQMsg, 4, 62, 18, 36); // hey, what's the matter?
+ playAnimation(851, 0, true);
+ playActorAnimation(930, true);
+ waitAnimation();
+ playSound(24, 11);
+ playActorAnimation(931);
+
+ displayCredits(dsAddr_introCredits4);
+
+ playMusic(3);
+ loadScene(40, 50, 186, 1);
+ setOns(0, 113);
+ dialog->show(196, scene, 919, 0, textColorRGBBoss, textColorMark, 1, 0);
+ moveTo(196, 186, 1);
+ dialog->show(197, scene, 0, 920, textColorMark, textColorRGBBoss, 0, 1);
+ playActorAnimation(932);
+ dialog->show(198, scene, 0, 920, textColorMark, textColorRGBBoss, 0, 1);
+ playActorAnimation(932);
+ dialog->show(199, scene, 0, 920, textColorMark, textColorRGBBoss, 0, 1);
+ playActorAnimation(932);
+ dialog->show(200, scene, 0, 922, textColorMark, textColorRGBBoss, 0, 1);
+ playActorAnimation(933);
+ dialog->show(201, scene, 0, 920, textColorMark, textColorRGBBoss, 0, 1);
+ moveTo(174, 186, 1);
+ playAnimation(851, 0, true);
+ playActorAnimation(934, true);
+ waitAnimation();
+ loadScene(10, 136, 153, 3);
}
+void TeenAgentEngine::fnPoleClimbFail() {
+ moveTo(86, 195, 1, true);
+ playActorAnimation(868);
+}
-bool TeenAgentEngine::processCallback(uint16 addr) {
- if (addr == 0)
- return false;
+void TeenAgentEngine::fnGotAnchor() {
+ SET_FLAG(dsAddr_timedCallbackState, 0);
+ setTimerCallback(0, 0);
+ scene->getActorAnimation()->free();
+ playSound(64, 7);
+ playActorAnimation(618);
+ disableObject(5);
+ setOns(0, 0);
+ playSound(31, 1);
+ playActorAnimation(619);
+ fnGetOutOfLake();
+ inventory->add(kInvItemAnchor);
+ displayMessage(dsAddr_hookedAnchorMsg); // "I was really hooked on this anchor!"
+}
- Resources *res = Resources::instance();
- debug(0, "processCallback(%04x)", addr);
- byte *code = res->cseg.ptr(addr);
-
- //try trivial callbacks first
- if (code[0] == 0xbb && code[3] == 0xe8 && code[6] == 0xc3) {
- //call display_message, r
- uint16 msg = READ_LE_UINT16(code + 1);
- uint16 func = 6 + addr + READ_LE_UINT16(code + 4);
- debug(0, "call %04x", func);
- //debug(0, "trivial callback, showing message %s", (const char *)res->dseg.ptr(addr));
- switch (func) {
- case 0xa055:
- displayMessage(msg);
- return true;
- }
+void TeenAgentEngine::fnGetOutOfLake() {
+ loadScene(15, 156, 180, 3);
+ playSound(5, 5);
+ playSound(38, 14);
+ playSound(38, 20);
+ playSound(5, 25);
+ playActorAnimation(616);
+}
+
+void TeenAgentEngine::fnGuardDrinking() {
+ SET_FLAG(dsAddr_timedCallbackState, 0);
+ setTimerCallback(0, 0);
+ scene->getAnimation(0)->free();
+ SET_FLAG(dsAddr_scaredGuardAlreadyFlag, 1);
+
+ displayAsyncMessage(dsAddr_BooMsg, 300, 130, 1, 5); // "Booo!"
+ setOns(0, 16);
+ enableObject(2);
+
+ playSound(17, 5);
+ playAnimation(545, 0);
+
+ dialog->show(5, scene, 0, 546, textColorMark, textColorMansionGuard, 0, 1);
+ SET_FLAG(dsAddr_spokenWithMansionGuardFlag, 1);
+ SET_FLAG(dsAddr_haveNotSpokenWithMansionGuardFlag, 0);
+}
+
+void TeenAgentEngine::fnEgoDefaultPosition() {
+ if (scene->getPosition().y <= 149)
+ moveTo(94, 115, 4);
+ else
+ moveTo(51, 149, 4);
+}
+
+void TeenAgentEngine::fnEnterCave() {
+ loadScene(24, 230, 170, 1);
+ playSound(52, 3);
+ playSound(52, 7);
+ playSound(52, 11);
+ playSound(52, 14);
+ playSound(52, 18);
+ playSound(52, 21);
+ playSound(52, 25);
+ playActorAnimation(601);
+ moveTo(230, 179, 3);
+ if (!CHECK_FLAG(dsAddr_lightOnFlag, 1))
+ displayMessage(dsAddr_kindaDarkMsg); // "It's kinda dark here"
+}
+
+void TeenAgentEngine::fnEgoScaredBySpider() {
+ if (CHECK_FLAG(dsAddr_egoAlreadyScaredBySpiderFlag, 1)) {
+ fnMoveToLadderAndLeaveCellar();
+ dialog->showMark(75, scene);
+ } else {
+ dialog->showMark(73, scene);
+ fnMoveToLadderAndLeaveCellar();
+ wait(100);
+ dialog->showMark(74, scene);
+ SET_FLAG(dsAddr_egoAlreadyScaredBySpiderFlag, 1);
}
+}
- if (code[0] == 0xe8 && code[3] == 0xc3) {
- uint func = 3 + addr + READ_LE_UINT16(code + 1);
- debug(0, "call %04x and return", func);
- if (func == 0xa4d6) {
- rejectMessage();
+void TeenAgentEngine::fnMoveToLadderAndLeaveCellar() {
+ Object *objTemp = scene->getObject(3);
+ moveTo(objTemp);
+ fnLeaveCellar();
+ moveTo(48, 190, 3);
+}
+
+void TeenAgentEngine::fnLeaveCellar() {
+ playSound(52, 10);
+ playSound(52, 14);
+ playSound(52, 18);
+ playSound(52, 21);
+ playSound(52, 25);
+ playSound(52, 28);
+ playSound(52, 32);
+ playActorAnimation(600);
+ loadScene(21, 297, 178, 3);
+}
+
+void TeenAgentEngine::fnPutRockInHole() {
+ if (CHECK_FLAG(dsAddr_timedCallbackState, 0)) {
+ playSound(5, 2);
+ playSound(15, 12);
+ playActorAnimation(638);
+ inventory->remove(kInvItemMouse);
+ setTimerCallback(csAddr_mouseOutOfHoleTimeout, 100);
+ SET_FLAG(dsAddr_timedCallbackState, 1);
+ } else if (CHECK_FLAG(dsAddr_timedCallbackState, 1)) {
+ playSound(5, 2);
+ playSound(52, 13);
+ playActorAnimation(648);
+ setOns(1, 46);
+ inventory->remove(kInvItemRock);
+ setTimerCallback(csAddr_mouseOutOfHoleTimeout, 100);
+ SET_FLAG(dsAddr_timedCallbackState, 2);
+ } else if (CHECK_FLAG(dsAddr_timedCallbackState, 2)) {
+ playActorAnimation(649);
+ setOns(1, 47);
+ wait(300);
+ for (byte i = 1; i <= 37; i += 4)
+ playSound(68, i);
+ playAnimation(639, 2);
+ setOns(0, 42);
+ enableObject(6);
+ disableObject(5);
+ SET_FLAG(dsAddr_mouseGotGoldNuggetFlag, 1);
+ SET_FLAG(dsAddr_timedCallbackState, 0);
+ setTimerCallback(0, 0);
+ }
+}
+
+void TeenAgentEngine::fnEgoBottomRightTurn() {
+ Common::Point p = scene->getPosition();
+ if (p.x == 208 && p.y == 151)
+ moveRel(0, 0, 2);
+ else
+ moveTo(208, 151, 1);
+}
+
+bool TeenAgentEngine::fnCheckingDrawers() {
+ uint16 v = GET_FLAG(dsAddr_drawerPuzzleBookValue) - 1;
+ if (GET_FLAG(dsAddr_blueDrawerOpenFlag + v) != 1)
+ return false;
+ else {
+ uint16 sum = 0;
+ for (uint i = 0; i < 6; ++i)
+ sum += GET_FLAG(dsAddr_blueDrawerOpenFlag + i);
+ if (sum != 1)
+ return false;
+ else
return true;
- }
}
+}
- if (code[0] == 0xc7 && code[1] == 0x06 && code[2] == 0xf3 && code[3] == 0xb4 &&
- code[6] == 0xb8 && code[9] == 0xbb && code[12] == 0xbf &&
- code[22] == 0xe8 && code[25] == 0xc3) {
- loadScene(code[4], Common::Point(
- (READ_LE_UINT16(code + 7) + READ_LE_UINT16(code + 13) + 1) / 2 ,
- READ_LE_UINT16(code + 10)));
- scene->setOrientation(code[21]);
+void TeenAgentEngine::fnDrawerOpenMessage() {
+ if (CHECK_FLAG(dsAddr_drawerPuzzleHintGivenFlag, 1))
+ displayMessage(dsAddr_drawerOpenMsg); // "I cannot open the drawer if the next one is open!"
+ else {
+ displayMessage(dsAddr_strangeDrawerMsg); // "Strange, but the drawer is stuck if the next drawer is open"
+ displayMessage(dsAddr_notOrdinaryDrawersMsg); // "Maybe these are not just ordinary drawers!"
+ SET_FLAG(dsAddr_drawerPuzzleHintGivenFlag, 1);
+ }
+}
+
+bool TeenAgentEngine::fnRobotSafeAlreadyUnlockedCheck() {
+ if (CHECK_FLAG(dsAddr_MansionRobotSafeUnlockedFlag, 1)) {
return true;
+ } else {
+ displayMessage(dsAddr_noReasonMsg); // "There's no reason to do it"
+ return false;
}
+}
- switch (addr) {
+void TeenAgentEngine::fnRobotSafeUnlockCheck() {
+ if (CHECK_FLAG(dsAddr_MansionRobotSafeVoiceTestPassedFlag, 1) &&
+ CHECK_FLAG(dsAddr_MansionRobotSafeScentTestPassedFlag, 1) &&
+ CHECK_FLAG(dsAddr_MansionRobotSafeViewTestPassedFlag, 1)) {
+ waitLanAnimationFrame(1, 1);
+ playSound(89, 2);
+ playActorAnimation(731);
+ setOns(0, 70);
+ setLan(1, 0);
+ disableObject(1);
+ enableObject(2);
+ enableObject(3);
+ }
+}
- case 0x024c: //intro
- hideActor();
+bool TeenAgentEngine::fnMansionIntrusionAttempt() {
+ wait(50);
+ byte attempts = res->dseg.get_byte(dsAddr_mansionEntryCount) + 1;
+ res->dseg.set_byte(dsAddr_mansionEntryCount, attempts);
+ debugC(0, kDebugCallbacks, "mansion intrusion attempt #%u", attempts);
+ if (attempts >= 7)
+ return false;
+ else {
+ byte id = scene->getId();
- loadScene(41, 139, 156, 3);
- playSound(41, 12);
- playAnimation(912, 1);
- setOns(0, 108);
- playSound(62, 8);
- playSound(58, 40);
- playAnimation(913, 1);
- setOns(1, 109);
- setLan(2, 1);
- Dialog::show(scene, 0x748e, 914, 915, 0xe7, 0xd7, 2, 1);
- displayCredits(0xe3c2);
-
- loadScene(42, 139, 156, 3);
- playSound(15, 20);
- playAnimation(916, 1);
- playSound(40, 18);
- playSound(40, 22);
- for (byte i = 27; i < 37; i += 2)
- playSound(40, i);
- playSound(29, 44);
- playAnimation(918, 0, true);
- playAnimation(917, 1, true);
- waitAnimation();
- displayCredits(0xe3e6);
+ playMusic(11);
+ displayCutsceneMessage(dsAddr_cutsceneMsg2, 84, 95); // "Meanwhile in the mansion"
+ switch (attempts) {
+ case 2:
+ fnSecondMansionIntrusion();
+ break;
+ case 3:
+ fnThirdMansionIntrusion();
+ break;
+ case 4:
+ fnFourthMansionIntrusion();
+ break;
+ case 5:
+ fnFifthMansionIntrusion();
+ break;
+ case 6:
+ fnSixthMansionIntrusion();
+ break;
+ default:
+ error("mansion intrusion attempts out of range!");
+ break;
+ }
+ playMusic(6);
+ if (getFlag(dsAddr_johnNotyOutsideMansionDoorFlag) != 1 || attempts != 6)
+ loadScene(id, scene->getPosition());
+ return true;
+ }
+}
- loadScene(40, 139, 156, 3);
- playMusic(3);
- Dialog::show(scene, 0x750d, 920, 924, 0xe7, 0xeb, 1, 2); //as i told you, our organization...
- playSound(26, 50);
- playAnimation(925, 0, true);
- playAnimation(926, 1, true);
- waitAnimation();
- Dialog::show(scene, 0x78a6, 927, 920, 0xeb, 0xe7, 2, 1);
- displayCredits(0xe3ff);
+void TeenAgentEngine::fnSecondMansionIntrusion() {
+ hideActor();
+ loadScene(34, scene->getPosition());
+ playAnimation(986, 0, true);
+ playAnimation(987, 1, true);
+ waitAnimation();
+ dialog->show(178, scene, 988, 989, textColorMansionGuard, textColorJohnNoty, 1, 2);
+ playAnimation(990, 0, true);
+ playAnimation(991, 1, true);
+ waitAnimation();
+ showActor();
+}
- loadScene(39, 139, 156, 3);
- playMusic(11);
- playSound(81, 2);
- playSound(81, 8);
- playSound(81, 11);
- playSound(81, 14);
- playSound(81, 16);
- playSound(81, 18);
- playSound(81, 20);
- playSound(81, 21);
- playAnimation(928, 1);
- setOns(0, 112);
- Dialog::showMono(scene, 0x78e1, 929, 0xd1, 1); //he's coming
- showActor();
- moveTo(319, 150, 1, true);
- moveTo(63, 150, 1);
- displayAsyncMessage(0x5da8, 19844, 18, 36); //hey, what's the matter?
- playAnimation(851, 0, true);
- playActorAnimation(930, true);
- waitAnimation();
- playSound(24, 11);
- playActorAnimation(931);
+void TeenAgentEngine::fnThirdMansionIntrusion() {
+ hideActor();
+ loadScene(30, scene->getPosition());
+ playAnimation(887, 1);
+ playAnimation(888, 2, true, true, true);
+ //waitAnimation();
+ dialog->showMono(179, scene, 889, textColorMansionGuard, 2);
+ playSound(26, 3);
+ playAnimation(891, 1, true, true, true);
+ playAnimation(892, 2);
+ waitAnimation();
+ dialog->show(180, scene, 890, 889, textColorJohnNoty, textColorMansionGuard, 3, 2);
+ showActor();
+}
- displayCredits(0xe42f);
+void TeenAgentEngine::fnFourthMansionIntrusion() {
+ hideActor();
+ loadScene(32, scene->getPosition());
+ playAnimation(894, 1, true, true, true);
+ playAnimation(893, 2, true);
+ waitAnimation();
+ dialog->showMono(181, scene, 895, textColorMansionGuard, 3);
+ playSound(75, 9);
+ playAnimation(898, 1, true);
+ playAnimation(897, 2, true);
+ dialog->show(182, scene, 896, 895, textColorJohnNoty, textColorMansionGuard, 2, 3);
+ showActor();
+}
- playMusic(3);
- loadScene(40, 50, 186, 1);
- setOns(0, 113);
- Dialog::show(scene, 0x78f1, 919, 0, 0xe7, 0xd1, 1, 0);
- moveTo(196, 186, 1);
- Dialog::show(scene, 0x7958, 0, 920, 0xd1, 0xe7, 0, 1);
- playActorAnimation(932);
- Dialog::show(scene, 0x7e07, 0, 920, 0xd1, 0xe7, 0, 1);
- playActorAnimation(932);
- Dialog::show(scene, 0x7e1a, 0, 920, 0xd1, 0xe7, 0, 1);
- playActorAnimation(932);
- Dialog::show(scene, 0x7e2c, 0, 922, 0xd1, 0xe7, 0, 1);
- playActorAnimation(933);
- Dialog::show(scene, 0x7e70, 0, 920, 0xd1, 0xe7, 0, 1);
- moveTo(174, 186, 1);
- playAnimation(851, 0, true);
- playActorAnimation(934, true);
- waitAnimation();
- loadScene(10, 136, 153, 3);
+void TeenAgentEngine::fnFifthMansionIntrusion() {
+ hideActor();
+ loadScene(29, scene->getPosition());
+ playActorAnimation(901, true);
+ playAnimation(900, 1, true);
+ waitAnimation();
+ dialog->show(183, scene, 903, 902, textColorJohnNoty, textColorMansionGuard, 2, 3);
+ for (byte i = 3; i <= 9; i += 2)
+ playSound(56, i);
+
+ playActorAnimation(905, true);
+ playAnimation(904, 1, true);
+ dialog->show(184, scene, 903, 902, textColorJohnNoty, textColorMansionGuard, 2, 3);
+ showActor();
+}
+
+void TeenAgentEngine::fnSixthMansionIntrusion() {
+ hideActor();
+ loadScene(35, scene->getPosition());
+ playAnimation(907, 2, true);
+ playAnimation(906, 3, true);
+ waitAnimation();
+ dialog->show(185, scene, 908, 909, textColorMansionGuard, textColorJohnNoty, 2, 3);
+ dialog->show(186, scene, 910, 908, textColorJohnNoty, textColorMansionGuard, 3, 2);
+ loadScene(11, scene->getPosition());
+ showActor();
+ setOns(3, 51);
+ playAnimation(911, 1);
+ playAnimation(899, 1);
+ setFlag(dsAddr_johnNotyOutsideMansionDoorFlag, 1);
+ reloadLan();
+ wait(200);
+ enableObject(8);
+ setLan(2, 8);
+}
+void TeenAgentEngine::fnTooDark() {
+ displayMessage(dsAddr_TooDarkMsg); // "It's too dark to see clearly"
+}
+
+bool TeenAgentEngine::fnIsCookGone() {
+ if (CHECK_FLAG(dsAddr_MansionCookGoneFlag, 1)) {
return true;
+ } else {
+ displayMessage(dsAddr_cookAroundMsg); // "I can't do anything with this cook around"
+ return false;
+ }
+}
+
+void TeenAgentEngine::fnEgoSuspiciousPosition() {
+ Common::Point p = scene->getPosition();
+ if (p.x != 203 && p.y != 171)
+ moveTo(203, 169, 2);
+ else
+ moveTo(203, 169, 1);
+}
+
+void TeenAgentEngine::fnGivingFlowerToOldLady() {
+ playSound(5, 2);
+ dialog->show(37, scene, 0, 523, textColorMark, textColorOldLady, 0, 1);
+ playActorAnimation(537, true);
+ playAnimation(538, 0, true);
+ waitAnimation();
+ wait(100);
+ dialog->show(38, scene, 0, 523, textColorMark, textColorOldLady, 0, 1);
+}
+
+void TeenAgentEngine::fnGiveAnotherFlowerToOldLady() {
+ dialog->pop(scene, dsAddr_dialogStackOldLady, 0, 523, textColorMark, textColorOldLady, 0, 1);
+}
+
+void TeenAgentEngine::fnGivingFlowerToAnne() {
+ dialog->show(53, scene, 0, 524, textColorMark, textColorAnne, 0, 2);
+ playSound(5, 10);
+ playActorAnimation(540, true);
+ playAnimation(539, 1, true);
+ waitAnimation();
+ wait(100);
+ dialog->show(54, scene, 0, 524, textColorMark, textColorAnne, 0, 2);
+ wait(50);
+ dialog->show(55, scene, 0, 524, textColorMark, textColorAnne, 0, 2);
+ dialog->show(56, scene, 0, 524, textColorMark, textColorAnne, 0, 2);
+ wait(50);
+ moveRel(0, 1, 0);
+ dialog->show(57, scene, 0, 524, textColorMark, textColorAnne, 0, 2);
+ moveRel(0, -1, 0);
+ wait(50);
+}
+
+void TeenAgentEngine::fnGiveAnotherFlowerToAnne() {
+ dialog->pop(scene, dsAddr_dialogStackAnotherFlowerToAnne, 0, 524, textColorMark, textColorAnne, 0, 2);
+}
+
+void TeenAgentEngine::rejectMessage() {
+ uint i = _rnd.getRandomNumber(3);
+ switch (i) {
+ case 0:
+ displayMessage(dsAddr_rejectMsg0); // "I have no idea what to do with it"
+ break;
+ case 1:
+ displayMessage(dsAddr_rejectMsg1); // "I can't imagine what I could do with this"
+ break;
+ case 2:
+ displayMessage(dsAddr_rejectMsg2); // "I can't figure out what I should do with this"
+ break;
+ case 3:
+ displayMessage(dsAddr_rejectMsg3); // "I can't find any reason to mess with it"
+ break;
+ default:
+ error("rejectMessage() index out of range");
+ break;
+ }
+}
+
+bool TeenAgentEngine::processCallback(uint16 addr) {
+ if (addr == 0)
+ return false;
+
+ debugC(0, kDebugCallbacks, "processCallback(%04x)", addr);
+
+ bool retVal = true;
+ switch (addr) {
+ case csAddr_intro: // intro
+ fnIntro();
+ break;
+
+ case 0x3fed:
+ loadScene(3, Common::Point(305, 104));
+ scene->setOrientation(4);
+ break;
+
+ case 0x4007:
+ loadScene(5, Common::Point(300, 131));
+ scene->setOrientation(3);
+ break;
case 0x4021:
- //pulling out mysterious object
- if (CHECK_FLAG(0xdbe1, 1)) {
+ // pulling out mysterious object
+ if (CHECK_FLAG(dsAddr_cutFenceFlag, 1)) {
playActorAnimation(844);
playActorAnimation(846);
playActorAnimation(845);
- displayMessage(0x5696);
+ displayMessage(dsAddr_pullObjMsg1); // "I can't pull it out"
} else {
- displayMessage(0x570f);
+ displayMessage(dsAddr_pullObjMsg2); // "I can't reach it"
}
- return true;
-
- case 0x4094: //climbing to the pole near mudpool
- if (CHECK_FLAG(0xDBE4, 1)) {
- displayMessage(0x57b2);
- return true;
+ break;
+
+ case 0x4048:
+ displayMessage(dsAddr_dontWantToTouchMsg); // "I don't want to touch it - I might get hurt"
+ break;
+
+ case 0x404f:
+ displayMessage(dsAddr_notWantToSleepMsg); // "I don't want to sleep"
+ break;
+
+ case 0x4056:
+ // FIXME - This is the bird use callback in the first act at
+ // the mudpool. Current Code based on behaviour. Need to analyse cseg data.
+ dialog->popMark(scene, dsAddr_dialogStackMudpoolBird);
+ break;
+
+ case 0x4060:
+ loadScene(2, Common::Point(28, 180));
+ scene->setOrientation(2);
+ break;
+
+ case 0x407a:
+ loadScene(4, Common::Point(297, 128));
+ scene->setOrientation(4);
+ break;
+
+ case 0x4094: // climbing to the pole near mudpool
+ if (CHECK_FLAG(dsAddr_gotMugOfMudFlag, 1)) {
+ displayMessage(dsAddr_poleClimbDoneMsg); // "Never Again!"
} else {
for (byte i = 11; i <= 27; i += 4)
playSound(76, i);
@@ -196,39 +574,49 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playAnimation(865, 1);
playActorAnimation(866);
//InventoryObject *obj = inventory->selectedObject();
- //if (obj != NULL && obj->id == 0x55) {
+ //if (obj != NULL && obj->id == kInvItemMug) {
- //implement pause and using real object:
- if (inventory->has(0x55)) {
+ // FIXME: implement pause in mudpool and using of Mug object, as per original interpreter
+ if (inventory->has(kInvItemMug)) {
playSound(5, 4);
playSound(5, 19);
playSound(64, 11);
playActorAnimation(867);
- inventory->remove(0x55);
- inventory->add(0x56);
+ inventory->remove(kInvItemMug);
+ inventory->add(kInvItemMugOfMud);
moveTo(86, 195, 1, true);
playActorAnimation(868);
- SET_FLAG(0xDBE4, 1);
+ SET_FLAG(dsAddr_gotMugOfMudFlag, 1);
} else {
- processCallback(0x4173);
- Dialog::pop(scene, 0xDB72, 0, 0, 0xd1, 0xd1, 0, 0);
+ fnPoleClimbFail();
+ dialog->popMark(scene, dsAddr_dialogStackFallIntoMudpool);
}
- return true;
}
- case 0x4173:
- //fail!
- moveTo(86, 195, 1, true);
- playActorAnimation(868);
- return true;
+ break;
+
+ case csAddr_poleClimbFail:
+ fnPoleClimbFail();
+ break;
- case 0x419c: //getting the bird
+ case 0x4195:
+ displayMessage(dsAddr_preferWaterMsg); // "I prefer water"
+ break;
+
+ case 0x419c: // getting the bird
setOns(0, 0);
playSound(56, 10);
playActorAnimation(875);
disableObject(6);
- inventory->add(0x5c);
- return true;
+ inventory->add(kInvItemBird);
+ break;
+ case 0x41c3:
+ displayMessage(dsAddr_pullObjMsg2); // "I can't reach it"
+ break;
+
+ case 0x41ca:
+ rejectMessage();
+ break;
case 0x41ce:
moveTo(197, 159, 4);
@@ -236,9 +624,23 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playSound(71, 8);
playActorAnimation(833);
moveTo(225, 159, 4);
- inventory->add(0x4e);
+ inventory->add(kInvItemDelicatePlant);
disableObject(3);
- return true;
+ break;
+
+ case 0x422c:
+ displayMessage(dsAddr_tooWeakToClimbMsg); // "I'm too weak to climb it"
+ break;
+
+ case 0x4233:
+ loadScene(3, Common::Point(216, 199));
+ scene->setOrientation(1);
+ break;
+
+ case 0x424d:
+ loadScene(5, Common::Point(18, 174));
+ scene->setOrientation(2);
+ break;
case 0x4267:
hideActor();
@@ -252,92 +654,111 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playSound(5, 26);
playActorAnimation(842);
wait(100);
- //shown in different positions
- displayMessage(0x5656, 0xd1, 0x5510);
+ // shown in different positions
+ displayMessage(dsAddr_fnMsg2, textColorMark, 16, 68); // "And how am I supposed to get back?"
wait(50);
- displayMessage(0x567a, 0xd1, 0x555c);
+ displayMessage(dsAddr_fnMsg3, textColorMark, 92, 68); // "Great"
wait(50);
- displayMessage(0x5682, 0xd1, 0x553e);
+ displayMessage(dsAddr_fnMsg4, textColorMark, 62, 68); // "Oh, yeah, right"
wait(50);
playActorAnimation(843);
showActor();
moveTo(223, 149, 0, true);
disableObject(7);
disableObject(1);
- inventory->add(0x51);
- displayMessage(0x5646);
- return true;
+ inventory->add(kInvItemShovelAct1);
+ displayMessage(dsAddr_fnMsg1); // "Piece of cake"
+ break;
+
+ case 0x433a:
+ loadScene(10, Common::Point(294, 183));
+ scene->setOrientation(4);
+ break;
+
+ case 0x4354:
+ loadScene(4, Common::Point(300, 185));
+ scene->setOrientation(4);
+ break;
+
+ case 0x436e:
+ loadScene(2, Common::Point(219, 199));
+ scene->setOrientation(1);
+ break;
case 0x4388:
playSound(80, 4);
playActorAnimation(961);
loadScene(8, 155, 199, 1);
- return true;
+ break;
- case 0x43b5: //HQ, first trial - prison
+ case 0x43b5: // HQ, first trial - prison
playSound(70, 6);
playActorAnimation(962);
loadScene(7, 30, 184, 2);
- if (res->dseg.get_byte(0xDBDF) < 2) {
+ if (res->dseg.get_byte(dsAddr_FirstActTrialState) < 2) {
wait(150);
moveTo(134, 167, 2);
- displayMessage(0x54f7);
+ displayMessage(dsAddr_firstTrialMsg); // "Sir, I'm Mark. A rookie"
setLan(1, 0);
playAnimation(812, 0, true);
playActorAnimation(811);
- Dialog::show(scene, 0x6117, 0, 813, 0xd1, 0xec, 0, 1);
+ dialog->show(148, scene, 0, 813, textColorMark, textColorCaptain, 0, 1);
loadScene(6, 230, 184);
playMusic(5);
- Dialog::show(scene, 0x626a, 0, 814, 0xd1, 0xec, 0, 1);
+ dialog->show(149, scene, 0, 814, textColorMark, textColorCaptain, 0, 1);
playSound(4, 14);
playAnimation(815, 0);
setOns(1, 0);
- Dialog::showMono(scene, 0x62dc, 0, 0xd1, 0);
+ dialog->showMono(150, scene, 0, textColorMark, 0);
- SET_FLAG(0xDBDF, 1);
+ SET_FLAG(dsAddr_FirstActTrialState, 1);
}
- return true;
+ break;
case 0x4482:
- if (CHECK_FLAG(0xDBDF, 0)) {
+ if (CHECK_FLAG(dsAddr_FirstActTrialState, 0)) {
playActorAnimation(968);
- displayMessage(0x5511);
+ displayMessage(dsAddr_lockedMsg); // "It's Locked!"
} else {
playSound(80, 3);
playSound(79, 4);
playActorAnimation(968);
loadScene(6, 280, 186, 4);
}
- return true;
+ break;
- case 0x44fc: //pull out spring from bed
+ case 0x44fc: // pull out spring from bed
playSound(53, 25);
playSound(24, 27);
playSound(5, 36);
playActorAnimation(839);
moveTo(278, scene->getPosition().y, 0, true);
- inventory->add(0x50);
+ inventory->add(kInvItemSpring);
disableObject(1);
- return true;
+ break;
case 0x44cb:
- if (CHECK_FLAG(0xDBE5, 1)) {
- displayMessage(0x57c0);
+ if (CHECK_FLAG(dsAddr_gotRopeAct1Flag, 1)) {
+ displayMessage(dsAddr_vacMsg); // "What am I? A vacuum cleaner?!"
} else {
playSound(49, 14);
playSound(5, 21);
playActorAnimation(869);
- inventory->add(0x58);
- SET_FLAG(0xDBE5, 1);
+ inventory->add(kInvItemRopeAct1);
+ SET_FLAG(dsAddr_gotRopeAct1Flag, 1);
}
- return true;
+ break;
+
+ case 0x4532:
+ displayMessage(dsAddr_springPrickMsg); // "The springs would prick my back"
+ break;
- case 0x4539: //prison cell: use crates
- if (CHECK_FLAG(0xdbdd, 2)) {
- //finished the meal - trap
- displayMessage(0x55c0);
+ case 0x4539: // prison cell: use crates
+ if (CHECK_FLAG(dsAddr_JailCableAndBowlState, 2)) {
+ // finished the meal - trap
+ displayMessage(dsAddr_mealFinishedMsg); // "Hey! I finished my meal."
moveTo(306, 196, 2);
wait(50);
//playAnimation(825, 1); //very long empty animation. what for?
@@ -354,66 +775,65 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
loadScene(6, scene->getPosition());
setOns(3, 0x5b);
wait(50);
- displayMessage(0x55db);
- SET_FLAG(0xdbdd, 3);
+ displayMessage(dsAddr_bowlWeldedMsg); // "Wow. He got welded to the bowl"
+ SET_FLAG(dsAddr_JailCableAndBowlState, 3);
scene->getObject(4)->setName("body");
} else {
- if (Dialog::pop(scene, 0xdb5c, 0, 0, 0xd1, 0xd1, 0, 0) != 0x636b) //not 'im getting hungry'
- return true;
-
- wait(100);
- playSound(52, 8);
- playSound(52, 13);
- playAnimation(820, 1);
- setOns(3, 0x59);
- wait(50);
- moveTo(scene->getPosition().x, scene->getPosition().y + 1, 3);
- wait(150);
- moveTo(scene->getPosition().x, scene->getPosition().y - 1, 2);
- wait(100);
- displayMessage(0x551f);
- enableObject(4);
- SET_FLAG(0xdbdc, 1);
+ if (dialog->pop(scene, dsAddr_dialogStackJailDoorGrates, 0, 0, textColorMark, textColorMark, 0, 0) == 0x636b) { // 'im getting hungry'
+ wait(100);
+ playSound(52, 8);
+ playSound(52, 13);
+ playAnimation(820, 1);
+ setOns(3, 0x59);
+ wait(50);
+ moveTo(scene->getPosition().x, scene->getPosition().y + 1, 3);
+ wait(150);
+ moveTo(scene->getPosition().x, scene->getPosition().y - 1, 2);
+ wait(100);
+ displayMessage(dsAddr_ThanksMsg); // "Thanks."
+ enableObject(4);
+ SET_FLAG(dsAddr_GotFoodBowlInJailFlag, 1);
+ }
}
- return true;
+ break;
case 0x4662:
- if (CHECK_FLAG(0xDBDD, 3)) {
- if (CHECK_FLAG(0xDBDE, 1)) {
- displayMessage(0x5608);
+ if (CHECK_FLAG(dsAddr_JailCableAndBowlState, 3)) {
+ if (CHECK_FLAG(dsAddr_GotJailKeyFlag, 1)) {
+ displayMessage(dsAddr_noPocketMsg); // "I don't want to touch his pockets again."
} else {
moveTo(280, 179, 2);
playSound(49, 7);
playSound(5, 17);
playActorAnimation(827);
- inventory->add(0x4d);
- SET_FLAG(0xDBDE, 1);
+ inventory->add(kInvItemJailKey);
+ SET_FLAG(dsAddr_GotJailKeyFlag, 1);
}
} else
- displayMessage(0x5905);
- return true;
+ displayMessage(dsAddr_foodAliveMsg); // "No, thanks. This food seems still alive"
+ break;
- case 0x46af: //prison cell: use live cable
- if (CHECK_FLAG(0xdbdc, 1)) {
- displayMessage(0x555d);
+ case 0x46af: // prison cell: use live cable
+ if (CHECK_FLAG(dsAddr_GotFoodBowlInJailFlag, 1)) {
+ displayMessage(dsAddr_ideaMsg); // "That gives me an idea"
setOns(2, 0);
playActorAnimation(821);
setOns(2, 0x5a);
setOns(3, 0);
playSound(22, 2);
playActorAnimation(822);
- displayMessage(0x5577);
+ displayMessage(dsAddr_checkWorksMsg); // "Now I got to check if it works"
disableObject(5);
- SET_FLAG(0xdbdd, 1);
+ SET_FLAG(dsAddr_JailCableAndBowlState, 1);
} else
- displayMessage(0x5528);
- return true;
+ displayMessage(dsAddr_unkUsageMsg); // "I don't have any idea what to do with it right now"
+ break;
- case 0x4705: //prison: getting lamp bulb
+ case 0x4705: // prison: getting lamp bulb
wait(50);
moveTo(144, 185, 4);
playSound(56, 15);
- setOns(0, 86); //hiding lamp
+ setOns(0, 86); // hiding lamp
playActorAnimation(816, true);
playAnimation(817, 0, true);
waitAnimation();
@@ -430,69 +850,102 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
disableObject(6);
enableObject(5);
- inventory->add(0x4c);
- return true;
+ inventory->add(kInvItemBulb);
+ break;
- case 0x4794: //prison cell door
- if (res->dseg.get_byte(0xDBDF) >= 2) {
+ case 0x4794: // prison cell door
+ if (res->dseg.get_byte(dsAddr_FirstActTrialState) >= 2) {
loadScene(5, 287, 143);
} else {
- displayMessage(0x592f);
+ displayMessage(dsAddr_doorClosedMsg); // "The door is closed. What a surprise."
}
- return true;
+ break;
- case 0x47bc: //prison: examining trash can
+ case 0x47bc: // prison: examining trash can
playSound(79, 5);
playSound(1, 14);
playActorAnimation(966);
- displayMessage(0x5955);
- return true;
+ displayMessage(dsAddr_emptyMsg); // "It's Empty"
+ break;
- case 0x47db: //prison: use switch
- if (CHECK_FLAG(0xDBDF, 1)) {
+ case 0x47db: // prison: use switch
+ if (CHECK_FLAG(dsAddr_FirstActTrialState, 1)) {
playSound(71, 4);
playActorAnimation(823);
- if (CHECK_FLAG(0xDBDD, 0)) {
- displayMessage(0x4d80);
+ if (CHECK_FLAG(dsAddr_JailCableAndBowlState, 0)) {
+ displayMessage(dsAddr_NotHappenMsg); // "Nothing happened"
} else {
playSound(74, 1);
playAnimation(824, 1);
- if (CHECK_FLAG(0xDBDD, 1)) {
+ if (CHECK_FLAG(dsAddr_JailCableAndBowlState, 1)) {
wait(100);
- displayMessage(0x559a);
- SET_FLAG(0xDBDD, 2);
+ displayMessage(dsAddr_timeToCallMsg); // "I think it is time to call captain"
+ SET_FLAG(dsAddr_JailCableAndBowlState, 2);
}
}
} else {
- displayMessage(0x52f6);
+ displayMessage(dsAddr_nahMsg); // "Nah"
}
- return true;
+ break;
+
+ case 0x4836:
+ rejectMessage();
+ break;
case 0x4871:
playActorAnimation(965);
- displayMessage(0x5511);
- return true;
+ displayMessage(dsAddr_lockedMsg); // "It's Locked!"
+ break;
+
+ case 0x487e:
+ displayMessage(dsAddr_geographyClassMsg); // "I should have paid more attention in geography classes."
+ break;
+
+ case 0x4885:
+ displayMessage(dsAddr_dontNeedMessMsg); // "I don't need this mess"
+ break;
+
+ case 0x488c:
+ displayMessage(dsAddr_seenSofterRocksMsg); // "Thanks, but I've seen softer rocks"
+ break;
- case 0x4893: //taking pills
- if (CHECK_FLAG(0xDBE6, 1)) {
- SET_FLAG(0xDBE6, 2);
+ case 0x4893: // taking pills
+ if (CHECK_FLAG(dsAddr_captainDrawerState, 1)) {
+ SET_FLAG(dsAddr_captainDrawerState, 2);
setOns(1, 0x67);
playSound(5, 9);
playActorAnimation(872);
- inventory->add(0x5a);
+ inventory->add(kInvItemMedicine);
disableObject(7);
} else {
playActorAnimation(964);
- displayMessage(0x5511);
+ displayMessage(dsAddr_lockedMsg); // "It's Locked!"
}
- return true;
+ break;
+
+ case 0x48d4:
+ displayMessage(dsAddr_tooBluntMsg); // "They are too blunt to be of any use"
+ break;
+
+ case 0x48db:
+ displayMessage(dsAddr_uselessModelsMsg); // "What's the use of the models?"
+ break;
+
+ case 0x48e2:
+ case 0x48e6:
+ rejectMessage();
+ break;
+
+ case 0x4911:
+ displayMessage(dsAddr_barmanWillNoticeMsg); // "The barman will surely notice its disappearing"
+ break;
- case 0x4918: //talking with barmen
- if (CHECK_FLAG(0xDBE7, 1)) {
+ case 0x4918: // talking with barmen
+ if (CHECK_FLAG(dsAddr_birdOnBarRadioAntennaFlag, 1)) {
moveTo(140, 152, 1);
- if (CHECK_FLAG(0xDBE8, 1)) {
- Dialog::showMono(scene, 0x6f20, 0, 0xd1, 0); //aren't you thirsty?
- displayMessage(0x5883, 0xef, 21472);
+ if (CHECK_FLAG(dsAddr_swappedBarmanMugFlag, 1)) {
+ dialog->showMono(177, scene, 0, textColorMark, 0);
+ displayMessage(dsAddr_yeahRightMsg, textColorBarman, 32, 67); // "Yeah right!"
//reloadLan();
setLan(1, 0);
playAnimation(882, 0);
@@ -504,86 +957,145 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
shakeScreen();
disableObject(1);
disableObject(2);
- SET_FLAG(0xDBE9, 1);
+ SET_FLAG(dsAddr_barmanPassedOutFlag, 1);
} else
- displayMessage(0x5855);
+ displayMessage(dsAddr_talkNotNowMsg); // "I've got no reason to talk to him right now."
} else {
- if (CHECK_FLAG(0xDBDF, 3)) {
- if (CHECK_FLAG(0xDBE3, 1)) {
- Dialog::show(scene, 0x6BD6, 0, 857, 0xd1, 0xef, 0, 1);
+ if (CHECK_FLAG(dsAddr_FirstActTrialState, 3)) {
+ if (CHECK_FLAG(dsAddr_spokeToBarmanAboutThirdTrialFlag, 1)) {
+ dialog->show(168, scene, 0, 857, textColorMark, textColorBarman, 0, 1);
} else {
- Dialog::show(scene, 0x69B5, 0, 857, 0xd1, 0xef, 0, 1); //taking mug
+ dialog->show(166, scene, 0, 857, textColorMark, textColorBarman, 0, 1); // taking mug
playActorAnimation(859, true);
playAnimation(858, 0, true);
waitAnimation();
playSound(75, 6);
playActorAnimation(860);
- Dialog::show(scene, 0x69C2, 0, 857, 0xd1, 0xef, 0, 1);
- inventory->add(0x55);
- SET_FLAG(0xDBE3, 1);
- SET_FLAG(0xDBF0, 0);
+ dialog->show(167, scene, 0, 857, textColorMark, textColorBarman, 0, 1);
+ inventory->add(kInvItemMug);
+ SET_FLAG(dsAddr_spokeToBarmanAboutThirdTrialFlag, 1);
+ SET_FLAG(dsAddr_gotPasswordNeedSpeakBarmanFlag, 0);
}
} else {
- Dialog::pop(scene, 0xDB68, 0, 857, 0xd1, 0xef, 0, 1);
+ dialog->pop(scene, dsAddr_dialogStackBarman, 0, 857, textColorMark, textColorBarman, 0, 1);
}
}
- return true;
+ break;
- case 0x4f14: //use the hollow
- displayMessage(CHECK_FLAG(0xDBA1, 1) ? 0x370f : 0x36c2);
- return true;
+ case 0x4d7d:
+ case 0x4d81:
+ rejectMessage();
+ break;
+
+ case 0x4d89:
+ displayMessage(dsAddr_getRidOfGuardFirstMsg); // "If I want to get inside I must get rid of this guard first..."
+ break;
+
+ case 0x4d90:
+ rejectMessage();
+ break;
+
+ case 0x4e47:
+ loadScene(13, Common::Point(9, 172));
+ scene->setOrientation(2);
+ break;
+
+ case 0x4e85:
+ loadScene(15, Common::Point(291, 162));
+ scene->setOrientation(4);
+ break;
+
+ case 0x4e9f:
+ loadScene(12, Common::Point(310, 152));
+ scene->setOrientation(4);
+ break;
+
+ case 0x4f14: // use the hollow
+ if (CHECK_FLAG(dsAddr_mansionTreeHollowEmptyFlag, 1))
+ displayMessage(dsAddr_totalEmptyMsg); // "I can see it's totally empty"
+ else
+ displayMessage(dsAddr_noHandsMsg); // "I'd better not put my hands in there..."
+ break;
case 0x4a64:
- if (CHECK_FLAG(0xDBF0, 1)) {
- displayMessage(0x5e25);
- } else {
+ if (CHECK_FLAG(dsAddr_gotPasswordNeedSpeakBarmanFlag, 1))
+ displayMessage(dsAddr_firstBusinessMsg); // "First I've got some business to take care of"
+ else
loadScene(5, 35, 162);
- }
- return true;
+ break;
case 0x4bf5:
playActorAnimation(959);
loadScene(8, 40, 152, 3);
- return true;
+ break;
+
+ case 0x4c18:
+ rejectMessage();
+ break;
+
+ case 0x4c29:
+ displayMessage(dsAddr_tooManyToSearchMsg); // "There are too many of them to search"
+ break;
+
+ case 0x4c30:
+ case 0x4c37:
+ displayMessage(dsAddr_captainWouldNotFitMsg); // "Captain surely wouldn't fit them. I must look elsewhere"
+ break;
case 0x483a:
- Dialog::pop(scene, 0xdb82, 0, 0, 0xd1, 0xd1, 0, 0);
- return true;
+ dialog->popMark(scene, dsAddr_dialogStackInterrogateCaptain);
+ break;
case 0x4844:
playSound(80, 4);
playActorAnimation(963);
loadScene(5, 166, 158);
- return true;
+ break;
case 0x48ea:
setOns(0, 0);
playSound(5, 9);
playActorAnimation(836);
- inventory->add(0x4f);
+ inventory->add(kInvItemSwissArmyKnife);
disableObject(12);
- return true;
+ break;
case 0x4a8c:
- if (CHECK_FLAG(0xDBE9, 1)) {
+ if (CHECK_FLAG(dsAddr_barmanPassedOutFlag, 1)) {
playSound(89, 5);
playActorAnimation(958);
loadScene(9, 240, 182, 4);
- } else if (CHECK_FLAG(0xDBE7, 1)) {
- displayMessage(0x5894);
+ } else if (CHECK_FLAG(dsAddr_birdOnBarRadioAntennaFlag, 1)) {
+ displayMessage(dsAddr_barmanTooCloseMsg); // "The barman is too close"
} else {
- Dialog::pop(scene, 0xDB8A, 0, 857, 0xd1, 0xef, 0, 1);
+ dialog->pop(scene, dsAddr_dialogStackBarCellarDoor, 0, 857, textColorMark, textColorBarman, 0, 1);
}
- return true;
+ break;
- case 0x4af4: //taking the crumbs
+ case 0x4aed:
+ displayMessage(dsAddr_tooBigMsg); // "It's too big and I doubt if I'll ever need it"
+ break;
+
+ case 0x4af4: // taking the crumbs
setOns(0, 0);
playSound(49, 6);
playSound(5, 13);
playActorAnimation(861);
- inventory->add(0x57);
+ inventory->add(kInvItemCrumbs);
disableObject(6);
- return true;
+ break;
+
+ case 0x4b23:
+ rejectMessage();
+ break;
+
+ case 0x4b27:
+ displayMessage(dsAddr_tooMuchToDrinkMsg); // "It'd take too much time to drink it..."
+ break;
+
+ case 0x4b2e:
+ displayMessage(dsAddr_notThiefMsg); // "I'm not a thief. And it's empty, by the way."
+ break;
case 0x4b35:
playSound(15, 7);
@@ -591,140 +1103,149 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playSound(55, 1);
playSound(24, 12);
playAnimation(885, 0);
- Dialog::show(scene, 0x67e5, 886, 0, 0xd0, 0xd1, 1, 0);
+ dialog->show(164, scene, 886, 0, textColorJohnNoty, textColorMark, 1, 0);
playMusic(3);
loadScene(40, 198, 186, 1);
- Dialog::show(scene, 0x7f20, 0, 920, 0xd1, 0xe7, 0, 1);
+ dialog->show(202, scene, 0, 920, textColorMark, textColorRGBBoss, 0, 1);
inventory->clear();
- inventory->add(0x1d);
- displayCredits(0xe45c);
+ inventory->add(kInvItemSuperGlue);
+ displayCredits(dsAddr_credits5);
loadScene(1, 198, 186);
hideActor();
playActorAnimation(956);
- Dialog::showMono(scene, 0x8bc4, 957, 0xd1, 1);
+ dialog->showMono(212, scene, 957, textColorMark, 1);
waitAnimation();
loadScene(15, 157, 199, 1);
playMusic(6);
- return true;
+ break;
- case 0x4c3e: //get the grenade
+ case 0x4c3e: // get the grenade
playSound(32, 24);
playActorAnimation(862);
reloadLan();
playAnimation(863, 1);
- inventory->add(0x54);
+ inventory->add(kInvItemGrenade);
disableObject(1);
- SET_FLAG(0xDBE2, 2);
- return true;
+ SET_FLAG(dsAddr_act1GuardState, 2);
+ break;
case 0x4c70:
- if (CHECK_FLAG(0xDBE2, 0)) {
- if (CHECK_FLAG(0xDBDA, 1)) { //papers are shown
- Dialog::pop(scene, 0xDB4C, 0, 809, 0xd1, 0xd0, 0, 1);
+ if (CHECK_FLAG(dsAddr_act1GuardState, 0)) {
+ if (CHECK_FLAG(dsAddr_ShownPassToGuardFlag, 1)) { // papers are shown
+ dialog->pop(scene, dsAddr_dialogStackCampGuardReadingNews, 0, 809, textColorMark, textColorCampGuard, 0, 1);
} else {
- Dialog::pop(scene, 0xDB40, 0, 809, 0xd1, 0xd0, 0, 1);
+ dialog->pop(scene, dsAddr_dialogStackCampGuardWantsDocuments, 0, 809, textColorMark, textColorCampGuard, 0, 1);
}
} else {
- displayMessage(0x5722);
+ displayMessage(dsAddr_helloQMsg); // "Hello?"
wait(100);
- displayMessage(0x572a);
+ displayMessage(dsAddr_totallyAddictedMsg); // "He's totally addicted"
}
- return true;
+ break;
case 0x4c1c:
playActorAnimation(960);
- displayMessage(0x5511);
- return true;
+ displayMessage(dsAddr_lockedMsg); // "It's Locked!"
+ break;
+
+ case 0x4ca5:
+ displayMessage(dsAddr_chickenNeverMsg); // "Chickening? Me? Never!"
+ break;
case 0x4cac:
- if (CHECK_FLAG(0xdbda, 1)) { //papers are shown
+ if (CHECK_FLAG(dsAddr_ShownPassToGuardFlag, 1)) { // papers are shown
loadScene(5, 124, 199);
} else {
- Dialog::show(scene, 0x5FE9, 0, 809, 0xd1, 0xd0, 0, 1);
+ dialog->show(144, scene, 0, 809, textColorMark, textColorCampGuard, 0, 1);
moveTo(269, 175, 4);
- Dialog::pop(scene, 0xDB56, 0, 809, 0xd1, 0xd0, 0, 1);
+ dialog->pop(scene, dsAddr_dialogStackCampGuardShowPass, 0, 809, textColorMark, textColorCampGuard, 0, 1);
}
- return true;
-
- case 0x4cf1: { //talking with mansion guard
- SET_FLAG(0xda96, 1);
- if (Dialog::pop(scene, 0xdaa6, 0, 529, 0xd1, 0xd9, 0, 1) != 0x1b4)
- return true;
+ break;
- Common::Point p = scene->getPosition();
- moveTo(189, 159, 0);
- //waitLanAnimationFrame(1, 1);
+ case 0x4cf1: // talking with mansion guard
+ SET_FLAG(dsAddr_spokenWithMansionGuardFlag, 1);
+ if (dialog->pop(scene, dsAddr_dialogStackPleadingToMansionGuard, 0, 529, textColorMark, textColorMansionGuard, 0, 1) == 0x01b4) { // 2nd try
+ Common::Point p = scene->getPosition();
+ moveTo(189, 159, 0);
+ //waitLanAnimationFrame(1, 1);
- playSound(5, 2);
- playSound(5, 19);
- playActorAnimation(550, true);
- playAnimation(551, 0, true);
- waitAnimation();
+ playSound(5, 2);
+ playSound(5, 19);
+ playActorAnimation(550, true);
+ playAnimation(551, 0, true);
+ waitAnimation();
- moveTo(p, 2);
- inventory->add(0x13);
- Dialog::pop(scene, 0xdaa6, 0, 529, 0xd1, 0xd9, 0, 1);
- }
- return true;
+ moveTo(p, 2);
+ inventory->add(kInvItemChocCandy);
+ dialog->pop(scene, dsAddr_dialogStackPleadingToMansionGuard, 0, 529, textColorMark, textColorMansionGuard, 0, 1);
+ }
+ break;
- case 0x4d94: //talking with fatso
- Dialog::show(scene, 0x33bd, 0, 666, 0xd1, 0xd0, 0, 2);
- displayAsyncMessage(0x49ae, /*25060*/ 35000, 1, 10, 0xd0);
+ case 0x4d94: // talking with fatso
+ dialog->show(87, scene, 0, 666, textColorMark, textColorJohnNoty, 0, 2);
+ displayAsyncMessage(dsAddr_BribeMsg, 120, 109, 1, 10, textColorJohnNoty); // FIXME: Original (x,y) was (100, 78), rather than (120, 109)?
playSound(5, 3);
playAnimation(667, 1);
playAnimation(668, 1);
setOns(2, 50);
- Dialog::show(scene, 0x36c7, 0, 666, 0xd1, 0xd0, 0, 2);
+ dialog->show(88, scene, 0, 666, textColorMark, textColorJohnNoty, 0, 2);
setOns(3, 0);
- setFlag(0xDBEC, 0);
+ setFlag(dsAddr_johnNotyOutsideMansionDoorFlag, 0);
reloadLan();
playSound(82, 19);
playAnimation(669, 1);
- Dialog::showMark(scene, 0x3779);
+ dialog->showMark(89, scene);
enableObject(15);
disableObject(8);
- return true;
+ break;
case 0x4e61:
loadScene(14, 280, 198);
- return true;
+ break;
case 0x4ee5:
setOns(2, 0);
playSound(5, 12);
playActorAnimation(676);
- displayMessage(0x4ab0);
+ displayMessage(dsAddr_WimpMsg); // "I'm a pathetic little wimp"
disableObject(15);
- inventory->add(51);
- return true;
+ inventory->add(kInvItemBanknote);
+ break;
case 0x4d56:
- inventory->add(16);
+ inventory->add(kInvItemWhisky);
disableObject(2);
setOns(0, 0);
playSound(5, 12);
playActorAnimation(547);
- return true;
+ break;
+ case 0x4d85:
+ rejectMessage();
+ break;
- case 0x4eb9://Pick up wrapper
+ case 0x4eb9: // Pick up wrapper
playSound(5, 12);
playSound(5, 18);
- inventory->add(0x12);
+ inventory->add(kInvItemWrapper);
setOns(1, 0);
playActorAnimation(549);
disableObject(13);
- return true;
+ break;
+
+ case 0x4ee1:
+ rejectMessage();
+ break;
case 0x4f25:
playActorAnimation(967);
- displayMessage(0x3542);
- return true;
+ displayMessage(dsAddr_tooHardWoodMsg); // "This wood is too hard to break"
+ break;
- case 0x4f32: //use tree near the mansion
- if (CHECK_FLAG(0xDBA1, 1)) {
- if (CHECK_FLAG(0xDBA2, 1)) {
- displayMessage(0x3766);
+ case 0x4f32: // use tree near the mansion
+ if (CHECK_FLAG(dsAddr_mansionTreeHollowEmptyFlag, 1)) {
+ if (CHECK_FLAG(dsAddr_climbedMansionTreeAlreadyFlag, 1)) {
+ displayMessage(dsAddr_noChanceMsg); // "I won't take my chances a second time"
} else {
playSound(26, 13);
playSound(26, 15);
@@ -739,95 +1260,126 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playSound(60, 16);
playActorAnimation(591);
wait(50);
- displayMessage(0x372e);
- SET_FLAG(0xDBA2, 1);
- processCallback(0x9d45);
+ displayMessage(dsAddr_oneSmallStepMsg); // "One small step for man, one big pain in the head"
+ SET_FLAG(dsAddr_climbedMansionTreeAlreadyFlag, 1);
+ fnMansionIntrusionAttempt();
}
} else {
playActorAnimation(49);
playSound(56, 8);
playSound(56, 12);
playSound(49, 10);
- displayAsyncMessage(0x4652, 31579, 16, 24);
+ displayAsyncMessage(dsAddr_laughterMsg, 219, 98, 16, 24); // "(laughter)"
playActorAnimation(587);
moveRel(0, 0, 2);
wait(100);
- displayMessage(0x3668);
+ displayMessage(dsAddr_tickledMsg); // "Something tickled me!"
}
- return true;
+ break;
- case 0x500d: //picking up wild plant
- if (CHECK_FLAG(0xDB9E, 1)) {
- displayMessage(0x35E8); //there are no more
+ case 0x500d: // picking up wild plant
+ if (CHECK_FLAG(dsAddr_gotPotatoAlreadyFlag, 1)) {
+ displayMessage(dsAddr_noPotatoMsg); // "There are no more potatoes"
} else {
- SET_FLAG(0xDB9E, 1);
+ SET_FLAG(dsAddr_gotPotatoAlreadyFlag, 1);
setOns(2, 0);
playSound(21, 9);
playSound(34, 21);
playSound(26, 30);
playActorAnimation(552);
setOns(2, 0x12);
- inventory->add(0x14);
+ inventory->add(kInvItemPotato);
}
- return true;
+ break;
+
+ case 0x505f:
+ displayMessage(dsAddr_wallTooSmoothMsg); // "The wall surface is too smooth to climb"
+ break;
+
+ case 0x5066:
+ loadScene(11, Common::Point(183, 109));
+ scene->setOrientation(3);
+ break;
+
+ case 0x5080:
+ loadScene(13, Common::Point(290, 181));
+ scene->setOrientation(4);
+ break;
+
+ case 0x50f6:
+ displayMessage(dsAddr_tooMuchResinToClimbMsg); // "I could climb it if there wasn't so much resin"
+ break;
+
+ case 0x50fd:
+ displayMessage(dsAddr_onlyGreenRectMsg); // "The only green stuff that I like is that rectangular piece of paper with..."
+ break;
case 0x5104:
loadScene(11, 319, 198, 4);
- if (CHECK_FLAG(0xDB9C, 1))
- return true;
-
- //guard's drinking
- SET_FLAG(0, 3);
- setTimerCallback(0x516d, 40);
- playAnimation(544, 0, true, true); //ignore busy flag for this animation
- return true;
+ if (!CHECK_FLAG(dsAddr_scaredGuardAlreadyFlag, 1)) {
+ // guard is drinking
+ SET_FLAG(dsAddr_timedCallbackState, 3);
+ setTimerCallback(csAddr_guardScareTimeout, 40);
+ playAnimation(544, 0, true, true); // ignore busy flag for this animation
+ }
+ break;
- case 0x516d: //too late to scare guard, resetting
- SET_FLAG(0, 0);
- return true;
+ case csAddr_guardScareTimeout: // too late to scare guard, resetting
+ SET_FLAG(dsAddr_timedCallbackState, 0);
+ break;
- case 0x5189: //guard's drinking, boo!
- SET_FLAG(0, 0);
- setTimerCallback(0, 0);
- scene->getAnimation(0)->free();
- SET_FLAG(0xDB9C, 1);
+ case csAddr_guardDrinking:
+ fnGuardDrinking();
+ break;
- displayAsyncMessage(0x3563, 320 * 130 + 300, 1, 5);
- setOns(0, 16);
- enableObject(2);
+ case 0x51c8:
+ displayMessage(dsAddr_wallTooSmoothMsg); // "The wall surface is too smooth to climb"
+ break;
- playSound(17, 5);
- playAnimation(545, 0);
+ case 0x51cf:
+ loadScene(12, Common::Point(15, 189));
+ scene->setOrientation(2);
+ break;
- Dialog::show(scene, 0x0917, 0, 546, 0xd1, 0xd9, 0, 1);
- SET_FLAG(0xDA96, 1);
- SET_FLAG(0xDA97, 0);
- return true;
+ case 0x51e9:
+ displayMessage(dsAddr_dontWannaTouchHedgehogMsg); // "I don't wanna touch it. Its spines could hurt my delicate hands"
+ break;
case 0x51f0:
setOns(0, 0);
playSound(5, 11);
playActorAnimation(637);
disableObject(7);
- inventory->add(49);
- return true;
+ inventory->add(kInvItemRock);
+ break;
case 0x5217:
- displayMessage(CHECK_FLAG(0xDB9F, 1) ? 0x402e : 0x34e1);
- return true;
+ if (CHECK_FLAG(dsAddr_beesGoneFlag, 1))
+ displayMessage(dsAddr_notHungryMsg); // "Thanks, I'm not hungry"
+ else
+ displayMessage(dsAddr_avoidBeesMsg); // "I'm going to stay at least five meters away from these bees!"
+ break;
+
+ case 0x522c:
+ displayMessage(dsAddr_avoidBeesMsg); // "I'm going to stay at least five meters away from these bees!"
+ break;
+
+ case 0x5233:
+ rejectMessage();
+ break;
case 0x5237:
- if (!CHECK_FLAG(0xDB9F, 1)) {
- displayMessage(0x34e1);
- } else if (CHECK_FLAG(0xDBA0, 1))
- displayMessage(0x3E31);
+ if (!CHECK_FLAG(dsAddr_beesGoneFlag, 1)) {
+ displayMessage(dsAddr_avoidBeesMsg); // "I'm going to stay at least five meters away from these bees!"
+ } else if (CHECK_FLAG(dsAddr_mansionTunnelDoneFlag, 1))
+ displayMessage(dsAddr_roadNowhereMsg); // "Nah. It's a road to nowhere"
else {
moveTo(173, 138, 2);
playSound(28, 5);
playActorAnimation(583);
playActorAnimation(584);
- loadScene(0, 0, 0, 0); //clear background
+ loadScene(0, 0, 0, 0); // clear background
playSound(72, 18);
playSound(73, 39);
@@ -837,82 +1389,257 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playSound(28, 2);
playActorAnimation(586);
moveTo(138, 163, 3);
- displayMessage(0x3650);
- SET_FLAG(0xDBA0, 1);
- processCallback(0x9d45); //another mansion try
+ displayMessage(dsAddr_lifeBrutalMsg); // "Life is really brutal"
+ SET_FLAG(dsAddr_mansionTunnelDoneFlag, 1);
+ fnMansionIntrusionAttempt();
}
- return true;
-
- case 0x55a8: {
- uint16 d = Dialog::pop(scene, 0xdb08, 0, 0, 0xd1, 0xd1, 0, 0);
- if (d == 0x2c5d) {
- waitLanAnimationFrame(1, 0x23);
- setOns(0, 0);
- playSound(52, 9);
- playSound(52, 11);
- playSound(52, 13);
- playSound(53, 32);
- playAnimation(570, 0);
- wait(50);
- displayMessage(0x551f);
- disableObject(5);
- SET_FLAG(0xDBB0, 1);
- } else if (d != 0x2c9b) {
- waitLanAnimationFrame(1, 0x23);
- playSound(52, 9);
- playSound(52, 11);
- playSound(52, 13);
- playAnimation(569, 0);
+ break;
+
+ case 0x5320:
+ loadScene(11, Common::Point(30, 124));
+ scene->setOrientation(2);
+ break;
+
+ case 0x533a:
+ displayMessage(dsAddr_noLongHandsMsg); // "I really don't have such long hands"
+ break;
+
+ case 0x5341:
+ displayMessage(dsAddr_tooFarToSwimMsg); // "It's too far to swim there"
+ break;
+
+ case 0x5403:
+ displayMessage(dsAddr_noBucketMsg); // "It's not a barrel-organ. And there's no bucket."
+ break;
+
+ case 0x540a:
+ loadScene(20, Common::Point(10, 185));
+ scene->setOrientation(2);
+ break;
+
+ case 0x5424:
+ loadScene(11, Common::Point(30, 170));
+ scene->setOrientation(2);
+ break;
+
+ case 0x543e:
+ loadScene(18, Common::Point(224, 199));
+ scene->setOrientation(4);
+ break;
+
+ case 0x5547:
+ loadScene(15, Common::Point(15, 172));
+ scene->setOrientation(2);
+ break;
+
+ case 0x55a8:
+ {
+ uint16 d = dialog->popMark(scene, dsAddr_dialogStackSquirrel);
+ if (d == 0x2c5d) { // 4th try - Throw Nut
+ waitLanAnimationFrame(1, 0x23);
+ setOns(0, 0);
+ playSound(52, 9);
+ playSound(52, 11);
+ playSound(52, 13);
+ playSound(53, 32);
+ playAnimation(570, 0);
+ wait(50);
+ displayMessage(dsAddr_ThanksMsg); // "Thanks."
+ disableObject(5);
+ SET_FLAG(dsAddr_squirrelNutState, 1);
+ } else if (d != 0x2c9b) { // 5th (last) try
+ waitLanAnimationFrame(1, 0x23);
+ playSound(52, 9);
+ playSound(52, 11);
+ playSound(52, 13);
+ playAnimation(569, 0);
+ }
}
- }
- return true;
+ break;
case 0x5663:
- displayMessage(CHECK_FLAG(0xDBB0, 1) ? 0x41b1 : 0x417e);
- return true;
+ if (CHECK_FLAG(dsAddr_squirrelNutState, 1))
+ displayMessage(dsAddr_findNutMsg); // "I won't find the nut just like that. The grass is too dense"
+ else
+ displayMessage(dsAddr_hmmGrassMsg); // "Hmmm. Grass..."
+ break;
+
+ case 0x5674:
+ loadScene(18, Common::Point(94, 115));
+ scene->setOrientation(3);
+ break;
+
+ case 0x568e:
+ displayMessage(dsAddr_notHornyMsg); // "I'm not horny"
+ break;
+
+ case 0x5695:
+ displayMessage(dsAddr_dontNeedToOpenMsg); // "I don't need to open it"
+ break;
case 0x569c:
playSound(67, 5);
playActorAnimation(983);
- displayMessage(0x5955);
- return true;
+ displayMessage(dsAddr_emptyMsg); // "It's Empty"
+ break;
+
+ case 0x56b3:
+ rejectMessage();
+ break;
case 0x56b7:
playSound(66, 5);
playSound(67, 11);
playActorAnimation(984);
- displayMessage(0x5955);
- return true;
+ displayMessage(dsAddr_emptyMsg); // "It's Empty"
+ break;
+
+ case 0x56d6:
+ displayMessage(dsAddr_CantJumpMsg); // "No way I can jump so high, cause, err, white men can't jump"
+ break;
+
+ case 0x56dd:
+ displayMessage(dsAddr_dontNeedItMsg); // "I don't need it"
+ break;
+
+ case 0x56e4:
+ displayMessage(dsAddr_notSantaClausMsg); // "I'm not Santa Claus"
+ break;
+
+ case 0x56eb:
+ displayMessage(dsAddr_noPlasticImitationsMsg); // "I don't need plastic imitations"
+ break;
+
+ case 0x56f2:
+ rejectMessage();
+ break;
+
+ case 0x5721:
+ displayMessage(dsAddr_dontNeedItMsg); // "I don't need it"
+ break;
case 0x5728:
- inventory->add(0x0d);
+ inventory->add(kInvItemChainsaw);
disableObject(14);
setOns(0, 0);
playSound(5, 10);
playActorAnimation(566);
- return true;
+ break;
+
+ case 0x574f:
+ displayMessage(dsAddr_tooFragileMsg); // "It's too fragile to carry around"
+ break;
case 0x5793:
- if (!CHECK_FLAG(0xDB94, 1)) {
- displayMessage(0x3e63);
- } else if (CHECK_FLAG(0xDB95, 1)) {
- displayMessage(0x3e75);
+ if (!CHECK_FLAG(dsAddr_alreadyPulledTrunkReleaseLeverFlag, 1)) {
+ displayMessage(dsAddr_shutTightMsg); // "It's shut tight"
+ } else if (CHECK_FLAG(dsAddr_carTrunkEmptyFlag, 1)) {
+ displayMessage(dsAddr_bootEmptyMsg); // "There's nothing else in the boot"
} else {
- SET_FLAG(0xDB95, 1);
+ SET_FLAG(dsAddr_carTrunkEmptyFlag, 1);
moveTo(188, 179, 0);
playSound(7, 16);
playActorAnimation(519);
wait(150);
moveTo(168, 179, 2);
- inventory->add(3);
+ inventory->add(kInvItemToolboxFull);
}
- return true;
+ break;
+
+ case 0x57fa:
+ displayMessage(dsAddr_dontNeedItMsg); // "I don't need it"
+ break;
+
+ case 0x5801:
+ rejectMessage();
+ break;
+
+ case 0x583f:
+ case 0x5846:
+ displayMessage(dsAddr_dontNeedToOpenMsg);
+ break;
+
+ case 0x584d:
+ displayMessage(dsAddr_pullObjMsg2);
+ break;
+
+ case 0x5854:
+ loadScene(15, Common::Point(157, 199));
+ scene->setOrientation(1);
+ break;
+
+ case 0x586e:
+ loadScene(21, Common::Point(24, 187));
+ scene->setOrientation(2);
+ break;
+
+ case 0x5888:
+ loadScene(27, Common::Point(108, 199));
+ scene->setOrientation(2);
+ break;
+
+ case 0x5903:
+ displayMessage(dsAddr_keepItOpenMsg); // "I'd like to keep it open"
+ break;
+
+ case 0x590a:
+ loadScene(20, Common::Point(304, 190));
+ scene->setOrientation(4);
+ break;
+
+ case 0x5924:
+ loadScene(25, Common::Point(298, 146));
+ scene->setOrientation(4);
+ break;
+
+ case 0x5978:
+ displayMessage(dsAddr_notTakingSocksMsg); // "I really don't want to walk around with someone else's socks"
+ break;
+
+ case 0x597f:
+ case 0x5986:
+ case 0x598d:
+ displayMessage(dsAddr_dontNeedToOpenMsg); // "I don't need to open it"
+ break;
+
+ case 0x5b44:
+ // FIXME - This is the doorbell use callback on House #2
+ // i.e. Granny and Anne's House. Need to analyse cseg data properly.
+ // Current code inferred from behaviour.
+ // FIXME - Add animation call for Ego pushing doorbell.
+ displayMessage(dsAddr_ItsOpenMsg);
+ break;
+
+ case 0x5c72:
+ displayMessage(dsAddr_notTiredMsg); // "Thanks, I'm not tired"
+ break;
+
+ case 0x5c79:
+ displayMessage(dsAddr_dontNeedToOpenMsg); // "I don't need to open it"
+ break;
+
+ case 0x5c80:
+ rejectMessage();
+ break;
+
+ case 0x5cdb:
+ case 0x5ce2:
+ displayMessage(dsAddr_dontNeedItMsg); // "I don't need it"
+ break;
+
+ case 0x5ce9:
+ displayMessage(dsAddr_tooBigMsg); // "It's too big and I doubt if I'll ever need it"
+ break;
+
+ case 0x5d1d:
+ displayMessage(dsAddr_CantJumpMsg); // "No way I can jump so high, cause, err, white men can't jump"
+ break;
case 0x5d88:
- if (CHECK_FLAG(0xDBA5, 1)) { //dry laundry
- SET_FLAG(0xDBA5, 2);
- Dialog::show(scene, 0x1F4F, 0, 523, 0xd1, 0xe5, 0, 1);
- //waitLanAnimationFrame(1, 1); //another long waiting
+ if (CHECK_FLAG(dsAddr_laundryState, 1)) { // dry laundry
+ SET_FLAG(dsAddr_laundryState, 2);
+ dialog->show(46, scene, 0, 523, textColorMark, textColorOldLady, 0, 1);
+ //waitLanAnimationFrame(1, 1); // another long waiting
playAnimation(604, 0);
loadScene(21, scene->getPosition());
@@ -924,184 +1651,393 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
setOns(0, 33);
loadScene(23, scene->getPosition());
playAnimation(605, 0);
- Dialog::show(scene, 0x2002, 0, 523, 0xd1, 0xe5, 0, 1);
+ dialog->show(47, scene, 0, 523, textColorMark, textColorOldLady, 0, 1);
} else {
- uint16 d = Dialog::pop(scene, 0xdada, 0, 523, 0xd1, 0xe5, 0, 1);
- if (d == 0x1913) {
+ uint16 d = dialog->pop(scene, dsAddr_dialogStackAskOldLadyOK, 0, 523, textColorMark, textColorOldLady, 0, 1);
+ if (d == 0x1913) { // 3rd time
wait(100);
moveRel(0, 0, 3);
wait(50);
- displayMessage(0x34d5); //I give up
+ displayMessage(dsAddr_giveUpMsg); // "I give up"
wait(50);
}
}
- return true;
+ break;
+
+ case 0x5f9a:
+ case 0x5fa1:
+ displayMessage(dsAddr_dontNeedToOpenMsg); // "I don't need to open it"
+ break;
- case 0x5ff3: //get duster
- if (CHECK_FLAG(0xDB9A, 0)) {
- Dialog::pop(scene, 0xdaf6, 0, 523, 0xd1, 0xe5, 0, 1);
+ case 0x5fa8:
+ displayMessage(dsAddr_CantJumpMsg); // "No way I can jump so high, cause, err, white men can't jump"
+ break;
+
+ case 0x5faf:
+ displayMessage(dsAddr_noSecretPassageMsg); // "I don't think there's any secret passage inside"
+ break;
+
+ case 0x5fe5:
+ displayMessage(dsAddr_jugMeMsg); // "They can jug me if I steal this"
+ break;
+
+ case 0x5fec:
+ displayMessage(dsAddr_leaveFlowersAloneMsg); // "I'd better leave it. Women are really oversensitive about flowers."
+ break;
+
+ case 0x5ff3: // get duster
+ if (CHECK_FLAG(dsAddr_givenFlowerToOldLadyAlreadyFlag, 0)) {
+ dialog->pop(scene, dsAddr_dialogStackBorrowDusterFromOldLady, 0, 523, textColorMark, textColorOldLady, 0, 1);
} else {
- Dialog::show(scene, 0x1e1e, 0, 523, 0xd1, 0xe5, 0, 1);
+ dialog->show(43, scene, 0, 523, textColorMark, textColorOldLady, 0, 1);
wait(50);
- inventory->add(12);
+ inventory->add(kInvItemFeatherDusterClean);
disableObject(12);
setOns(0, 0);
playSound(5, 6);
playActorAnimation(541);
}
- return true;
+ break;
+
+ case 0x603a:
+ rejectMessage();
+ break;
case 0x603e:
- if (CHECK_FLAG(0xDBB3, 1)) {
- displayMessage(0x44a7);
+ if (CHECK_FLAG(dsAddr_spokenToMirrorFlag, 1)) {
+ displayMessage(dsAddr_busyThinkingMsg); // "I'd better not interrupt it's thought process"
} else {
- displayMessage(0x4412);
+ displayMessage(dsAddr_mirrorMirrorMsg); // "Mirror, Mirror on the wall...."
wait(150);
- displayMessage(0x444f);
+ displayMessage(dsAddr_thinkTooLongMsg); // "Hey, don't think too long"
wait(150);
- displayMessage(0x446b);
+ displayMessage(dsAddr_HintMaleMsg); // "A hint: Someone in this room, a male"
wait(150);
- displayMessage(0x4492);
+ displayMessage(dsAddr_okWaitMsg); // "OK, take your time"
wait(150);
- SET_FLAG(0xDBB3, 1);
+ SET_FLAG(dsAddr_spokenToMirrorFlag, 1);
}
- return true;
+ break;
+
+ case 0x6074:
+ rejectMessage();
+ break;
+
+ case 0x6078:
+ displayMessage(dsAddr_tooBigMsg); // "It's too big and I doubt if I'll ever need it"
+ break;
case 0x6205:
- if (CHECK_FLAG(0xDBA4, 1))
- displayMessage(0x450e);
+ if (CHECK_FLAG(dsAddr_lightOnFlag, 1))
+ displayMessage(dsAddr_tooHeavyMsg); // "It's too heavy. Not that I'm wimp"
else
- processCallback(0x61fe);
- return true;
+ fnTooDark();
+ break;
case 0x6217:
- if (CHECK_FLAG(0xDBA4, 1))
- displayMessage(0x44d6);
+ if (CHECK_FLAG(dsAddr_lightOnFlag, 1))
+ displayMessage(dsAddr_noDentistsMsg); // "I don't want to have anything in common with dentists"
else
- processCallback(0x61fe);
- return true;
+ fnTooDark();
+ break;
case 0x62c1:
- if (CHECK_FLAG(0xDBA4, 1))
- return false;
+ if (CHECK_FLAG(dsAddr_lightOnFlag, 1))
+ retVal = false;
+ else
+ fnTooDark();
+ break;
- processCallback(0x61fe);
- return true;
+ case 0x634a:
+ displayMessage(dsAddr_noHandsSharpThornsMsg); // "I can't remove it with my hands. these thorns look really sharp"
+ break;
+
+ case 0x637f:
+ loadScene(21, Common::Point(201, 199));
+ scene->setOrientation(1);
+ break;
+
+ case 0x6399:
+ displayMessage(dsAddr_rockWalkingGeeMsg); // "Yeah, great idea. Let's take this rock and walk around a bit. Gee..."
+ break;
+
+ case 0x63a0:
+ case 0x63a7:
+ displayMessage(dsAddr_butterflyMsg); // "I'd better leave them alone, they make this place beautiful"
+ break;
+
+ case 0x63ae:
+ displayMessage(dsAddr_notSureIfAliveMsg); // "I'm not sure if it's alive"
+ break;
case 0x63bc:
playMusic(6);
loadScene(25, 151, 156, 2);
- return true;
+ break;
case 0x63dc:
- Dialog::showMono(scene, 0x3375, 0, 0xd1, 0);
- return true;
+ dialog->showMono(86, scene, 0, textColorMark, 0);
+ break;
+
+ case 0x63e3:
+ displayMessage(dsAddr_holeTooNarrowMsg); // "The hole is too narrow to fit my hand"
+ break;
case 0x646e:
case 0x6475:
- Dialog::showMono(scene, 0x32C1, 0, 0xd1, 0);
- return true;
+ dialog->showMono(85, scene, 0, textColorMark, 0);
+ break;
case 0x6479:
- Dialog::showMono(scene, 0x325e, 0, 0xd1, 0);
- return true;
+ dialog->showMono(84, scene, 0, textColorMark, 0);
+ break;
case 0x6507:
- if (CHECK_FLAG(0xDB96, 1)) {
+ if (CHECK_FLAG(dsAddr_birdsGoneFromScarecrowFlag, 1))
rejectMessage();
- } else
- displayMessage(0x47e7);
- return true;
+ else
+ displayMessage(dsAddr_birdAttackMsg); // "Hey You! Wake up! Bird attack!"
+ break;
+
+ case 0x6541:
+ loadScene(20, Common::Point(10, 131));
+ scene->setOrientation(3);
+ break;
+
+ case 0x6635:
+ displayMessage(dsAddr_uninterestingHaystackMsg); // "I don't see anything interesting about this haystack"
+ break;
+
+ case 0x666a:
+ displayMessage(dsAddr_moreComplicatedMsg); // "It's more complicated than that"
+ break;
case 0x65c3:
- if (CHECK_FLAG(0xDBA9, 1)) {
+ if (CHECK_FLAG(dsAddr_mouseHoleState, 1)) {
playActorAnimation(635);
setOns(5, 0);
playSound(63, 11);
playSound(15, 20);
playSound(32, 31);
playActorAnimation(636);
- inventory->add(47);
- inventory->add(48);
+ inventory->add(kInvItemHandkerchief);
+ inventory->add(kInvItemMouse);
moveTo(scene->getPosition().x - 1, 139, 1, true);
- displayMessage(0x3b83);
- SET_FLAG(0xDBA9, 2);
- SET_FLAG(0xDBA8, 0);
+ displayMessage(dsAddr_yikesMsg); // "Yikes!"
+ SET_FLAG(dsAddr_mouseHoleState, 2);
+ SET_FLAG(dsAddr_HankerchiefInMouseholeFlag, 0);
} else
- displayMessage(0x4808);
- return true;
+ displayMessage(dsAddr_noSearchWarrantMsg); // "I don't have a search-warrant"
+ break;
+
+ case 0x6671:
+ displayMessage(dsAddr_cantOpenItMsg); // "I can't open it"
+ break;
+
+ case 0x6678:
+ rejectMessage();
+ break;
+
+ case 0x670f:
+ displayMessage(dsAddr_dontNeedThemMsg); // "I don't need them"
+ break;
+
+ case 0x6716:
+ displayMessage(dsAddr_pullObjMsg2); // "I can't reach it"
+ break;
+
+ case 0x6772:
+ loadScene(31, Common::Point(20, 188));
+ scene->setOrientation(2);
+ break;
+
+ case 0x678c:
+ loadScene(28, Common::Point(189, 153));
+ scene->setOrientation(4);
+ break;
+
+ case 0x67fa:
+ rejectMessage();
+ break;
+
+ case 0x67fe:
+ displayMessage(dsAddr_troubleWithStairsMsg); // "If I put it on I might have trouble walking up the stairs"
+ break;
+
+ case 0x6911:
+ displayMessage(dsAddr_9LivesToReadMsg); // "I'd need 9 lives to read them all"
+ break;
+
+ case 0x6954:
+ displayMessage(dsAddr_thanksNotTiredMsg); // "Thanks, I'm not so tired"
+ break;
+
+ case 0x695b:
+ displayMessage(dsAddr_noNeedToTurnOnMsg); // "There's no need to turn it on"
+ break;
+
+ case 0x6ba6:
+ displayMessage(dsAddr_wontBearWeightMsg); // "It won't bear my weight"
+ break;
+
+ case 0x6bda:
+ displayMessage(dsAddr_peepingTomMsg); // "What am I? A Peeping Tom?"
+ break;
+
+ case 0x6c1c:
+ case 0x6c20:
+ rejectMessage();
+ break;
+
+ case 0x6c24:
+ displayMessage(dsAddr_dontNeedThemMsg); // "I don't need them"
+ break;
+
+ case 0x6c2b:
+ loadScene(29, Common::Point(300, 188));
+ scene->setOrientation(4);
+ break;
+
+ case 0x6c7c:
+ displayMessage(dsAddr_bigPocketsMsg); // "I have big pockets, but there are limits"
+ break;
+
+ case 0x724e:
+ displayMessage(dsAddr_soSharpMsg); // "They're so sharp they'd rip my trousers!"
+ break;
+
+ case 0x72be:
+ rejectMessage();
+ break;
+
+ case 0x7305:
+ rejectMessage();
+ break;
+
+ case 0x7328:
+ displayMessage(dsAddr_noTimeForPleasuresMsg); // "I don't have time for pleasures"
+ break;
+
+ case 0x732f:
+ displayMessage(dsAddr_notSocksWithBareHandsMsg); // "I won't touch these socks with my bare hands!"
+ break;
+
+ case 0x739c:
+ displayMessage(dsAddr_notHalloweenMsg); // "It's not Halloween"
+ break;
+
+ case 0x7401:
+ displayMessage(dsAddr_NotManualMsg); // "It can't be controlled manually! I hate it!"
+ break;
+
+ case 0x746f:
+ displayMessage(dsAddr_nothingToPlayMsg); // "I have nothing to play"
+ break;
+
+ case 0x74b3:
+ loadScene(29, Common::Point(256, 171));
+ scene->setOrientation(3);
+ break;
+
+ case 0x74cd:
+ rejectMessage();
+ break;
+
+ case 0x74f9:
+ loadScene(38, Common::Point(160, 199));
+ scene->setOrientation(1);
+ break;
+
+ case 0x784a:
+ displayMessage(dsAddr_notMineMsg); // "I can't take it. It's not mine."
+ break;
+
+ case 0x7851:
+ displayMessage(dsAddr_lockedMsg); // "It's Locked!"
+ break;
+
+ case 0x7858:
+ displayMessage(dsAddr_lockedMsg); // "It's Locked!"
+ break;
+
+ case 0x785f:
+ displayMessage(dsAddr_pullObjMsg2); // "I can't reach it"
+ break;
case 0x7866:
- if (CHECK_FLAG(0xdbdd, 3)) {
- displayMessage(0x55ff);
- return true;
- } else
- return false;
+ if (CHECK_FLAG(dsAddr_JailCableAndBowlState, 3))
+ displayMessage(dsAddr_gotchaMsg); // "Gotcha"
+ else
+ retVal = false;
+ break;
- case 0x7878: {
- byte v = res->dseg.get_byte(0xDBDB) + 1;
- if (v <= 6)
- SET_FLAG(0xDBDB, v);
+ case 0x7878:
+ {
+ byte v = res->dseg.get_byte(dsAddr_graffitiMsgId) + 1;
+ if (v <= 6)
+ SET_FLAG(dsAddr_graffitiMsgId, v);
- switch (v) {
- case 1:
- displayMessage(0x5411);
- return true;
- case 2:
- displayMessage(0x5463);
- return true;
- case 3:
- displayMessage(0x5475);
- return true;
- case 4:
- displayMessage(0x5484);
- return true;
- case 5:
- displayMessage(0x54c4);
- return true;
- default:
- displayMessage(0x54d5);
- return true;
+ switch (v) {
+ case 1:
+ displayMessage(dsAddr_SavingFineMsg); // "Saving is a very fine thing..."
+ break;
+ case 2:
+ displayMessage(dsAddr_loveCaptainMsg); // "I love captain"
+ break;
+ case 3:
+ displayMessage(dsAddr_soccerRulzMsg); // "Soccer rulz"
+ break;
+ case 4:
+ displayMessage(dsAddr_treeCutMsg); // "Don't cut the trees..."
+ break;
+ case 5:
+ displayMessage(dsAddr_visaAcceptedMsg); // "VISA Accepted"
+ break;
+ default:
+ displayMessage(dsAddr_otherGraffitiMsg); // "The rest of graffiti is obscene"
+ break;
+ }
}
- }
+ break;
case 0x78a9:
- if (CHECK_FLAG(0xDBE6, 1)) {
- displayMessage(0x5827);
- return true;
- } else
- return false;
+ if (CHECK_FLAG(dsAddr_captainDrawerState, 1))
+ displayMessage(dsAddr_nowOpenMsg); // "Now it's open"
+ else
+ retVal = false;
+ break;
case 0x78bb:
- if (CHECK_FLAG(0xDBE8, 1)) {
- displayMessage(0x58b0);
- return true;
- } else
- return false;
+ if (CHECK_FLAG(dsAddr_swappedBarmanMugFlag, 1))
+ displayMessage(dsAddr_yuckMsg); // "Yuck!"
+ else
+ retVal = false;
+ break;
case 0x78ce:
- if (!CHECK_FLAG(0xDBA1, 1)) {
- displayMessage(0x3694);
- return true;
- } else
- return false;
+ if (!CHECK_FLAG(dsAddr_mansionTreeHollowEmptyFlag, 1))
+ displayMessage(dsAddr_monstersMsg); // "Who knows what monsters live in there"
+ else
+ retVal = false;
+ break;
- case 0x792b: //left click on ann
+ case 0x792b: // left click on ann
moveTo(245, 198, 1);
- if (CHECK_FLAG(0xDBAF, 1))
- return false;
-
- Dialog::showMono(scene, 0x2193, 0, 0xd1, 0);
- SET_FLAG(0xDBAF, 1);
- return true;
+ if (!CHECK_FLAG(dsAddr_alreadySaidAnneBeautifulFlag, 1)) {
+ dialog->showMono(50, scene, 0, textColorMark, 0);
+ SET_FLAG(dsAddr_alreadySaidAnneBeautifulFlag, 1);
+ } else
+ retVal = false;
+ break;
case 0x79c3:
- if (CHECK_FLAG(0xDBA4, 1))
- return false;
- processCallback(0x61fe);
- return true;
+ if (CHECK_FLAG(dsAddr_lightOnFlag, 1))
+ retVal = false;
+ else
+ fnTooDark();
+ break;
- case 0x7b26: //cutting the fence
+ case 0x7b26: // cutting the fence
setOns(0, 0);
playSound(5, 2);
playSound(51, 11);
@@ -1114,11 +2050,11 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
setOns(0, 0x60);
moveTo(281, scene->getPosition().y, 0, true);
disableObject(4);
- SET_FLAG(0xDBE1, 1);
- return true;
+ SET_FLAG(dsAddr_cutFenceFlag, 1);
+ break;
- case 0x7b89: //digging mysterious object
- if (CHECK_FLAG(0xDBE1, 1)) {
+ case 0x7b89: // digging mysterious object
+ if (CHECK_FLAG(dsAddr_cutFenceFlag, 1)) {
playActorAnimation(844);
setOns(1, 0);
playSound(5, 5);
@@ -1130,11 +2066,15 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
setOns(1, 0x64);
playActorAnimation(845);
disableObject(3);
- inventory->add(0x52);
- inventory->remove(0x51);
+ inventory->add(kInvItemKaleidoscope);
+ inventory->remove(kInvItemShovelAct1);
} else
- displayMessage(0x56da);
- return true;
+ displayMessage(dsAddr_fenceBlocksMsg); // "The fence blocks the way"
+ break;
+
+ case 0x7bf6:
+ displayMessage(dsAddr_noDiggingKnifeMsg); // "Digging it out with the knife could take a hundred years"
+ break;
case 0x7bfd:
playSound(76, 18);
@@ -1149,7 +2089,7 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playSound(76, 63);
playActorAnimation(873);
moveTo(240, 163, 4);
- displayMessage(0x5837);
+ displayMessage(dsAddr_cmonBabyMsg); // "C'mon baby, it's all yours!"
waitLanAnimationFrame(1, 0x22);
playSound(77, 2);
playSound(77, 12);
@@ -1164,23 +2104,36 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
setLan(1, 0);
playAnimation(874, 1);
setOns(0, 0x68);
- inventory->remove(0x5b);
+ inventory->remove(kInvItemDruggedFood);
enableObject(6);
disableObject(1);
- return true;
+ break;
+
+ case 0x7cc9:
+ case 0x7cd0:
+ displayMessage(dsAddr_throwCrumbsToBirdQMsg); // "Should I throw the crumbs to the bird?"
+ break;
+
+ case 0x7cd7:
+ displayMessage(dsAddr_dontWasteCrumbs); // "I don't want to waste these tasty crumbs"
+ break;
- case 0x7ce5: //put spring on the solid ground
+ case 0x7cde:
+ displayMessage(dsAddr_mightSlipFallInMsg); // "Better not... I might slip and fall in..."
+ break;
+
+ case 0x7ce5: // put spring on the solid ground
playSound(5, 2);
playSound(19, 11);
playActorAnimation(840);
setOns(1, 0x61);
- inventory->remove(0x50);
+ inventory->remove(kInvItemSpring);
disableObject(2);
enableObject(7);
- return true;
+ break;
- case 0x7d1a: //captain's key + door
- if (res->dseg.get_byte(0xDBDF) <= 1) {
+ case 0x7d1a: // captain's key + door
+ if (res->dseg.get_byte(dsAddr_FirstActTrialState) <= 1) {
playSound(5, 2);
playSound(57, 12);
playSound(70, 19);
@@ -1198,24 +2151,23 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
wait(200);
playAnimation(0, 1);
setOns(0, 0);
- Dialog::showMono(scene, 0x63a5, 830, 0xd0, 1);
+ dialog->showMono(156, scene, 830, textColorShockedCaptain, 1);
loadScene(7, 130, 195, 2);
playMusic(4);
setLan(1, 1);
wait(100);
- Dialog::show(scene, 0x6406, 0, 832, 0xd1, 0xec, 0, 1);
+ dialog->show(157, scene, 0, 832, textColorMark, textColorCaptain, 0, 1);
//playAnimation(831, 1);
- SET_FLAG(0xDBDF, 2);
-
+ SET_FLAG(dsAddr_FirstActTrialState, 2);
} else
- displayMessage(0x52f6);
- return true;
+ displayMessage(dsAddr_nahMsg); // "Nah"
+ break;
- case 0x7e02: //tickling the captain
- if (CHECK_FLAG(0xdbe0, 1)) {
- displayMessage(0x5632);
+ case 0x7e02: // tickling the captain
+ if (CHECK_FLAG(dsAddr_AlreadyTickledCaptainFlag, 1)) {
+ displayMessage(dsAddr_doesNotWorkMsg); // "That doesn't work"
} else {
playSound(5, 6);
playSound(27, 49);
@@ -1224,37 +2176,37 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
waitAnimation();
setOns(0, 94);
- Dialog::show(scene, 0x65e9, 0, 832, 0xd1, 0xec, 0, 1);
+ dialog->show(161, scene, 0, 832, textColorMark, textColorCaptain, 0, 1);
enableObject(12);
- SET_FLAG(0xdbe0, 1);
+ SET_FLAG(dsAddr_AlreadyTickledCaptainFlag, 1);
}
- return true;
+ break;
- case 0x7e4f: //giving magazine to captain
- Dialog::show(scene, 0x66c0, 0, 856, 0xd1, 0xec, 0, 1);
+ case 0x7e4f: // giving magazine to captain
+ dialog->show(162, scene, 0, 856, textColorMark, textColorCaptain, 0, 1);
playSound(5, 3);
playActorAnimation(852, true);
playActorAnimation(853, true);
- displayMessage(0x5742);
- displayMessage(0x5757);
- displayMessage(0x5770);
- displayMessage(0x5782);
- displayMessage(0x5799);
+ displayMessage(dsAddr_whatAboutMsg); // "What about a new"
+ displayMessage(dsAddr_hotOffMsg); // "hot off the press"
+ displayMessage(dsAddr_fullColorMsg); // "full-color"
+ displayMessage(dsAddr_specialEdMsg); // "special edition"
+ displayMessage(dsAddr_soldierNewsMsg); // "of Soldier News?!"
playAnimation(856, 1);
playSound(5, 3);
//playActorAnimation(854);
- Dialog::show(scene, 0x66fe, 0, 856, 0xd1, 0xec, 0, 1);
+ dialog->show(163, scene, 0, 856, textColorMark, textColorCaptain, 0, 1);
playAnimation(855, 1);
wait(200);
moveTo(30, 181, 0);
disableObject(1);
setLan(1, 0);
- SET_FLAG(0xDBDF, 3);
- SET_FLAG(0xDBF0, 1);
+ SET_FLAG(dsAddr_FirstActTrialState, 3);
+ SET_FLAG(dsAddr_gotPasswordNeedSpeakBarmanFlag, 1);
loadScene(8, 155, 199);
- return true;
+ break;
- case 0x7fbd: //using bird & bartender
+ case 0x7fbd: // using bird & bartender
playSound(5, 3);
playActorAnimation(876);
setOns(1, 0);
@@ -1263,15 +2215,15 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playAnimation(877, 1);
playAnimation(880, 1, true);
- Dialog::show(scene, 0x6f0e, 0, 857, 0xd1, 0xef, 0, 1);
+ dialog->show(176, scene, 0, 857, textColorMark, textColorBarman, 0, 1);
setOns(2, 0x6a);
reloadLan();
playAnimation(878, 0);
- //playAnimation(879, 0); //background bartender animation
- inventory->remove(0x5c);
+ //playAnimation(879, 0); // background bartender animation
+ inventory->remove(kInvItemBird);
enableObject(1);
- SET_FLAG(0xDBE7, 1);
- return true;
+ SET_FLAG(dsAddr_birdOnBarRadioAntennaFlag, 1);
+ break;
case 0x8047:
playSound(32, 5);
@@ -1279,27 +2231,26 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playSound(52, 23);
playActorAnimation(881);
setOns(2, 0x6b);
- inventory->remove(0x56);
- inventory->add(0x55);
- SET_FLAG(0xDBE8, 1);
- return true;
+ inventory->remove(kInvItemMugOfMud);
+ inventory->add(kInvItemMug);
+ SET_FLAG(dsAddr_swappedBarmanMugFlag, 1);
+ break;
case 0x808b:
- if (CHECK_FLAG(0xDBDA, 1)) {
- //alredy shown
- displayMessage(0x53F2);
+ if (CHECK_FLAG(dsAddr_ShownPassToGuardFlag, 1)) {
+ displayMessage(dsAddr_gotPermissionMsg); // "I already got the permission"
} else {
- displayMessage(0x53DD);
+ displayMessage(dsAddr_showPapersMsg); // "Here are my papers"
playSound(5, 2);
playSound(5, 18);
playActorAnimation(810);
- Dialog::show(scene, 0x60BF, 0, 809, 0xd1, 0xd0, 0, 1);
- SET_FLAG(0xDBDA, 1);
+ dialog->show(147, scene, 0, 809, textColorMark, textColorCampGuard, 0, 1);
+ SET_FLAG(dsAddr_ShownPassToGuardFlag, 1);
}
- return true;
+ break;
- case 0x80c3: //show kaleydoscope to the guard
- Dialog::show(scene, 0x6811, 0, 809, 0xd1, 0xd0, 0, 1);
+ case 0x80c3: // show kaleidoscope to the guard
+ dialog->show(165, scene, 0, 809, textColorMark, textColorCampGuard, 0, 1);
playSound(5, 3);
playSound(5, 30);
playSound(26, 14);
@@ -1309,124 +2260,146 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playAnimation(851, 0);
playAnimation(850, 0);
reloadLan();
- inventory->add(0x53);
- inventory->remove(0x52);
+ inventory->add(kInvItemSoldierNews);
+ inventory->remove(kInvItemKaleidoscope);
enableObject(1);
- SET_FLAG(0xDBE2, 1);
- return true;
+ SET_FLAG(dsAddr_act1GuardState, 1);
+ break;
+
+ case 0x8398:
+ displayMessage(dsAddr_trySomewhereElseMsg); // "I'd better try somewhere else - I suppose this side is heavily guarded"
+ break;
+
+ case 0x85dd:
+ displayMessage(dsAddr_branchNotPaddleMsg); // "This branch is not a paddle. It doesn't even look like one"
+ break;
+
+ case 0x85e4:
+ displayMessage(dsAddr_sharpenNotPulverizeMsg); // "I needed to sharpen it, not pulverize"
+ break;
+
+ case 0x8d42:
+ displayMessage(dsAddr_bluntSickleMsg); // "The sickle is too blunt"
+ break;
- //Shore
+ case 0x8d49:
+ displayMessage(dsAddr_noChainsawFuelMsg); // "There's no fuel in the chainsaw"
+ break;
+
+ case 0x8d50:
+ displayMessage(dsAddr_thornsTooThinMsg); // "Thorns are too thin, the chainsaw is useless here"
+ break;
+
+ // Shore
case 0x5348:
- if (CHECK_FLAG(0xdb99, 1)) { //got broken paddle from boat
- displayMessage(0x351f);
+ if (CHECK_FLAG(dsAddr_alreadyGotBrokenPaddleFlag, 1)) { // got broken paddle from boat
+ displayMessage(dsAddr_boatEmptyMsg); // "There's nothing else in the boat"
} else {
- SET_FLAG(0xDB99, 1);
+ SET_FLAG(dsAddr_alreadyGotBrokenPaddleFlag, 1);
playSound(57, 6);
playActorAnimation(536);
- Dialog::showMono(scene, 0x30c3, 0, 0xd1, 0);
- inventory->add(0x8);
+ dialog->showMono(77, scene, 0, textColorMark, 0);
+ inventory->add(kInvItemBrokenPaddle);
}
- return true;
+ break;
case 0x53a1:
- if (CHECK_FLAG(0xdbb2, 1)) { //spoken to man in well
- displayMessage(0x411d);
+ if (CHECK_FLAG(dsAddr_spokenToManInWellFlag, 1)) { // spoken to man in well
+ displayMessage(dsAddr_stillThereMsg); // "Are you still there?"
} else {
- displayMessage(0x408a);
- displayMessage(0x4091, 0xe5, 52728);
- displayMessage(0x4098);
- displayMessage(0x40a7, 0xe5, 52705);
- displayMessage(0x40b6);
- displayMessage(0x40ce, 0xe5, 52652);
- displayMessage(0x40e8);
- displayMessage(0x410f, 0xe5, 52712);
+ displayMessage(dsAddr_echoMsg); // "Echo!"
+ displayMessage(dsAddr_loudEchoMsg, textColorWellEcho, 248, 164); // "ECHO!"
+ displayMessage(dsAddr_whoThereMsg); // "Who's there?!"
+ displayMessage(dsAddr_loudWhoThereMsg, textColorWellEcho, 225, 164); // "WHO'S THERE?!"
+ displayMessage(dsAddr_dontCopyMsg); // "DON'T COPY ME!"
+ displayMessage(dsAddr_loudDontCopyMsg, textColorWellEcho, 172, 164); // "DON'T COPY ME!!!"
+ displayMessage(dsAddr_throwRockMsg); // "OR I WILL THROW A ROCK DOWN THERE!"
+ displayMessage(dsAddr_orIWillMsg, textColorWellEcho, 232, 164); // "OR I WILL"
wait(100);
- displayMessage(0x4091, 0xe5, 52728);
- SET_FLAG(0xDBB2, 1);
+ displayMessage(dsAddr_loudEchoMsg, textColorWellEcho, 248, 164);
+ SET_FLAG(dsAddr_spokenToManInWellFlag, 1);
}
- return true;
+ break;
+ case 0x5458:
+ {
+ setOns(2, 0);
+ playSound(34, 7);
+ playActorAnimation(535);
+ inventory->add(kInvItemSecondFlower);
+ disableObject(1);
- case 0x5458: {
- setOns(2, 0);
- playSound(34, 7);
- playActorAnimation(535);
- inventory->add(11);
- disableObject(1);
-
- byte *scene_15_ons = scene->getOns(15); //patch ons for the scene 15
- scene_15_ons[0] = 0;
+ byte *scene_15_ons = scene->getOns(15); // patch ons for the scene 15
+ scene_15_ons[0] = 0;
- byte f = GET_FLAG(0xDB98) + 1;
- SET_FLAG(0xDB98, f);
- if (f >= 2) {
- //disable object boat for scene 15!!
- disableObject(1, 15);
+ byte f = GET_FLAG(dsAddr_flowerIsleState) + 1;
+ SET_FLAG(dsAddr_flowerIsleState, f);
+ if (f >= 2) {
+ // disable object boat for scene 15!!
+ disableObject(1, 15);
+ }
}
- }
- return true;
+ break;
- case 0x54b3: {
- setOns(1, 0);
- setOns(3, 0);
- playSound(33, 6);
- playActorAnimation(534);
- inventory->add(10);
- disableObject(2);
- setOns(1, 10);
- setOns(1, 0, 15);
- byte f = GET_FLAG(0xDB98) + 1;
- SET_FLAG(0xDB98, f);
- if (f >= 2) {
- //disable object boat for scene 15!!
- disableObject(1, 15);
+ case 0x54b3:
+ {
+ setOns(1, 0);
+ setOns(3, 0);
+ playSound(33, 6);
+ playActorAnimation(534);
+ inventory->add(kInvItemFirstFlower);
+ disableObject(2);
+ setOns(1, 10);
+ setOns(1, 0, 15);
+ byte f = GET_FLAG(dsAddr_flowerIsleState) + 1;
+ SET_FLAG(dsAddr_flowerIsleState, f);
+ if (f >= 2) {
+ // disable object boat for scene 15!!
+ disableObject(1, 15);
+ }
}
- }
- return true;
+ break;
case 0x5502:
setOns(0, 0);
loadScene(15, 115, 180, 1);
playMusic(6);
playActorAnimation(568);
- return true;
+ break;
- case 0x5561://Enter lakeside house
- moveTo(94, 115, 4); //call 557e, but it's not needed I guess
+ case 0x5561: // Enter lakeside house
+ fnEgoDefaultPosition();
loadScene(19, 223, 199, 1);
- return true;
+ break;
case 0x55a1:
- processCallback(0x557e);
+ fnEgoDefaultPosition();
rejectMessage();
- return true;
+ break;
- case 0x557e:
- if (scene->getPosition().y <= 149)
- moveTo(94, 115, 4);
- else
- moveTo(51, 149, 4);
- return true;
+ case csAddr_egoDefaultPosition:
+ fnEgoDefaultPosition();
+ break;
case 0x563b:
playSound(5, 10);
setOns(1, 0);
playActorAnimation(561);
- inventory->add(26);
+ inventory->add(kInvItemNut);
disableObject(6);
- return true;
+ break;
case 0x56f6:
playSound(32, 7);
setOns(1, 0);
playActorAnimation(626);
disableObject(12);
- inventory->add(45);
- displayMessage(0x3b04);
- return true;
+ inventory->add(kInvItemCheese);
+ displayMessage(dsAddr_foundFoodMsg); // "People leave food in unbelievable places"
+ break;
- case 0x5756://Open car door
+ case 0x5756: // Open car door
playSound(11, 4);
playActorAnimation(514);
setOns(4, 8);
@@ -1435,106 +2408,94 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
enableObject(15);
enableObject(16);
disableObject(1);
- return true;
+ break;
- case 0x5805://Enter basketball house
+ case 0x5805: // Enter basketball house
playSound(70, 6);
playActorAnimation(513);
loadScene(22, 51, 180, 2);
- return true;
+ break;
- case 0x5832://Ring doorbell
+ case 0x5832: // Ring doorbell
playActorAnimation(509);
- displayMessage(0x5dce);
- return true;
+ displayMessage(dsAddr_outOfOrderMsg); // "It's out of order"
+ break;
case 0x58a2:
- Dialog::pop(scene, 0xdaba, 0, 502, 0xd1, 0xe5, 0, 1);
- scene->getObject(13)->setName((const char *)res->dseg.ptr(0x92e5));
- return true;
+ dialog->pop(scene, dsAddr_dialogStackSonny, 0, 502, textColorMark, textColorSonny, 0, 1);
+ scene->getObject(13)->setName((const char *)res->dseg.ptr(dsAddr_scnObjNameSonny));
+ break;
- case 0x58b7://Get comb from car
+ case 0x58b7: // Get comb from car
disableObject(14);
setOns(4, 0);
playSound(5, 7);
playActorAnimation(521);
setOns(4, 0);
- inventory->add(0x6);
- return true;
+ inventory->add(kInvItemComb);
+ break;
- case 0x58df://Pull trunk lever in car
- SET_FLAG(0xDB94, 1);
+ case 0x58df: // Pull trunk lever in car
+ SET_FLAG(dsAddr_alreadyPulledTrunkReleaseLeverFlag, 1);
playSound(6, 1);
setOns(3, 6);
playActorAnimation(515);
- return true;
+ break;
- case 0x593e://Enter annes house
+ case 0x593e: // Enter annes house
playSound(89, 4);
playActorAnimation(980);
loadScene(23, 76, 199, 1);
- if (CHECK_FLAG(0xDBEE, 1))
+ if (CHECK_FLAG(dsAddr_lovestruckByAnneFlag, 1))
playMusic(7);
- return true;
+ break;
case 0x5994:
- processCallback(0x599b);
- processCallback(0x5a21);
- return true;
+ fnEnterCave();
+ break;
- case 0x599b:
- return true;
+ case csAddr_caveNOP:
+ break;
- case 0x5a21:
- loadScene(24, 230, 170, 1);
- playSound(52, 3);
- playSound(52, 7);
- playSound(52, 11);
- playSound(52, 14);
- playSound(52, 18);
- playSound(52, 21);
- playSound(52, 25);
- playActorAnimation(601);
- moveTo(230, 179, 3);
- if (!CHECK_FLAG(0xDBA4, 1))
- displayMessage(0x37ea); //it's kinda dark here
- return true;
+ case csAddr_enterCave:
+ fnEnterCave();
+ break;
case 0x5a8b:
- if (!CHECK_FLAG(0xDBAD, 1)) {
- playSound(43, 4); //grrrrrr
+ if (!CHECK_FLAG(dsAddr_dogHasBoneFlag, 1)) {
+ playSound(43, 4); // grrrrrr
playSound(42, 15);
playSound(42, 17);
playSound(42, 19);
playAnimation(656, 0);
wait(50);
- displayMessage(0x3c16);
- } else if (!CHECK_FLAG(0xDBA3, 1)) {//Dog has bone
+ displayMessage(dsAddr_goodDoggyMsg); // "I understand. Good doggy"
+ } else if (!CHECK_FLAG(dsAddr_cellarDoorOpenFlag, 1)) { // Dog has bone
playSound(28, 3);
playActorAnimation(596);
setOns(1, 30);
- SET_FLAG(0xDBA3, 1);
+ SET_FLAG(dsAddr_cellarDoorOpenFlag, 1);
enableObject(8);
} else {
setOns(1, 0);
playSound(4, 4);
playActorAnimation(597);
- SET_FLAG(0xDBA3, 0);
+ SET_FLAG(dsAddr_cellarDoorOpenFlag, 0);
disableObject(8);
- displayMessage(0x37b8);
+ displayMessage(dsAddr_wallShakenMsg); // "Wow! This must have shaken all the nearby walls!"
setOns(1, 32, 24);
enableObject(4, 24);
}
- return true;
+ break;
- case 0x5b3a://Click on dog
- Dialog::popMark(scene, 0xDB14);
- return true;
+ case 0x5b3a: // Click on dog
+ dialog->popMark(scene, dsAddr_dialogStackDog);
+ break;
- case 0x5b59: //picking up the rope
- Dialog::showMark(scene, 0x2cbd);
+ case 0x5b59: // picking up the rope
+ dialog->showMark(70, scene);
wait(150);
- Dialog::showMark(scene, 0x2dc2);
+ dialog->showMark(71, scene);
moveRel(0, -12, 0);
playSound(34, 5);
playActorAnimation(607);
@@ -1545,81 +2506,81 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playSound(5, 25);
playActorAnimation(611);
moveTo(16, scene->getPosition().y, 4, true);
- inventory->add(38);
+ inventory->add(kInvItemRopeAct2);
disableObject(12);
- return true;
+ break;
- case 0x5be1://Talk to grandpa
- Dialog::pop(scene, 0xDAC4, 0, 522, 0xd1, 0xd8, 0, 1);
- return true;
+ case 0x5be1: // Talk to grandpa
+ dialog->pop(scene, dsAddr_dialogStackGrandpa, 0, 522, textColorMark, textColorGrandpa, 0, 1);
+ break;
case 0x5bee:
playSound(89, 5);
playSound(67, 11);
playActorAnimation(982);
- displayMessage(0x5955);
- return true;
+ displayMessage(dsAddr_emptyMsg); // "It's Empty"
+ break;
- case 0x5c0d: //grandpa - drawers
- if (CHECK_FLAG(0xDBA7, 1)) {
- displayMessage(0x3bac);
+ case 0x5c0d: // grandpa - drawers
+ if (CHECK_FLAG(dsAddr_SearchedGrandpaDrawersFlag, 1)) {
+ displayMessage(dsAddr_drawersEmptyMsg); // "There's nothing else in the drawers"
} else {
- if (!CHECK_FLAG(0xDB92, 1))
- Dialog::show(scene, 0x15a0, 0, 522, 0xd1, 0xd8, 0, 1); //can I search your drawers?
+ if (!CHECK_FLAG(dsAddr_alreadyAdjustedHoopPoleFlag, 1))
+ dialog->show(24, scene, 0, 522, textColorMark, textColorGrandpa, 0, 1);
playSound(66, 5);
playSound(67, 20);
playSound(5, 23);
playActorAnimation(631);
- inventory->add(47);
- SET_FLAG(0xDBA7, 1);
+ inventory->add(kInvItemHandkerchief);
+ SET_FLAG(dsAddr_SearchedGrandpaDrawersFlag, 1);
}
- return true;
+ break;
case 0x5c84:
- if (CHECK_FLAG(0xDB92, 1)) {
- inventory->add(2);
+ if (CHECK_FLAG(dsAddr_alreadyAdjustedHoopPoleFlag, 1)) {
+ inventory->add(kInvItemShotgun);
disableObject(7);
playSound(32, 7);
setOns(0, 0);
playActorAnimation(520);
} else {
- Dialog::pop(scene, 0xDACE, 0, 522, 0xd1, 0xd8, 0, 1);
+ dialog->pop(scene, dsAddr_dialogStackGrandpaShotgun, 0, 522, textColorMark, textColorGrandpa, 0, 1);
}
- return true;
+ break;
- case 0x5cf0://Exit basketball house
+ case 0x5cf0:// Exit basketball house
playSound(88, 5);
playActorAnimation(981);
loadScene(20, 161, 165);
- return true;
+ break;
- case 0x5d24: //getting the fan
- if (CHECK_FLAG(0xDB92, 1)) {
+ case 0x5d24: // getting the fan
+ if (CHECK_FLAG(dsAddr_alreadyAdjustedHoopPoleFlag, 1)) {
setLan(2, 0);
playSound(32, 7);
playActorAnimation(508);
disableObject(13);
- inventory->add(7);
+ inventory->add(kInvItemFan);
} else {
- Dialog::pop(scene, 0xDAD4, 0, 522, 0xd1, 0xd8, 0, 1);
+ dialog->pop(scene, dsAddr_dialogStackGrandpaFan, 0, 522, textColorMark, textColorGrandpa, 0, 1);
}
- return true;
+ break;
- case 0x5e4d: //right click on ann
- if (!CHECK_FLAG(0xDB97, 0)) {
- displayMessage(0x3d59);
+ case 0x5e4d: // right click on ann
+ if (!CHECK_FLAG(dsAddr_alreadySpokenToAnneFlag, 0)) {
+ displayMessage(dsAddr_girlTalkMsg); // "I really don't know how to talk to girls"
} else {
moveTo(245, 198, 1);
- Dialog::show(scene, 0x21d7, 0, 524, 0xd1, 0xe5, 0, 2);
- //waitLanAnimationFrame(2, 1); //too long, about 200 frames! seems to be present in original game (sic)
- SET_FLAG(0xDB97, 1);
+ dialog->show(51, scene, 0, 524, textColorMark, textColorAnne, 0, 2);
+ //waitLanAnimationFrame(2, 1); // too long, about 200 frames! seems to be present in original game (sic)
+ SET_FLAG(dsAddr_alreadySpokenToAnneFlag, 1);
for (byte i = 10; i <= 20; i += 2)
playSound(13, i);
playAnimation(528, 1);
wait(50);
playMusic(7);
- SET_FLAG(0xDBEE, 1);
+ SET_FLAG(dsAddr_lovestruckByAnneFlag, 1);
for (byte i = 3; i <= 17; i += 2)
playSound(56, i);
playActorAnimation(525);
@@ -1633,163 +2594,146 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playSound(55, 5);
playActorAnimation(527);
wait(50);
- Dialog::show(scene, 0x2219, 0, 524, 0xd1, 0xe5, 0, 2);
- scene->getObject(2)->setName((const char *)res->dseg.ptr(0x9820));
+ dialog->show(52, scene, 0, 524, textColorMark, textColorAnne, 0, 2);
+ scene->getObject(2)->setName((const char *)res->dseg.ptr(dsAddr_scnObjNameAnne));
}
- return true;
+ break;
- case 0x5f73: //exiting ann's house
- if (CHECK_FLAG(0xDBEE, 1))
+ case 0x5f73: // exiting ann's house
+ if (CHECK_FLAG(dsAddr_lovestruckByAnneFlag, 1))
playMusic(6);
loadScene(21, 99, 180, 3);
- return true;
+ break;
case 0x5fba:
- if (CHECK_FLAG(0xDBB1, 1)) {
- displayMessage(0x4380);
+ if (CHECK_FLAG(dsAddr_nutSwappedForAppleFlag, 1)) {
+ displayMessage(dsAddr_noFruitMsg); // "There are no more interesting fruits here"
} else {
- Dialog::pop(scene, 0xDAFC, 0, 523, 0xd1, 0xe5, 0, 1);
+ dialog->pop(scene, dsAddr_dialogStackGetAppleOldLady, 0, 523, textColorMark, textColorOldLady, 0, 1);
}
- return true;
+ break;
case 0x607f:
- return processCallback(0x60b5);
+ fnEgoScaredBySpider();
+ break;
case 0x6083:
- if (CHECK_FLAG(0xDBA4, 1)) {
+ if (CHECK_FLAG(dsAddr_lightOnFlag, 1)) {
setOns(0, 0);
playSound(56, 10);
playActorAnimation(599);
- inventory->add(37);
+ inventory->add(kInvItemShovelAct2);
disableObject(2);
} else
- processCallback(0x60b5);
- return true;
+ fnEgoScaredBySpider();
+ break;
- case 0x60b5:
- if (CHECK_FLAG(0xDBAE, 1)) {
- processCallback(0x60d9);
- Dialog::showMark(scene, 0x2fdd);
- } else {
- Dialog::showMark(scene, 0x2e41);
- processCallback(0x60d9);
- wait(100);
- Dialog::showMark(scene, 0x2e6d);
- }
- return true;
+ case csAddr_egoScaredBySpider:
+ fnEgoScaredBySpider();
+ break;
- case 0x60d9: {
- Object *obj = scene->getObject(3);
- moveTo(obj);
- processCallback(0x612b);
- moveTo(48, 190, 3);
- }
- return true;
+ case csAddr_moveToLadderAndLeaveCellar:
+ fnMoveToLadderAndLeaveCellar();
+ break;
- case 0x612b:
- playSound(52, 10);
- playSound(52, 14);
- playSound(52, 18);
- playSound(52, 21);
- playSound(52, 25);
- playSound(52, 28);
- playSound(52, 32);
- playActorAnimation(600);
- loadScene(21, 297, 178, 3);
- return true;
+ case csAddr_leaveCellar:
+ fnLeaveCellar();
+ break;
case 0x6176:
- if (CHECK_FLAG(0xDBA4, 1)) {
- displayMessage(0x3801);
- return true;
+ if (CHECK_FLAG(dsAddr_lightOnFlag, 1)) {
+ displayMessage(dsAddr_notInDarkMsg); // "I'm not going to wander here in the dark again"
+ } else {
+ playSound(71, 6);
+ playActorAnimation(598);
+ loadScene(24, scene->getPosition());
+ setOns(2, 0);
+ setLan(1, 0);
+ playAnimation(660, 0);
+ disableObject(1);
+ SET_FLAG(dsAddr_lightOnFlag, 1);
+ loadScene(24, scene->getPosition());
}
- playSound(71, 6);
- playActorAnimation(598);
- loadScene(24, scene->getPosition());
- setOns(2, 0);
- setLan(1, 0);
- playAnimation(660, 0);
- disableObject(1);
- SET_FLAG(0xDBA4, 1);
- loadScene(24, scene->getPosition());
-
- return true;
+ break;
case 0x61e9:
- if (CHECK_FLAG(0xDBA4, 1)) {
- Dialog::popMark(scene, 0xdb1e);
- } else
- processCallback(0x61fe);
+ if (CHECK_FLAG(dsAddr_lightOnFlag, 1))
+ dialog->popMark(scene, dsAddr_dialogStackTakeAxe);
+ else
+ fnTooDark();
+ break;
- return true;
+ case csAddr_TooDark:
+ displayMessage(dsAddr_TooDarkMsg); // "It's too dark to see clearly"
+ break;
- case 0x6229: //shelves in cellar
- if (CHECK_FLAG(0xDBA4, 1)) {
+ case 0x6229: // shelves in cellar
+ if (CHECK_FLAG(dsAddr_lightOnFlag, 1)) {
Common::Point p = scene->getPosition();
- byte v = GET_FLAG(0xDBB4);
+ byte v = GET_FLAG(dsAddr_cellarShelfExamineCount);
switch (v) {
case 0:
- displayMessage(0x4532);
+ displayMessage(dsAddr_whatGotMsg); // "Let's look what we've got here"
moveRel(-34, 0, 1);
- displayMessage(0x4555);
+ displayMessage(dsAddr_strawberryJamMsg); // "Strawberry jam"
moveRel(20, 0, 1);
- displayMessage(0x4568);
+ displayMessage(dsAddr_gooseberryJamMsg); // "Gooseberry jam"
moveRel(20, 0, 1);
- displayMessage(0x457b);
+ displayMessage(dsAddr_blackberryJamMsg); // "Blackberry jam"
moveRel(20, 0, 1);
- displayMessage(0x458e);
+ displayMessage(dsAddr_bilberryJamMsg); // "Bilberry jam"
moveTo(p, 3);
- displayMessage(0x459f);
- SET_FLAG(0xDBB4, 1);
+ displayMessage(dsAddr_getMeOutJamMsg); // "Get me out of this jam!"
+ SET_FLAG(dsAddr_cellarShelfExamineCount, 1);
break;
case 1:
- displayMessage(0x45b8);
+ displayMessage(dsAddr_rosemaryJamMsg); // "Oh, and there is Rosemary jam"
wait(100);
- displayMessage(0x45da);
- SET_FLAG(0xDBB4, 2);
+ displayMessage(dsAddr_knowRosemaryMsg); // "I used to know someone called Rosemary"
+ SET_FLAG(dsAddr_cellarShelfExamineCount, 2);
break;
default:
- displayMessage(0x4603);
+ displayMessage(dsAddr_unwantedJamsMsg); // "I don't want those jams"
+ break;
}
} else
- processCallback(0x61fe);
-
- return true;
+ fnTooDark();
+ break;
- case 0x6480: //dive mask
- if (CHECK_FLAG(0xDB96, 1)) {
+ case 0x6480: // dive mask
+ if (CHECK_FLAG(dsAddr_birdsGoneFromScarecrowFlag, 1)) {
playSound(56, 7);
playSound(5, 15);
playActorAnimation(613);
setOns(3, 36);
- inventory->add(39);
+ inventory->add(kInvItemMask);
disableObject(5);
- displayMessage(0x387c);
+ displayMessage(dsAddr_needSunglassesMsg); // "Sorry buddy, but I need your sunglasses"
} else
- displayMessage(0x3eb2);
- return true;
+ displayMessage(dsAddr_crowKillMsg); // "I'm sure these crows will kill me"
+ break;
- case 0x64c4: //flippers
- if (CHECK_FLAG(0xDB96, 1)) {
+ case 0x64c4: // flippers
+ if (CHECK_FLAG(dsAddr_birdsGoneFromScarecrowFlag, 1)) {
setOns(2, 35);
playSound(63, 8);
playSound(24, 10);
playActorAnimation(612);
- inventory->add(40);
+ inventory->add(kInvItemFins);
disableObject(6);
} else
- displayMessage(0x3eb2);
- return true;
+ displayMessage(dsAddr_crowKillMsg); // "I'm sure these crows will kill me"
+ break;
- case 0x7907://Describe car lever
- if (CHECK_FLAG(0xdb94, 1)) {//Already pulled lever?
- displayMessage(0x3e4f);
- return true;
+ case 0x7907: // Describe car lever
+ if (CHECK_FLAG(dsAddr_alreadyPulledTrunkReleaseLeverFlag, 1)) { // Already pulled lever?
+ displayMessage(dsAddr_openBootMsg); // "It opens the boot"
} else
- return false;
+ retVal = false;
+ break;
- case 0x62d0://Get bone from under rock
- displayAsyncMessage(0x463c, 30938, 16, 24);
+ case 0x62d0: // Get bone from under rock
+ displayAsyncMessage(dsAddr_yeowMsg, 218, 96, 16, 24); // "YEEEOOOWWWW!"
playSound(26, 6);
playSound(26, 10);
playSound(24, 13);
@@ -1798,35 +2742,34 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playActorAnimation(594);
setOns(0, 29);
disableObject(1);
- inventory->add(36);
+ inventory->add(kInvItemBone);
playSound(5, 2);
playActorAnimation(595);
- displayMessage(0x3790);
- return true;
+ displayMessage(dsAddr_dinoBoneMsg); // "I really hope this is DINOSAUR bone"
+ break;
case 0x6351:
- if (CHECK_FLAG(0xdaca, 1)) { //cave bush is cut down
+ if (CHECK_FLAG(dsAddr_caveThornsCutDownFlag, 1)) { // cave bush is cut down
playMusic(8);
loadScene(26, 319, 169, 4);
} else
- displayMessage(0x3bd2);
- return true;
+ displayMessage(dsAddr_ridBushMsg); // "I must get rid of this bush first"
+ break;
case 0x63ea:
playSound(5, 10);
setOns(0, 0);
playActorAnimation(640);
- inventory->add(50);
+ inventory->add(kInvItemNugget);
disableObject(6);
- return true;
+ break;
- case 0x6411://Kick hen
- if (CHECK_FLAG(0xdb93, 1)) { //already kicked hen
- displayMessage(0x3e08);
- return true;
+ case 0x6411: // Kick hen
+ if (CHECK_FLAG(dsAddr_alreadyKickedHenFlag, 1)) { // already kicked hen
+ displayMessage(dsAddr_ridFrustationsMsg); // "I'd already got rid of my frustrations"
} else {
- SET_FLAG(0xdb93, 1);
- displayMessage(0x3dc6);
+ SET_FLAG(dsAddr_alreadyKickedHenFlag, 1);
+ displayMessage(dsAddr_henFlyMsg); // "I wonder if hens can fly. Come here, baby"
waitLanAnimationFrame(1, 87);
playSound(30, 26);
playSound(29, 49);
@@ -1835,198 +2778,191 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
waitAnimation();
setOns(0, 1);
enableObject(14);
- displayMessage(0x3df4);
- return true;
+ displayMessage(dsAddr_firstTestFailMsg); // "First test failed"
}
+ break;
- case 0x6592: //Rake
+ case 0x6592: // Rake
setOns(1, 0);
playSound(18, 10);
playActorAnimation(553);
- inventory->add(0x15);
+ inventory->add(kInvItemRakeBroken);
wait(50);
- displayMessage(0x3605);
+ displayMessage(dsAddr_trousersMsg); // "Good I always asked mum for trousers with BIG pockets"
disableObject(11);
- return true;
+ break;
case 0x66b5:
playSound(89, 5);
playActorAnimation(969);
loadScene(33, 319, 181, 4);
- return true;
+ break;
- case 0x6519://Sickle
+ case 0x6519: // Sickle
setOns(4, 0);
playSound(5, 11);
playActorAnimation(625);
- inventory->add(0x2c);
+ inventory->add(kInvItemSickleBlunt);
disableObject(8);
- return true;
+ break;
- case 0x655b://Get needle from haystack
- if (CHECK_FLAG(0xdb9d, 1)) { //already have needle
- displayMessage(0x356a);
- return true;
+ case 0x655b: // Get needle from haystack
+ if (CHECK_FLAG(dsAddr_gotNeedleAlreadyFlag, 1)) { // already have needle
+ displayMessage(dsAddr_dontPushLuckMsg); // "I don't think I should push my luck"
} else {
- SET_FLAG(0xdb9d, 1);
+ SET_FLAG(dsAddr_gotNeedleAlreadyFlag, 1);
playSound(49, 3);
playActorAnimation(548);
- inventory->add(0x11);
- displayMessage(0x35b2);
- return true;
+ inventory->add(kInvItemNeedle);
+ displayMessage(dsAddr_needleHaystackMsg); // "And they say you can't find a needle in a haystack"
}
+ break;
- case 0x663c://Feather
+ case 0x663c: // Feather
setOns(0, 0);
playSound(5, 9);
playActorAnimation(511);
- inventory->add(1);
+ inventory->add(kInvItemFeather);
disableObject(15);
- return true;
+ break;
case 0x667c:
playSound(70, 4);
playActorAnimation(972);
loadScene(29, 160, 199, 1);
- return true;
+ break;
case 0x66a9:
- displayMessage(0x4a7e);
+ displayMessage(dsAddr_dontLeaveMansionMsg); // "I don't want to leave the mansion, I want blood!"
disableObject(4);
- return true;
+ break;
case 0x66e2:
playSound(88, 4);
playActorAnimation(970);
loadScene(35, 160, 199, 1);
- return true;
+ break;
case 0x70bb:
- Dialog::pop(scene, 0xdb24, 0, 709, 0xd1, 0xef, 0, 1);
- return true;
+ dialog->pop(scene, dsAddr_dialogStackBusyCook, 0, 709, textColorMark, textColorCook, 0, 1);
+ break;
case 0x71ae:
- if (CHECK_FLAG(0xDBCD, 1)) {
- if (CHECK_FLAG(0xDBCE, 1)) {
- displayMessage(0x4f9b);
+ if (CHECK_FLAG(dsAddr_MansionRadioBrokenFlag, 1)) {
+ if (CHECK_FLAG(dsAddr_MansionGotRadioBatteriesFlag, 1)) {
+ displayMessage(dsAddr_restUselessMsg); // "The rest is useless"
} else {
- displayMessage(0x4fb1);
+ displayMessage(dsAddr_twoBatteriesMsg); // "Wow! Two 1.5V batteries!"
playSound(32, 6);
playActorAnimation(717);
- inventory->add(66);
- SET_FLAG(0xDBCE, 1);
+ inventory->add(kInvItemBatteries);
+ SET_FLAG(dsAddr_MansionGotRadioBatteriesFlag, 1);
}
} else
- Dialog::showMark(scene, 0x3c9d);
- return true;
+ dialog->showMark(97, scene);
+ break;
case 0x70c8:
- if (!processCallback(0x70e0))
- return true;
- moveTo(81, 160, 4);
- displayMessage(0x5cac);
- return true;
-
- case 0x70e0:
- if (!CHECK_FLAG(0xDBCC, 1)) {
- displayMessage(0x4ece);
- return false;
+ if (fnIsCookGone()) {
+ moveTo(81, 160, 4);
+ displayMessage(dsAddr_cognacMsg); // "Pfui! The cognac really didn't do any good"
}
- return true;
+ break;
+
+ case csAddr_isCookGone:
+ retVal = fnIsCookGone();
+ break;
case 0x70ef:
- if (!processCallback(0x70e0))
- return true;
- displayMessage(0x5046);
- return true;
+ if (fnIsCookGone())
+ displayMessage(dsAddr_tooHotMsg); // "It's too hot to touch!"
+ break;
case 0x70f9:
- if (inventory->has(68)) {
- inventory->remove(68);
+ if (inventory->has(kInvItemBurningPaper)) {
+ inventory->remove(kInvItemBurningPaper);
loadScene(29, 40, 176, 2);
- displayMessage(0x500a);
+ displayMessage(dsAddr_paperBurntMsg); // "The paper burnt out completely!"
} else
loadScene(29, 40, 176, 2);
- return true;
+ break;
case 0x712c:
- if (!processCallback(0x70e0))
- return true;
-
- if (CHECK_FLAG(0xDBCF, 1)) {
- playSound(89, 4);
- playActorAnimation(719);
- setOns(4, 67);
- ++ *res->dseg.ptr(READ_LE_UINT16(res->dseg.ptr(0x6746 + (scene->getId() - 1) * 2)));
- disableObject(5);
- enableObject(12);
- } else {
- playSound(89, 4);
- playSound(89, 4);
- playSound(87, 45);
- displayAsyncMessage(0x4fcb, 34672, 11, 35, 0xe5);
- playActorAnimation(718);
- wait(100);
- displayMessage(0x4fe2);
- SET_FLAG(0xDBCF, 1);
+ if (fnIsCookGone()) {
+ if (CHECK_FLAG(dsAddr_MansionHaveOpenedFridgeBeforeFlag, 1)) {
+ playSound(89, 4);
+ playActorAnimation(719);
+ setOns(4, 67);
+ ++ *res->dseg.ptr(READ_LE_UINT16(res->dseg.ptr(dsAddr_sceneWalkboxTablePtr + (scene->getId() - 1) * 2)));
+ disableObject(5);
+ enableObject(12);
+ } else {
+ playSound(89, 4);
+ playSound(89, 4);
+ playSound(87, 45);
+ displayAsyncMessage(dsAddr_oneTakenMsg, 112, 108, 11, 35, textColorEskimo); // "This one's taken, OK?"
+ playActorAnimation(718);
+ wait(100);
+ displayMessage(dsAddr_slightMadMsg); // "It finally happened. I'm slightly mad"
+ SET_FLAG(dsAddr_MansionHaveOpenedFridgeBeforeFlag, 1);
+ }
}
- return true;
+ break;
case 0x71eb:
setOns(2, 0);
playSound(32, 7);
playActorAnimation(710);
- inventory->add(62);
+ inventory->add(kInvItemChilliWithLabel);
disableObject(7);
enableObject(8);
- return true;
+ break;
case 0x7244:
- if (!processCallback(0x70e0))
- return true;
- displayMessage(0x5c60);
- return true;
+ if (fnIsCookGone())
+ displayMessage(dsAddr_neverLearntMsg); // "I never learnt to how use one"
+ break;
case 0x7255:
- if (CHECK_FLAG(0xDBD0, 1)) {
+ if (CHECK_FLAG(dsAddr_MansionPutBurningPaperInFridgeFlag, 1)) {
setOns(4, 69);
playSound(32, 5);
playActorAnimation(725);
disableObject(12);
- inventory->add(69);
+ inventory->add(kInvItemMeat);
} else {
playActorAnimation(721);
- displayMessage(0x505e);
+ displayMessage(dsAddr_frozenShelfMsg); // "It has frozen hard onto the shelf!"
}
- return true;
+ break;
case 0x721c:
setOns(3, 0);
playSound(32, 7);
playActorAnimation(715);
- inventory->add(63);
+ inventory->add(kInvItemPastryRoller);
disableObject(9);
- return true;
+ break;
case 0x7336:
setOns(1, 0);
playSound(5, 42);
- displayAsyncMessage(0x4d02, 32642, 20, 38);
+ displayAsyncMessage(dsAddr_noDepraveMsg, 2, 102, 20, 38); // "Nah, I don't want to deprave the kids"
playActorAnimation(697);
- inventory->add(56);
+ inventory->add(kInvItemCognac);
disableObject(1);
- return true;
+ break;
case 0x7381:
playSound(5, 12);
playActorAnimation(704);
disableObject(2);
- inventory->add(58);
- return true;
+ inventory->add(kInvItemIceTongs);
+ break;
case 0x7408:
- if (CHECK_FLAG(0xDBC4, 1)) {
- displayMessage(0x4d2a);
+ if (CHECK_FLAG(dsAddr_mansionReadNewspaperFlag, 1)) {
+ displayMessage(dsAddr_noReadAgainMsg); // "I don't want to read it again. I might like it."
} else {
setOns(0, 0);
playSound(26, 17);
@@ -2038,45 +2974,45 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playActorAnimation(698);
setOns(0, 52);
setOns(2, 61);
- Dialog::showMark(scene, 0x38b6);
+ dialog->showMark(92, scene);
enableObject(11);
- SET_FLAG(0xDBC4, 1);
+ SET_FLAG(dsAddr_mansionReadNewspaperFlag, 1);
}
- return true;
+ break;
case 0x7476:
- if (CHECK_FLAG(0xDBC9, 1)) {
- displayMessage(0x4dbb);
+ if (CHECK_FLAG(dsAddr_mansionExaminedCouchBeforeFlag, 1)) {
+ displayMessage(dsAddr_noSleepMsg); // "I don't want to sleep"
} else {
- SET_FLAG(0xDBC9, 1);
- Dialog::showMark(scene, 0x3aca);
+ SET_FLAG(dsAddr_mansionExaminedCouchBeforeFlag, 1);
+ dialog->showMark(94, scene);
playSound(61, 5);
playSound(5, 14);
playActorAnimation(705);
- displayMessage(0x4dd3);
- inventory->add(59);
+ displayMessage(dsAddr_justCorkMsg); // "It's just a cork"
+ inventory->add(kInvItemCork);
}
- return true;
+ break;
case 0x74d1:
setOns(2, 0);
playSound(5, 12);
playActorAnimation(699);
- inventory->add(57);
+ inventory->add(kInvItemRemoteControl);
disableObject(11);
- return true;
+ break;
- case 0x7513: //fatso + doctor: pre-final
- if (CHECK_FLAG(0xDBD7, 1)) {
- if (CHECK_FLAG(0xDBD8, 1)) {
+ case 0x7513: // fatso + doctor: pre-final
+ if (CHECK_FLAG(dsAddr_MansionThruFanByTimePillFlag, 1)) {
+ if (CHECK_FLAG(dsAddr_MansionVentFanStoppedFlag, 1)) {
playSound(88, 4);
playActorAnimation(979);
loadScene(37, 51, 183);
- Dialog::show(scene, 0x54ea, 768, 769, 0xd9, 0xe5, 1, 2);
+ dialog->show(125, scene, 768, 769, textColorMansionGuard, textColorProfessor, 1, 2);
playAnimation(770, 0, true, true, true);
playAnimation(771, 1, true, true, true);
- Dialog::showMono(scene, 0x5523, 0, 0xd1, 0);
+ dialog->showMono(126, scene, 0, textColorMark, 0);
playAnimation(770, 0, true, true, true);
playAnimation(771, 1, true, true, true);
playSound(5, 3);
@@ -2090,11 +3026,11 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
waitAnimation();
setOns(0, 74);
hideActor();
- Dialog::showMono(scene, 0x5556, 775, 0xd0, 1);
+ dialog->showMono(127, scene, 775, textColorJohnNoty, 1);
playAnimation(771, 1, true, true, true);
playAnimation(776, 0);
- Dialog::show(scene, 0x55f7, 777, 778, 0xd0, 0xe5, 1, 2); //i have to kill you anyway
+ dialog->show(128, scene, 777, 778, textColorJohnNoty, textColorProfessor, 1, 2);
playAnimation(779, 0, true, true, true);
playAnimation(780, 1, true, true, true);
@@ -2151,7 +3087,7 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
setOns(0, 80);
playAnimation(792, 3, true, true, true);
- Dialog::show(scene, 0x5665, 0, 791, 0xd1, 0xd0, 0, 4);
+ dialog->show(129, scene, 0, 791, textColorMark, textColorJohnNoty, 0, 4);
playAnimation(792, 3, true, true, true);
moveTo(40, 171, 4);
@@ -2161,43 +3097,47 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playAnimation(0, 3);
loadScene(31, 298, 177, 4);
- SET_FLAG(0xDBD9, 1);
- } else {
- displayMessage(0x52fe);
- }
+ SET_FLAG(dsAddr_MansionJohnNotyEscapingFlag, 1);
+ } else
+ displayMessage(dsAddr_ventFirstMsg); // "I'd better stop this ventilator first"
} else
- displayMessage(0x52cb);
- return true;
+ displayMessage(dsAddr_noSaladMsg); // "I don't want to turn myself into a salad"
+ break;
case 0x783d:
- Dialog::pop(scene, 0xdb36, 0, 797, 0xd1, 0xd0, 0, 1);
- return true;
+ dialog->pop(scene, dsAddr_dialogStackJohnNotyEndgame, 0, 797, textColorMark, textColorJohnNoty, 0, 1);
+ break;
case 0x7966:
- if (CHECK_FLAG(0xDBA4, 1))
- return false;
- return processCallback(0x60b5);
+ if (CHECK_FLAG(dsAddr_lightOnFlag, 1))
+ retVal = false;
+ else
+ fnEgoScaredBySpider();
+ break;
case 0x7ad0:
case 0x7ad7:
- return !processCallback(0x70e0);
+ retVal = !fnIsCookGone();
+ break;
case 0x7ab9:
- if (CHECK_FLAG(0xDBB6, 1))
- return false;
- Dialog::showMono(scene, 0x37d0, 0, 0xd1, 0);
- SET_FLAG(0xDBB6, 1);
- return true;
+ if (CHECK_FLAG(dsAddr_vgaArtistQuipAlreadySaidFlag, 1))
+ retVal = false;
+ else {
+ dialog->showMono(90, scene, 0, textColorMark, 0);
+ SET_FLAG(dsAddr_vgaArtistQuipAlreadySaidFlag, 1);
+ }
+ break;
case 0x7ade:
- if (CHECK_FLAG(0xdbcd, 1)) {
- displayMessage(0x4f69);
- return true;
- } else
- return false;
+ if (CHECK_FLAG(dsAddr_MansionRadioBrokenFlag, 1))
+ displayMessage(dsAddr_whatInsideMsg); // "I was always curious what's inside these things"
+ else
+ retVal = false;
+ break;
- case 0x7f23://Use grenade on captains drawer
- if (CHECK_FLAG(0xDBDF, 3)) {
+ case 0x7f23: // Use grenade on captains drawer
+ if (CHECK_FLAG(dsAddr_FirstActTrialState, 3)) {
enableOn(false);
playSound(5, 3);
playSound(58, 11);
@@ -2207,123 +3147,120 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playActorAnimation(870);
playSound(54, 15);
playActorAnimation(871);
- SET_FLAG(0xDBE6, 1);
+ SET_FLAG(dsAddr_captainDrawerState, 1);
setOns(1, 0x66);
moveTo(224, 194, 0, true);
- displayCutsceneMessage(0x57df, 30423);
- inventory->remove(0x59);
+ displayCutsceneMessage(dsAddr_cutsceneMsg1, 23, 95); // "sixty seven rude words later"
+ inventory->remove(kInvItemRopeAndGrenade);
enableOn(true);
- } else {
- displayMessage(0x5de2);
- }
- return true;
+ } else
+ displayMessage(dsAddr_captainWatchingMsg); // "with captain watching? Better not"
+ break;
- case 0x505c: {
- //suspicious stuff
- Common::Point p = scene->getPosition();
- if (p.x != 203 && p.y != 171)
- moveTo(203, 169, 2);
- else
- moveTo(203, 169, 1);
- }
- return true;
+ case csAddr_egoSuspiciousPosition:
+ fnEgoSuspiciousPosition();
+ break;
case 0x509a:
- processCallback(0x505c);
+ fnEgoSuspiciousPosition();
setOns(1, 0);
playSound(5, 10);
playActorAnimation(543);
- inventory->add(15);
+ inventory->add(kInvItemBranch);
disableObject(9);
- return true;
+ break;
case 0x7802:
- if (CHECK_FLAG(0xDBD7, 1)) {
- if (CHECK_FLAG(0xDBD8, 1))
- displayMessage(0x52f6);
+ if (CHECK_FLAG(dsAddr_MansionThruFanByTimePillFlag, 1)) {
+ if (CHECK_FLAG(dsAddr_MansionVentFanStoppedFlag, 1))
+ displayMessage(dsAddr_nahMsg); // "Nah"
else {
playSound(71, 4);
playActorAnimation(796);
setLan(1, 0);
- SET_FLAG(0xDBD8, 1);
+ SET_FLAG(dsAddr_MansionVentFanStoppedFlag, 1);
}
} else
- displayMessage(0x52cb);
- return true;
+ displayMessage(dsAddr_noSaladMsg); // "I don't want to turn myself into a salad"
+ break;
case 0x78e0:
- processCallback(0x505c);
- return false;
+ fnEgoSuspiciousPosition();
+ retVal = false;
+ break;
case 0x78e7:
- processCallback(0x557e);
- return false;
-
case 0x78ee:
- processCallback(0x557e);
- return false;
+ fnEgoDefaultPosition();
+ retVal = false;
+ break;
case 0x78f5:
- if (CHECK_FLAG(0xDB95, 1)) {
- displayMessage(0x3E75);
- return true;
+ if (CHECK_FLAG(dsAddr_carTrunkEmptyFlag, 1)) {
+ displayMessage(dsAddr_bootEmptyMsg); // "There's nothing else in the boot"
} else
- return false;
+ retVal = false;
+ break;
case 0x7919:
- if (!CHECK_FLAG(0xDBA5, 1))
- return false;
- displayMessage(0x3E98);
- return true;
+ if (!CHECK_FLAG(dsAddr_laundryState, 1))
+ retVal = false;
+ else
+ displayMessage(dsAddr_clothesDryMsg); // "The clothes are dry now."
+ break;
case 0x7950:
- if (!CHECK_FLAG(0xDBB1, 1))
- return false;
-
- displayMessage(0x3DAF);
- return true;
+ if (CHECK_FLAG(dsAddr_nutSwappedForAppleFlag, 1))
+ displayMessage(dsAddr_nutRealMsg); // "Only the nut is real"
+ else
+ retVal = false;
+ break;
case 0x7975:
- if (CHECK_FLAG(0xDBA4, 1))
- return false;
- displayMessage(0x3832);
- return true;
+ if (CHECK_FLAG(dsAddr_lightOnFlag, 1))
+ retVal = false;
+ else
+ displayMessage(dsAddr_shutValveMsg); // "Shutting the valve shook the dirt from the wall..."
+ break;
case 0x7987:
case 0x7996:
case 0x79a5:
case 0x79b4:
- if (CHECK_FLAG(0xDBA4, 1))
- return false;
- return processCallback(0x61fe);
+ if (CHECK_FLAG(dsAddr_lightOnFlag, 1))
+ retVal = false;
+ else
+ fnTooDark();
+ break;
case 0x79d2:
- if (!CHECK_FLAG(0xDB9D, 1))
- return false;
- displayMessage(0x3590);
- return true;
+ if (!CHECK_FLAG(dsAddr_gotNeedleAlreadyFlag, 1))
+ retVal = false;
+ else
+ displayMessage(dsAddr_ordinaryHaystackMsg); // "Just an ordinary hay stack. Now."
+ break;
case 0x7af0:
- if (!processCallback(0x70e0))
- return true;
- return false;
+ if (fnIsCookGone())
+ retVal = false;
+ break;
case 0x8117:
- Dialog::show(scene, 0x0a41, 0, 529, 0xd1, 0xd9, 0, 1);
+ dialog->show(9, scene, 0, 529, textColorMark, textColorMansionGuard, 0, 1);
playSound(5, 2);
playSound(5, 44);
playAnimation(642, 0, true);
playActorAnimation(641, true);
waitAnimation();
- Dialog::show(scene, 0x0aff, 0, 529, 0xd1, 0xd9, 0, 1);
+ dialog->show(10, scene, 0, 529, textColorMark, textColorMansionGuard, 0, 1);
wait(170);
- Dialog::show(scene, 0x0ba0, 0, 529, 0xd1, 0xd9, 0, 1);
+ dialog->show(11, scene, 0, 529, textColorMark, textColorMansionGuard, 0, 1);
moveRel(0, 1, 0);
wait(100);
- Dialog::show(scene, 0x0c10, 0, 529, 0xd1, 0xd9, 0, 1);
- inventory->remove(50);
- processCallback(0x9d45);
- return true;
+ dialog->show(12, scene, 0, 529, textColorMark, textColorMansionGuard, 0, 1);
+ inventory->remove(kInvItemNugget);
+ fnMansionIntrusionAttempt();
+ break;
case 0x8174:
setOns(0, 0);
@@ -2336,7 +3273,7 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
setOns(1, 15);
disableObject(3);
enableObject(9);
- return true;
+ break;
case 0x81c2:
playSound(56, 11);
@@ -2353,12 +3290,12 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playActorAnimation(588, true);
waitAnimation();
wait(50);
- displayMessage(0x367f);
- inventory->remove(34);
- SET_FLAG(0xDBA1, 1);
- return true;
+ displayMessage(dsAddr_itsGoneMsg); // "At least it's gone"
+ inventory->remove(kInvItemPaintedPotato);
+ SET_FLAG(dsAddr_mansionTreeHollowEmptyFlag, 1);
+ break;
- case 0x823d: //grappling hook on the wall
+ case 0x823d: // grappling hook on the wall
playSound(5, 3);
for (byte i = 16; i <= 28; i += 2)
playSound(65, i);
@@ -2367,27 +3304,26 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
for (byte i = 3; i <= 18; i += 3)
playSound(56, i);
- displayAsyncMessage(0x3ace, 3878, 20, 37, 0xd9);
+ displayAsyncMessage(dsAddr_heyLetGoMsg, 38, 12, 20, 37, textColorMansionGuard); // "Hey, let go, will ya?!"
playActorAnimation(621, true);
playAnimation(623, 1, true);
waitAnimation();
- displayAsyncMessage(0x3ae6, 3870, 1, 9, 0xd9);
+ displayAsyncMessage(dsAddr_aaahhhMsg, 30, 12, 1, 9, textColorMansionGuard); // "Aaaaaaaaaaaaahhh!"
playSound(35, 1);
playActorAnimation(622, true);
playAnimation(624, 0, true);
waitAnimation();
wait(150);
- displayMessage(0x3afd);
-
- inventory->remove(43);
- processCallback(0x9d45);
- return true;
+ displayMessage(dsAddr_oopsMsg); // "Oops"
+ inventory->remove(kInvItemGrapplingHook);
+ fnMansionIntrusionAttempt();
+ break;
- case 0x8312: //hedgehog + plastic apple
- Dialog::showMark(scene, 0x3000);
+ case 0x8312: // hedgehog + plastic apple
+ dialog->showMark(76, scene);
setLan(1, 0);
playSound(5, 24);
playSound(26, 32);
@@ -2405,13 +3341,13 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
waitAnimation();
disableObject(6);
- displayMessage(0x363f);
- inventory->remove(27);
- inventory->add(28);
- return true;
+ displayMessage(dsAddr_lifeIsBrutalMsg); // "Life is brutal"
+ inventory->remove(kInvItemPlasticApple);
+ inventory->add(kInvItemCone);
+ break;
case 0x839f:
- inventory->remove(32);
+ inventory->remove(kInvItemDart);
playSound(37, 14);
playSound(16, 17);
playActorAnimation(564, true);
@@ -2437,10 +3373,10 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playSound(55, 18);
playAnimation(581, 1);
disableObject(2);
- SET_FLAG(0xDB9F, 1);
- return true;
+ SET_FLAG(dsAddr_beesGoneFlag, 1);
+ break;
- case 0x84c7: //using paddle on boat
+ case 0x84c7: // using paddle on boat
playSound(20, 9);
playActorAnimation(530);
loadScene(16, 236, 95, 1);
@@ -2451,12 +3387,12 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playActorAnimation(533);
setOns(0, 9);
moveTo(236, 95, 1, true);
- return true;
+ break;
- case 0x8538://Sharpen sickle on well
+ case 0x8538: // Sharpen sickle on well
moveTo(236, 190, 0);
setOns(2, 0);
- //TODO: Remove handle sprite
+ // FIXME: Add code to Remove handle sprite (visible GFX glitch)
playSound(5, 4);
playSound(14, 14);
playSound(14, 33);
@@ -2464,52 +3400,58 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playActorAnimation(643);
setOns(2, 43);
moveTo(236, 179, 3);
- inventory->remove(0x2c);
- inventory->add(0x2e);
- return true;
+ inventory->remove(kInvItemSickleBlunt);
+ inventory->add(kInvItemSickleSharp);
+ break;
+
+ case 0x85d6:
+ displayMessage(dsAddr_paddleBrokenMsg); // "The paddle is BROKEN"
+ break;
case 0x85eb:
- if (CHECK_FLAG(0xDBB0, 1)) {
+ if (CHECK_FLAG(dsAddr_squirrelNutState, 1)) {
enableObject(6);
playSound(25, 10);
playSound(25, 14);
playSound(25, 18);
playActorAnimation(559);
setOns(1, 23);
- SET_FLAG(0xDBB0, 2);
+ SET_FLAG(dsAddr_squirrelNutState, 2);
} else
- displayMessage(0x3d86);
-
- return true;
+ displayMessage(dsAddr_dontWorkPurposeMsg); // "I usually don't work without a purpose"
+ break;
case 0x863d:
playSound(12, 4);
playSound(50, 20);
playSound(50, 29);
playActorAnimation(554);
- inventory->remove(19);
- inventory->add(22);
- return true;
+ inventory->remove(kInvItemChocCandy);
+ inventory->add(kInvItemHeartShapedCandy);
+ break;
case 0x8665:
playSound(5, 3);
for (byte i = 12; i <= 24; i += 2)
playSound(56, i);
playActorAnimation(567);
- inventory->remove(12);
- inventory->add(33);
- return true;
+ inventory->remove(kInvItemFeatherDusterClean);
+ inventory->add(kInvItemFeatherDusterDirty);
+ break;
case 0x862c:
- displayMessage(CHECK_FLAG(0xDBB0, 1) ? 0x4882 : 0x3457);
- return true;
+ if (CHECK_FLAG(dsAddr_squirrelNutState, 1))
+ displayMessage(dsAddr_nutRakeMsg); // "It's pointless, the nut will slip between the rake's teeth"
+ else
+ displayMessage(dsAddr_objErrorMsg); // "That's no good"
+ break;
- case 0x86a9: //correcting height of the pole with spanner
- if (CHECK_FLAG(0xDB92, 1)) {
- displayMessage(0x3d40);
+ case 0x86a9: // correcting height of the pole with spanner
+ if (CHECK_FLAG(dsAddr_alreadyAdjustedHoopPoleFlag, 1)) {
+ displayMessage(dsAddr_noNeedMsg); // "No need to do it again"
} else {
- SET_FLAG(0xDB92, 1);
- Dialog::show(scene, 0x0fcd, 0, 502, 0xd0, 0xe5, 0, 1);
+ SET_FLAG(dsAddr_alreadyAdjustedHoopPoleFlag, 1);
+ dialog->show(17, scene, 0, 502, textColorMark, textColorSonny, 0, 1);
waitLanAnimationFrame(1, 7);
playSound(5, 16);
playSound(1, 25);
@@ -2528,7 +3470,7 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playSound(5, 43);
playSound(61, 70);
playSound(61, 91);
- displayAsyncMessage(0x3cfb, 28877, 6, 17);
+ displayAsyncMessage(dsAddr_ConfusionMsg, 77, 90, 6, 17); // "!?&!"
playActorAnimation(505, true);
playAnimation(507, 0, true);
waitAnimation();
@@ -2552,8 +3494,8 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
disableObject(15);
disableObject(16);
moveTo(162, 164, 2);
- displayMessage(0x3d01, 0xe5, 24390);
- displayMessage(0x3d20, 0xd8, 24410);
+ displayMessage(dsAddr_grandpaPromiseMsg, textColorSonny, 70, 76); // "But grandpa, you promised!"
+ displayMessage(dsAddr_ohLetsGoMsg, textColorGrandpa, 90, 76); // "Oh all right. Let's go"
moveTo(162, 191, 2);
setOns(1, 0);
setOns(2, 0);
@@ -2572,133 +3514,118 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playAnimation(512, 0);
wait(100);
- displayMessage(0x3d3a);
+ displayMessage(dsAddr_byeMsg); // "Bye."
{
Object *obj = scene->getObject(7);
- obj->actor_rect.left = obj->actor_rect.right = 228;
- obj->actor_rect.top = obj->actor_rect.bottom = 171;
- obj->actor_rect.save();
+ obj->actorRect.left = obj->actorRect.right = 228;
+ obj->actorRect.top = obj->actorRect.bottom = 171;
+ obj->actorRect.save();
}
{
Object *obj = scene->getObject(8);
- obj->actor_rect.left = obj->actor_rect.right = 290;
- obj->actor_rect.top = obj->actor_rect.bottom = 171;
- obj->actor_rect.save();
+ obj->actorRect.left = obj->actorRect.right = 290;
+ obj->actorRect.top = obj->actorRect.bottom = 171;
+ obj->actorRect.save();
}
}
- return true;
+ break;
- case 0x88c9: //give flower to old lady
- if (CHECK_FLAG(0xDB9A, 1))
- return processCallback(0x890b);
-
- inventory->remove(10);
- SET_FLAG(0xDB9A, 1);
- processCallback(0x88DE);
- return true;
-
- case 0x88de:
- playSound(5, 2);
- Dialog::show(scene, 0x1B5F, 0, 523, 0xd1, 0xe5, 0, 1);
- playActorAnimation(537, true);
- playAnimation(538, 0, true);
- waitAnimation();
- wait(100);
- Dialog::show(scene, 0x1BE0, 0, 523, 0xd1, 0xe5, 0, 1);
- return true;
+ case 0x88c9: // give flower to old lady
+ if (CHECK_FLAG(dsAddr_givenFlowerToOldLadyAlreadyFlag, 1))
+ fnGiveAnotherFlowerToOldLady();
+ else {
+ inventory->remove(kInvItemFirstFlower);
+ SET_FLAG(dsAddr_givenFlowerToOldLadyAlreadyFlag, 1);
+ fnGivingFlowerToOldLady();
+ }
+ break;
- case 0x890b:
- Dialog::pop(scene, 0xDAF0, 0, 523, 0xd1, 0xe5, 0, 1);
- return true;
+ case csAddr_givingFlowerToOldLady:
+ fnGivingFlowerToOldLady();
+ break;
- case 0x8918://give flower to old lady
- if (CHECK_FLAG(0xDB9A, 1))
- return processCallback(0x890B);
+ case csAddr_giveAnotherFlowerToOldLady:
+ fnGiveAnotherFlowerToOldLady();
+ break;
- inventory->remove(11);
- SET_FLAG(0xDB9A, 1);
- processCallback(0x88DE);
- return true;
+ case 0x8918: // give flower to old lady
+ if (CHECK_FLAG(dsAddr_givenFlowerToOldLadyAlreadyFlag, 1))
+ fnGiveAnotherFlowerToOldLady();
+ else {
+ inventory->remove(kInvItemSecondFlower);
+ SET_FLAG(dsAddr_givenFlowerToOldLadyAlreadyFlag, 1);
+ fnGivingFlowerToOldLady();
+ }
+ break;
case 0x892d:
- if (CHECK_FLAG(0xDB9B, 1))
- return processCallback(0x89aa);
+ if (CHECK_FLAG(dsAddr_givenFlowerToAnneAlreadyFlag, 1))
+ fnGiveAnotherFlowerToAnne();
+ else {
+ fnGivingFlowerToAnne();
+ inventory->remove(kInvItemFirstFlower);
+ SET_FLAG(dsAddr_givenFlowerToAnneAlreadyFlag, 1);
+ }
+ break;
- processCallback(0x8942);
- inventory->remove(10);
- SET_FLAG(0xDB9B, 1);
- return true;
+ case csAddr_givingFlowerToAnne:
+ fnGivingFlowerToAnne();
+ break;
- case 0x8942:
- Dialog::show(scene, 0x2293, 0, 524, 0xd1, 0xe5, 0, 2);
- playSound(5, 10);
- playActorAnimation(540, true);
- playAnimation(539, 1, true);
- waitAnimation();
- wait(100);
- Dialog::show(scene, 0x24b1, 0, 524, 0xd1, 0xe5, 0, 2);
- wait(50);
- Dialog::show(scene, 0x24d7, 0, 524, 0xd1, 0xe5, 0, 2);
- Dialog::show(scene, 0x2514, 0, 524, 0xd1, 0xe5, 0, 2);
- wait(50);
- moveRel(0, 1, 0);
- Dialog::show(scene, 0x2570, 0, 524, 0xd1, 0xe5, 0, 2);
- moveRel(0, -1, 0);
- wait(50);
- return true;
-
- case 0x89aa:
- Dialog::pop(scene, 0xdb02, 0, 524, 0xd1, 0xe5, 0, 2);
- return true;
+ case csAddr_giveAnotherFlowerToAnne:
+ fnGiveAnotherFlowerToAnne();
+ break;
case 0x89b7:
- if (CHECK_FLAG(0xDB9B, 1))
- return processCallback(0x89aa);
-
- processCallback(0x8942);
- inventory->remove(11);
- SET_FLAG(0xDB9B, 1);
- return true;
+ if (CHECK_FLAG(dsAddr_givenFlowerToAnneAlreadyFlag, 1))
+ fnGiveAnotherFlowerToAnne();
+ else {
+ fnGivingFlowerToAnne();
+ inventory->remove(kInvItemSecondFlower);
+ SET_FLAG(dsAddr_givenFlowerToAnneAlreadyFlag, 1);
+ }
+ break;
case 0x89cc:
- inventory->remove(23);
+ inventory->remove(kInvItemWrappedCandy);
playSound(5, 6);
- Dialog::show(scene, 0x2634, 0, 524, 0xd1, 0xe5, 0, 2);
+ dialog->show(60, scene, 0, 524, textColorMark, textColorAnne, 0, 2);
+ // FIXME - Dialog #61 not explicitly called. Does Dialog #60 run on somehow?
playActorAnimation(555, true);
playAnimation(556, 1, true);
waitAnimation();
playActorAnimation(557, true);
playAnimation(558, 1, true);
waitAnimation();
- Dialog::show(scene, 0x2971, 0, 524, 0xd1, 0xe5, 0, 2);
- inventory->add(24);
- return true;
+ dialog->show(62, scene, 0, 524, textColorMark, textColorAnne, 0, 2);
+ inventory->add(kInvItemRibbon);
+ break;
case 0x8a22:
playSound(45, 16);
playActorAnimation(560);
- inventory->remove(26);
- inventory->add(27);
+ inventory->remove(kInvItemNut);
+ inventory->add(kInvItemPlasticApple);
wait(50);
- Dialog::show(scene, 0x1ecd, 0, 523, 0xd1, 0xe5, 0, 1);
- Dialog::show(scene, 0x1f09, 0, 523, 0xd1, 0xe5, 0, 1);
- SET_FLAG(0xDBB1, 1);
- return true;
-
- case 0x8a6f: //banknote + ann
- if (CHECK_FLAG(0xDBB5, 1)) {
- Dialog::show(scene, 0x2992, 0, 524, 0xd1, 0xe5, 0, 2);
+ dialog->show(44, scene, 0, 523, textColorMark, textColorOldLady, 0, 1);
+ dialog->show(45, scene, 0, 523, textColorMark, textColorOldLady, 0, 1);
+ SET_FLAG(dsAddr_nutSwappedForAppleFlag, 1);
+ break;
+
+ case 0x8a6f: // banknote + ann
+ if (CHECK_FLAG(dsAddr_examinedBanknoteFlag, 1)) {
+ dialog->show(63, scene, 0, 524, textColorMark, textColorAnne, 0, 2);
playSound(5, 3);
playSound(5, 20);
playAnimation(671, 1, true);
playActorAnimation(670, true);
waitAnimation();
//playAnimation(672, 1);
- Dialog::show(scene, 0x2a00, 524, 672, 0xd1, 0xe5, 0, 2);
+ dialog->show(64, scene, 524, 672, textColorMark, textColorAnne, 0, 2);
//playAnimation(672, 1);
playSound(83, 12);
- displayAsyncMessage(0x4a5b, 36684, 23, 38, 0xe5);
+ displayAsyncMessage(dsAddr_hundredBucksMsg, 204, 114, 23, 38, textColorAnne); // "A hundred bucks!!!"
playActorAnimation(673);
loadScene(11, scene->getPosition());
playSound(24, 31);
@@ -2710,14 +3637,14 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
loadScene(28, 0, 167, 2);
playMusic(10);
moveTo(66, 167, 2);
- displayMessage(0x4a6f);
+ displayMessage(dsAddr_wantBloodMsg); // "I want Blood!"
inventory->clear();
- inventory->add(29);
+ inventory->add(kInvItemSuperGlue);
} else
- displayMessage(0x4a29);
- return true;
+ displayMessage(dsAddr_showHerMoneyMsg); // "If I just show her the money, she might take it"
+ break;
- case 0x8b82: //use fan on laundry
+ case 0x8b82: // use fan on laundry
setOns(0, 0);
playSound(5, 3);
playSound(5, 6);
@@ -2725,16 +3652,16 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playSound(92, 20);
playSound(92, 38);
playSound(92, 58);
- displayAsyncMessage(0x464a, 36510, 58, 67);
+ displayAsyncMessage(dsAddr_yawnMsg, 30, 114, 58, 67); // "(yawn)"
playActorAnimation(602);
playSound(5, 3);
playActorAnimation(603);
setOns(0, 27);
- SET_FLAG(0xDBA5, 1);
- return true;
+ SET_FLAG(dsAddr_laundryState, 1);
+ break;
- case 0x8bfc://Give bone to dog
- displayMessage(0x3c31);
+ case 0x8bfc: // Give bone to dog
+ displayMessage(dsAddr_hereBoyMsg); // "Here, boy"
playSound(5, 3);
playSound(26, 13);
playActorAnimation(657, true);
@@ -2744,20 +3671,20 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
reloadLan();
playAnimation(659, 0);
- inventory->remove(36);
- SET_FLAG(0xDBAD, 1);
+ inventory->remove(kInvItemBone);
+ SET_FLAG(dsAddr_dogHasBoneFlag, 1);
{
Object *o = scene->getObject(7);
- o->actor_rect.left = o->actor_rect.right = 297;
- o->actor_rect.top = o->actor_rect.bottom = 181;
- o->actor_orientation = 1;
+ o->actorRect.left = o->actorRect.right = 297;
+ o->actorRect.top = o->actorRect.bottom = 181;
+ o->actorOrientation = 1;
o->save();
}
{
Object *o = scene->getObject(9);
- o->actor_rect.left = o->actor_rect.right = 297;
- o->actor_rect.top = o->actor_rect.bottom = 181;
- o->actor_orientation = 1;
+ o->actorRect.left = o->actorRect.right = 297;
+ o->actorRect.top = o->actorRect.bottom = 181;
+ o->actorOrientation = 1;
o->save();
}
{
@@ -2767,10 +3694,10 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
w->save();
}
wait(100);
- displayMessage(0x3c3d);
- return true;
+ displayMessage(dsAddr_friendsNowMsg); // "I hope we're friends now"
+ break;
- case 0x8c6e://Use car jack on rock
+ case 0x8c6e: // Use car jack on rock
playSound(5, 3);
playSound(26, 13);
playSound(24, 22);
@@ -2782,10 +3709,10 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playActorAnimation(593);
setOns(0, 28);
enableObject(1);
- inventory->remove(35);
- return true;
+ inventory->remove(kInvItemCarJack);
+ break;
- case 0x8cc8://Cut bush with sickle
+ case 0x8cc8: // Cut bush with sickle
playSound(5, 3);
playActorAnimation(644);
setOns(1, 45);
@@ -2799,16 +3726,16 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playActorAnimation(646);
playSound(5, 21);
playActorAnimation(647);
- SET_FLAG(0xdaca, 1);
- inventory->remove(0x2e);
+ SET_FLAG(dsAddr_caveThornsCutDownFlag, 1);
+ inventory->remove(kInvItemSickleSharp);
disableObject(2);
- scene->getObject(3)->actor_rect.right = 156;
+ scene->getObject(3)->actorRect.right = 156;
scene->getObject(3)->save();
- return true;
+ break;
- case 0x8d79: //mouse falls back from the hole (cave)
- if (CHECK_FLAG(0, 1)) {
- inventory->add(48);
+ case csAddr_mouseOutOfHoleTimeout: // mouse falls back from the hole (cave)
+ if (CHECK_FLAG(dsAddr_timedCallbackState, 1)) {
+ inventory->add(kInvItemMouse);
playSound(24, 26);
playActorAnimation(650, true);
playAnimation(651, 2, true);
@@ -2824,54 +3751,26 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playActorAnimation(654, true);
playAnimation(655, 2, true);
waitAnimation();
- displayMessage(0x3bf6);
- inventory->add(49);
+ displayMessage(dsAddr_mouseGoneMsg); // "The mouse has gone!"
+ inventory->add(kInvItemRock);
setLan(2, 4, 27);
enableObject(4, 27);
- SET_FLAG(0xdba9, 0);
+ SET_FLAG(dsAddr_mouseHoleState, 0);
}
- SET_FLAG(0, 0);
- return true;
+ SET_FLAG(dsAddr_timedCallbackState, 0);
+ break;
- case 0x8d57:
- if (CHECK_FLAG(0, 0)) {
- playSound(5, 2);
- playSound(15, 12);
- playActorAnimation(638);
- inventory->remove(48);
- setTimerCallback(0x8d79, 100);
- SET_FLAG(0, 1);
- } else if (CHECK_FLAG(0, 1)) {
- playSound(5, 2);
- playSound(52, 13);
- playActorAnimation(648);
- setOns(1, 46);
- inventory->remove(49);
- setTimerCallback(0x8d79, 100);
- SET_FLAG(0, 2);
- } else if (CHECK_FLAG(0, 2)) {
- playActorAnimation(649);
- setOns(1, 47);
- wait(300);
- for (byte i = 1; i <= 37; i += 4)
- playSound(68, i);
- playAnimation(639, 2);
- setOns(0, 42);
- enableObject(6);
- disableObject(5);
- SET_FLAG(0xDBAB, 1);
- SET_FLAG(0, 0);
- setTimerCallback(0, 0);
- }
- return true;
+ case csAddr_putRockInHole:
+ fnPutRockInHole();
+ break;
case 0x8f1d:
- Dialog::showMark(scene, 0x2dd6);
+ dialog->showMark(72, scene);
for (uint i = 16; i <= 30; i += 2)
playSound(56, i);
playSound(2, 64);
playSound(3, 74);
- displayAsyncMessage(0x34c7, 25812, 35, 50);
+ displayAsyncMessage(dsAddr_lastChanceMsg, 212, 80, 35, 50); // "Last chance?"
playActorAnimation(516, true);
playAnimation(517, 2, true);
playAnimation(518, 3, true);
@@ -2880,12 +3779,12 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
setLan(4, 0);
disableObject(2);
disableObject(3);
- inventory->remove(2);
- SET_FLAG(0xDB96, 1);
- return true;
+ inventory->remove(kInvItemShotgun);
+ SET_FLAG(dsAddr_birdsGoneFromScarecrowFlag, 1);
+ break;
case 0x8fc8:
- displayMessage(0x3b2f);
+ displayMessage(dsAddr_comeHereMsg); // "Come here, I've got something for you"
waitLanAnimationFrame(2, 4);
playSound(5, 3);
playActorAnimation(627, true);
@@ -2894,25 +3793,25 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playSound(41, 10);
playSound(41, 47);
playSound(55, 52);
- if (CHECK_FLAG(0xDBA8, 1)) {
+ if (CHECK_FLAG(dsAddr_HankerchiefInMouseholeFlag, 1)) {
setLan(2, 0);
playActorAnimation(628, true);
playAnimation(634, 1, true);
waitAnimation();
disableObject(4);
- displayMessage(0x3b6c);
- SET_FLAG(0xDBA9, 1);
+ displayMessage(dsAddr_trappedMouseMsg); // "The mouse is trapped!"
+ SET_FLAG(dsAddr_mouseHoleState, 1);
} else {
playActorAnimation(628, true);
playAnimation(630, 1, true);
waitAnimation();
- displayMessage(0x3b59);
+ displayMessage(dsAddr_cantCatchMsg); // "I can't catch it!"
}
- return true;
+ break;
- case 0x9054: //mouse hole
- if (CHECK_FLAG(0xDBAB, 1)) {
- displayMessage(0x3c0b);
+ case 0x9054: // mouse hole
+ if (CHECK_FLAG(dsAddr_mouseGotGoldNuggetFlag, 1)) {
+ displayMessage(dsAddr_nonsenseMsg); // "Nonsense"
} else {
playSound(5, 11);
playSound(49, 21);
@@ -2920,50 +3819,48 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
setOns(5, 40);
moveTo(239, 139, 0, true);
playActorAnimation(633);
- SET_FLAG(0xDBA8, 1);
- inventory->remove(47);
- if (!CHECK_FLAG(0xDBAA, 1)) {
- SET_FLAG(0xDBAA, 1);
- displayMessage(0x3b8b);
+ SET_FLAG(dsAddr_HankerchiefInMouseholeFlag, 1);
+ inventory->remove(kInvItemHandkerchief);
+ if (!CHECK_FLAG(dsAddr_mouseNerveMsgSaidFlag, 1)) {
+ SET_FLAG(dsAddr_mouseNerveMsgSaidFlag, 1);
+ displayMessage(dsAddr_mouseNerveMsg); // "Boy, this mouse has some nerve!"
}
}
- return true;
+ break;
case 0x933d:
- if (!processCallback(0x70e0))
- return true;
-
- if (CHECK_FLAG(0xdbcd, 1)) {
- displayMessage(0x4f3d);
- return true;
+ if (fnIsCookGone()) {
+ if (CHECK_FLAG(dsAddr_MansionRadioBrokenFlag, 1))
+ displayMessage(dsAddr_breakFlattenMsg); // "I wanted to break it, not to flatten it!"
+ else {
+ setOns(1, 0);
+ playSound(5, 3);
+ playSound(5, 33);
+ playSound(24, 13);
+ playSound(24, 19);
+ playSound(24, 23);
+ playSound(24, 26);
+ playSound(24, 29);
+ playSound(23, 21);
+ playSound(74, 25);
+ playActorAnimation(716);
+ setOns(1, 66);
+ SET_FLAG(dsAddr_MansionRadioBrokenFlag, 1);
+ }
}
+ break;
- setOns(1, 0);
- playSound(5, 3);
- playSound(5, 33);
- playSound(24, 13);
- playSound(24, 19);
- playSound(24, 23);
- playSound(24, 26);
- playSound(24, 29);
- playSound(23, 21);
- playSound(74, 25);
- playActorAnimation(716);
- setOns(1, 66);
- SET_FLAG(0xDBCD, 1);
- return true;
-
- case 0x93af: //sheet + hot plate
- if (!processCallback(0x70e0))
- return true;
- playSound(5, 3);
- playSound(86, 11);
- playActorAnimation(720);
- inventory->add(68);
- inventory->remove(55);
- return true;
+ case 0x93af: // sheet + hot plate
+ if (fnIsCookGone()) {
+ playSound(5, 3);
+ playSound(86, 11);
+ playActorAnimation(720);
+ inventory->add(kInvItemBurningPaper);
+ inventory->remove(kInvItemSheetOfPaper);
+ }
+ break;
- case 0x93d5: //burning sheet + plate
+ case 0x93d5: // burning sheet + plate
setOns(4, 0);
playSound(87, 7);
playActorAnimation(722);
@@ -2971,323 +3868,298 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playSound(88, 12);
playSound(87, 24);
playActorAnimation(723);
- displayMessage(0x502b);
+ displayMessage(dsAddr_burnBabyMsg); // "Burn, baby, burn!"
wait(100);
playSound(89, 4);
playActorAnimation(724);
setOns(4, 68);
- displayMessage(0x503e);
- inventory->remove(68);
- SET_FLAG(0xDBD0, 1);
- return true;
-
- case 0x98fa://Right click to open toolbox
- inventory->remove(3);
- inventory->add(4);
- inventory->add(35);
+ displayMessage(dsAddr_voilaMsg); // "Voila"
+ inventory->remove(kInvItemBurningPaper);
+ SET_FLAG(dsAddr_MansionPutBurningPaperInFridgeFlag, 1);
+ break;
+
+ case csAddr_openFullToolbox: // Right click to open toolbox
+ inventory->remove(kInvItemToolboxFull);
+ inventory->add(kInvItemToolboxHalfEmpty);
+ inventory->add(kInvItemCarJack);
inventory->activate(false);
inventory->resetSelectedObject();
- displayMessage(0x3468);
- return true;
+ displayMessage(dsAddr_carJackMsg); // "Wow! There's a car jack inside! Great!"
+ break;
- case 0x9910:
- inventory->remove(4);
- inventory->add(5);
+ case csAddr_openHalfEmptyToolbox:
+ inventory->remove(kInvItemToolboxHalfEmpty);
+ inventory->add(kInvItemSpanner);
inventory->activate(false);
inventory->resetSelectedObject();
- displayMessage(0x3490);
- return true;
+ displayMessage(dsAddr_spannerMsg); // "There's something else inside the toolbox! A spanner!"
+ break;
-
- //very last part of the game:
- case 0x671d:
+ case 0x671d: // very last part of the game
moveTo(153, 163, 4);
playActorAnimation(973);
- if (CHECK_FLAG(0xDBC1, 0)) {
- SET_FLAG(0xDBC1, _rnd.getRandomNumber(5) + 1);
+ if (CHECK_FLAG(dsAddr_drawerPuzzleBookValue, 0)) {
+ SET_FLAG(dsAddr_drawerPuzzleBookValue, _rnd.getRandomNumber(5) + 1);
}
loadScene(30, 18, 159, 2);
- return true;
+ break;
case 0x67a6:
loadScene(29, 149, 163, 1);
playActorAnimation(974);
moveTo(160, 188, 0);
- return true;
+ break;
case 0x6805:
- processCallback(0x6849);
+ fnEgoBottomRightTurn();
playSound(32, 12);
playActorAnimation(694);
playSound(15, 8);
playAnimation(693, 0);
setOns(6, 0);
- displayMessage(0x4cc7);
- inventory->add(54);
+ displayMessage(dsAddr_fullAutomaticMsg); // "Fully Automatic"
+ inventory->add(kInvItemVideoTape);
disableObject(4);
- return true;
+ break;
- case 0x6849: {
- Common::Point p = scene->getPosition();
- if (p.x == 208 && p.y == 151) {
- moveRel(0, 0, 2);
- } else
- moveTo(208, 151, 1);
- }
- return true;
+ case csAddr_egoBottomRightTurn:
+ fnEgoBottomRightTurn();
+ break;
- case 0x687a: //using the book
- if (CHECK_FLAG(0xDBC2, 1)) {
- displayMessage(0x4ca0);
+ case 0x687a: // using the book
+ if (CHECK_FLAG(dsAddr_drawerPuzzleSolvedFlag, 1)) {
+ displayMessage(dsAddr_dontMessMsg); // "I don't need to mess with it anymore"
} else {
playSound(49, 5);
playSound(49, 17);
playActorAnimation(691);
- if (!processCallback(0x68e6)) {
- if (!CHECK_FLAG(0xDBC0, 1)) {
- displayMessage(0x4c61);
- SET_FLAG(0xDBC0, 1);
+ if (!fnCheckingDrawers()) {
+ if (!CHECK_FLAG(dsAddr_drawerPuzzleBookMessageFlag, 1)) {
+ displayMessage(dsAddr_bookHeldMsg); // "Something's got hold of the book!"
+ SET_FLAG(dsAddr_drawerPuzzleBookMessageFlag, 1);
}
} else {
- playSound(15, 8); //secret compartment
+ playSound(15, 8); // secret compartment
playAnimation(692, 0);
setOns(6, 59);
enableObject(4);
- displayMessage(0x4c84);
- SET_FLAG(0xDBC2, 1);
+ displayMessage(dsAddr_secretCompartmentMsg); // "Wow! A secret compartment!"
+ SET_FLAG(dsAddr_drawerPuzzleSolvedFlag, 1);
}
}
- return true;
+ break;
- case 0x68e6: { //checking drawers
- uint16 v = GET_FLAG(0xDBC1) - 1;
- uint bx = 0xDBB7;
- if (GET_FLAG(bx + v) != 1)
- return false;
-
- uint16 sum = 0;
- for (uint i = 0; i < 6; ++i) {
- sum += GET_FLAG(bx + i);
- }
- return sum == 1;
- }
+ case csAddr_checkingDrawers:
+ fnCheckingDrawers();
+ break;
case 0x6918:
- if (inventory->has(55)) {
- displayMessage(0x4cd9);
- return true;
- }
- if (!CHECK_FLAG(0xDBC3, 1)) {
- playActorAnimation(695);
- Dialog::showMark(scene, 0x386a);
- SET_FLAG(0xDBC3, 1);
- }
+ if (inventory->has(kInvItemSheetOfPaper))
+ displayMessage(dsAddr_noMoreSheetsMsg); // "Right now I don't need any more sheets"
+ else {
+ if (!CHECK_FLAG(dsAddr_mansionTrashcanSearchedFlag, 1)) {
+ playActorAnimation(695);
+ dialog->showMark(91, scene);
+ SET_FLAG(dsAddr_mansionTrashcanSearchedFlag, 1);
+ }
- playSound(5, 11);
- playActorAnimation(696);
- inventory->add(55);
- return true;
+ playSound(5, 11);
+ playActorAnimation(696);
+ inventory->add(kInvItemSheetOfPaper);
+ }
+ break;
case 0x6962:
- if (CHECK_FLAG(0xDBB7, 1)) {
+ if (CHECK_FLAG(dsAddr_blueDrawerOpenFlag, 1)) {
setOns(0, 0);
playSound(67, 4);
playActorAnimation(678);
- SET_FLAG(0xDBB7, 0);
- } else if (CHECK_FLAG(0xDBB8, 1)) {
- processCallback(0x6b86);
+ SET_FLAG(dsAddr_blueDrawerOpenFlag, 0);
+ } else if (CHECK_FLAG(dsAddr_redDrawerOpenFlag, 1)) {
+ fnDrawerOpenMessage();
} else {
playSound(66, 4);
playActorAnimation(677);
setOns(0, 53);
- SET_FLAG(0xDBB7, 1);
+ SET_FLAG(dsAddr_blueDrawerOpenFlag, 1);
}
- return true;
+ break;
case 0x69b8:
- if (CHECK_FLAG(0xDBB8, 1)) {
+ if (CHECK_FLAG(dsAddr_redDrawerOpenFlag, 1)) {
setOns(1, 0);
playSound(67, 4);
playActorAnimation(680);
- SET_FLAG(0xDBB8, 0);
- } else if (CHECK_FLAG(0xDBB7, 1)) {
- processCallback(0x6b86);
- } else if (CHECK_FLAG(0xDBB9, 1)) {
- processCallback(0x6b86);
+ SET_FLAG(dsAddr_redDrawerOpenFlag, 0);
+ } else if (CHECK_FLAG(dsAddr_blueDrawerOpenFlag, 1)) {
+ fnDrawerOpenMessage();
+ } else if (CHECK_FLAG(dsAddr_greyDrawerOpenFlag, 1)) {
+ fnDrawerOpenMessage();
} else {
playSound(66, 5);
playActorAnimation(679);
setOns(1, 54);
- SET_FLAG(0xDBB8, 1);
+ SET_FLAG(dsAddr_redDrawerOpenFlag, 1);
}
- return true;
+ break;
case 0x6a1b:
- if (CHECK_FLAG(0xDBB9, 1)) {
+ if (CHECK_FLAG(dsAddr_greyDrawerOpenFlag, 1)) {
setOns(2, 0);
playSound(67, 5);
playActorAnimation(682);
- SET_FLAG(0xDBB9, 0);
- } else if (CHECK_FLAG(0xDBB8, 1)) {
- processCallback(0x6b86);
+ SET_FLAG(dsAddr_greyDrawerOpenFlag, 0);
+ } else if (CHECK_FLAG(dsAddr_redDrawerOpenFlag, 1)) {
+ fnDrawerOpenMessage();
} else {
playSound(67, 5);
playActorAnimation(681);
setOns(2, 55);
- SET_FLAG(0xDBB9, 1);
+ SET_FLAG(dsAddr_greyDrawerOpenFlag, 1);
}
- return true;
+ break;
case 0x6a73:
- if (CHECK_FLAG(0xDBBA, 1)) {
+ if (CHECK_FLAG(dsAddr_greenDrawerOpenFlag, 1)) {
setOns(3, 0);
playSound(67, 4);
playActorAnimation(684);
- SET_FLAG(0xDBBA, 0);
- } else if (!CHECK_FLAG(0xDBBB, 1)) {
+ SET_FLAG(dsAddr_greenDrawerOpenFlag, 0);
+ } else if (!CHECK_FLAG(dsAddr_brownDrawerOpenFlag, 1)) {
playSound(66, 4);
playActorAnimation(683);
setOns(3, 56);
- SET_FLAG(0xDBBA, 1);
+ SET_FLAG(dsAddr_greenDrawerOpenFlag, 1);
} else
- processCallback(0x6b86);
- return true;
+ fnDrawerOpenMessage();
+ break;
case 0x6acb:
- if (CHECK_FLAG(0xDBBB, 1)) {
+ if (CHECK_FLAG(dsAddr_brownDrawerOpenFlag, 1)) {
setOns(4, 0);
playSound(67, 4);
playActorAnimation(686);
- SET_FLAG(0xDBBB, 0);
- } else if (CHECK_FLAG(0xDBBA, 1)) {
- processCallback(0x6b86);
- } else if (CHECK_FLAG(0xDBBC, 1)) {
- processCallback(0x6b86);
+ SET_FLAG(dsAddr_brownDrawerOpenFlag, 0);
+ } else if (CHECK_FLAG(dsAddr_greenDrawerOpenFlag, 1)) {
+ fnDrawerOpenMessage();
+ } else if (CHECK_FLAG(dsAddr_pinkDrawerOpenFlag, 1)) {
+ fnDrawerOpenMessage();
} else {
playSound(66, 5);
playActorAnimation(685);
setOns(4, 57);
- SET_FLAG(0xDBBB, 1);
+ SET_FLAG(dsAddr_brownDrawerOpenFlag, 1);
}
- return true;
+ break;
case 0x6b2e:
- if (CHECK_FLAG(0xdbbc, 1)) {
+ if (CHECK_FLAG(dsAddr_pinkDrawerOpenFlag, 1)) {
setOns(5, 0);
playSound(67, 5);
playActorAnimation(688);
- SET_FLAG(0xdbbc, 0);
- } else if (CHECK_FLAG(0xdbbb, 1)) {
- processCallback(0x6b86);
+ SET_FLAG(dsAddr_pinkDrawerOpenFlag, 0);
+ } else if (CHECK_FLAG(dsAddr_brownDrawerOpenFlag, 1)) {
+ fnDrawerOpenMessage();
} else {
playSound(66, 6);
playActorAnimation(687);
setOns(5, 58);
- SET_FLAG(0xDBBC, 1);
+ SET_FLAG(dsAddr_pinkDrawerOpenFlag, 1);
}
- return true;
-
+ break;
- case 0x6b86:
- if (CHECK_FLAG(0xDBBD, 1)) {
- displayMessage(0x4b39);
- } else {
- displayMessage(0x4acd);
- displayMessage(0x4b0d);
- SET_FLAG(0xDBBD, 1);
- }
- return true;
+ case csAddr_DrawerOpenMessage:
+ fnDrawerOpenMessage();
+ break;
- case 0x6be1: //handle to the bathroom
- if (CHECK_FLAG(0xDBD9, 1)) {
- displayMessage(0x5326); //i'd better catch johnny
- } else {
+ case 0x6be1: // handle to the bathroom
+ if (CHECK_FLAG(dsAddr_MansionJohnNotyEscapingFlag, 1))
+ displayMessage(dsAddr_catchJohnFirstMsg); // "I'd better catch John Noty first"
+ else {
playSound(88, 4);
playActorAnimation(808);
loadScene(36, 41, 195, 2);
}
- return true;
+ break;
case 0x6bad:
playSound(80, 4);
playActorAnimation(971);
loadScene(32, 139, 199, 1);
- return true;
+ break;
case 0x6c45:
playSound(89, 6);
- playActorAnimation(CHECK_FLAG(0xDBEF, 1) ? 985 : 806);
+ playActorAnimation(CHECK_FLAG(dsAddr_mansionHandleInDoorHoleFlag, 1) ? 985 : 806);
loadScene(34, 40, 133, 2);
- return true;
+ break;
case 0x6c83:
waitLanAnimationFrame(1, 1);
- Dialog::pop(scene, 0xdb2e, 0, 727, 0xd1, 0xef, 0, 1);
- scene->getObject(1)->setName((const char *)res->dseg.ptr(0xaa94));
- SET_FLAG(0xDBD1, 1);
- return true;
+ dialog->pop(scene, dsAddr_dialogStackRobotSafe, 0, 727, textColorMark, textColorMike, 0, 1);
+ scene->getObject(1)->setName((const char *)res->dseg.ptr(dsAddr_scnObjNameMike));
+ SET_FLAG(dsAddr_MansionRobotSafeUnlockedFlag, 1);
+ break;
- case 0x6c9d: //getting jar
+ case 0x6c9d: // getting jar
setOns(0, 71);
playSound(32, 5);
playActorAnimation(732);
disableObject(2);
- inventory->add(72);
- return true;
+ inventory->add(kInvItemTimePills);
+ break;
- case 0x6cc4: //secret diary
+ case 0x6cc4: // secret diary
playActorAnimation(754);
hideActor();
- displayCutsceneMessage(0x517b, 30430);
+ displayCutsceneMessage(dsAddr_cutsceneMsg0, 30, 95); // "A secret diary of ..."
playMusic(3);
loadScene(11, scene->getPosition());
playAnimation(750, 2);
- Dialog::show(scene, 0x4f50, 751, 529, 0xe5, 0xd9, 2, 1);
+ dialog->show(117, scene, 751, 529, textColorProfessor, textColorMansionGuard, 2, 1);
playAnimation(752, 0, true);
playAnimation(753, 1, true);
waitAnimation();
- Dialog::show(scene, 0x5168, 529, 751, 0xd9, 0xe5, 1, 2);
+ dialog->show(118, scene, 529, 751, textColorMansionGuard, textColorProfessor, 1, 2);
loadScene(30, scene->getPosition());
- Dialog::show(scene, 0x449e, 733, 734, 0xe5, 0xd0, 2, 3);
+ dialog->show(108, scene, 733, 734, textColorProfessor, textColorJohnNoty, 2, 3);
playSound(75, 13);
playSound(32, 22);
playAnimation(735, 1, true);
playAnimation(736, 2, true);
waitAnimation();
- Dialog::show(scene, 0x46cf, 737, 738, 0xd0, 0xe5, 3, 2);
-
+ dialog->show(109, scene, 737, 738, textColorJohnNoty, textColorProfessor, 3, 2);
playSound(32, 1);
playAnimation(739, 1, true);
playAnimation(740, 2, true);
waitAnimation();
- Dialog::show(scene, 0x4772, 733, 734, 0xe5, 0xd0, 2, 3);
+ dialog->show(110, scene, 733, 734, textColorProfessor, textColorJohnNoty, 2, 3);
playAnimation(742, 1, true);
playAnimation(741, 2, true);
waitAnimation();
- Dialog::show(scene, 0x481c, 743, 733, 0xd0, 0xe5, 3, 2); //where's my wallet??
+ dialog->show(111, scene, 743, 733, textColorJohnNoty, textColorProfessor, 3, 2);
playAnimation(744, 1, true);
playAnimation(745, 2, true);
waitAnimation();
- Dialog::show(scene, 0x4873, 734, 733, 0xd0, 0xe5, 3, 2);
+ dialog->show(112, scene, 734, 733, textColorJohnNoty, textColorProfessor, 3, 2);
playAnimation(746, 1, true);
playAnimation(747, 2, true);
waitAnimation();
-
- Dialog::show(scene, 0x4da5, 734, 734, 0xd0, 0xd0, 3, 3);
- Dialog::show(scene, 0x4eb9, 748, 748, 0xd0, 0xd0, 3, 3);
- Dialog::show(scene, 0x4f15, 749, 749, 0xd0, 0xd0, 3, 3);
- Dialog::show(scene, 0x4f2f, 748, 748, 0xd0, 0xd0, 3, 3);
+ dialog->show(113, scene, 734, 734, textColorJohnNoty, textColorJohnNoty, 3, 3);
+ dialog->show(114, scene, 748, 748, textColorJohnNoty, textColorJohnNoty, 3, 3);
+ dialog->show(115, scene, 749, 749, textColorJohnNoty, textColorJohnNoty, 3, 3);
+ dialog->show(116, scene, 748, 748, textColorJohnNoty, textColorJohnNoty, 3, 3);
playMusic(10);
loadScene(32, scene->getPosition());
@@ -3296,35 +4168,34 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playActorAnimation(755);
moveRel(0, 0, 3);
- Dialog::show(scene, 0x51bf, 0, 0, 0xd1, 0xd1, 0, 0);
+ dialog->showMark(119, scene);
hideActor();
loadScene(31, scene->getPosition());
- Dialog::show(scene, 0x539f, 763, 764, 0xd9, 0xd0, 1, 2);
+ dialog->show(123, scene, 763, 764, textColorMansionGuard, textColorJohnNoty, 1, 2);
loadScene(32, scene->getPosition());
showActor();
- Dialog::show(scene, 0x52c3, 0, 0, 0xd1, 0xd1, 0, 0); //i have to hide somewhere
+ dialog->showMark(120, scene);
disableObject(3);
enableObject(7);
- SET_FLAG(0xDBD5, 1);
- return true;
+ SET_FLAG(dsAddr_MansionJohnNotyOutsideBathroomFlag, 1);
+ break;
case 0x6f20:
- if (CHECK_FLAG(0xDBD5, 1)) {
- displayMessage(0x51a7);
- } else {
+ if (CHECK_FLAG(dsAddr_MansionJohnNotyOutsideBathroomFlag, 1))
+ displayMessage(dsAddr_cantHideMsg); // "I can't hide here!"
+ else
rejectMessage();
- }
- return true;
+ break;
- case 0x6f75: //hiding in left corner
+ case 0x6f75: // hiding in left corner
moveRel(0, 0, 3);
playActorAnimation(756);
hideActor();
playAnimation(758, 1);
- Dialog::show(scene, 0x52e6, 759, 759, 0xd0, 0xd0, 2, 2); //I have to buy...
+ dialog->show(121, scene, 759, 759, textColorJohnNoty, textColorJohnNoty, 2, 2);
playSound(40, 5);
playSound(52, 13);
@@ -3340,272 +4211,265 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playSound(58, 12);
playSound(58, 14);
playAnimation(765, 1);
- Dialog::show(scene, 0x5443, 766, 766, 0xd9, 0xd9, 1, 1);
+ dialog->show(124, scene, 766, 766, textColorMansionGuard, textColorMansionGuard, 1, 1);
loadScene(32, scene->getPosition());
- Dialog::show(scene, 0x5358, 761, 761, 0xd0, 0xd0, 2, 2);
+ dialog->show(122, scene, 761, 761, textColorJohnNoty, textColorJohnNoty, 2, 2);
playAnimation(762, 1);
setOns(2, 0);
showActor();
playActorAnimation(757);
moveRel(0, 0, 1);
- displayMessage(0x51e7);
+ displayMessage(dsAddr_wasCloseMsg); // "That was close"
enableObject(8);
disableObject(7);
- SET_FLAG(0xDBD5, 0);
- return true;
+ SET_FLAG(dsAddr_MansionJohnNotyOutsideBathroomFlag, 0);
+ break;
case 0x6f4d:
- if (CHECK_FLAG(0xDBD5, 1)) {
- displayMessage(0x51bb);
- } else {
+ if (CHECK_FLAG(dsAddr_MansionJohnNotyOutsideBathroomFlag, 1))
+ displayMessage(dsAddr_johnOutsideMsg); // "There's John Noty outside! I can't go out!"
+ else
loadScene(31, 139, 172, 3);
- }
- return true;
+ break;
case 0x6f32:
- if (CHECK_FLAG(0xDBD5, 1)) {
- displayMessage(0x51a7);
+ if (CHECK_FLAG(dsAddr_MansionJohnNotyOutsideBathroomFlag, 1)) {
+ displayMessage(dsAddr_cantHideMsg); // "I can't hide here!"
} else {
playActorAnimation(977);
- displayMessage(0x5511);
+ displayMessage(dsAddr_lockedMsg); // "It's Locked!"
}
- return true;
+ break;
case 0x7096:
playSound(32, 5);
playActorAnimation(767);
setOns(1, 0);
- inventory->add(73);
+ inventory->add(kInvItemHandle);
disableObject(8);
- return true;
+ break;
+
+ case 0x7218:
+ rejectMessage();
+ break;
case 0x7291:
playSound(89, 3);
playActorAnimation(975);
loadScene(31, 298, 177, 4);
- return true;
+ break;
case 0x72c2:
- if (CHECK_FLAG(0xDBD6, 2)) {
- displayMessage(0x522c);
+ if (CHECK_FLAG(dsAddr_MansionSinkState, 2)) {
+ displayMessage(dsAddr_enoughWaterMsg); // "There's enough water in the sink"
} else {
playSound(79, 6);
playSound(84, 9);
playActorAnimation(801);
wait(50);
- if (CHECK_FLAG(0xDBD6, 1)) {
- displayMessage(0x538d);
- SET_FLAG(0xDBD6, 2);
+ if (CHECK_FLAG(dsAddr_MansionSinkState, 1)) {
+ displayMessage(dsAddr_sinkFullMsg); // "The sink is full of hot water"
+ SET_FLAG(dsAddr_MansionSinkState, 2);
} else
- displayMessage(0x5372);
+ displayMessage(dsAddr_waterHotMsg); // "The water looks very hot"
}
- return true;
+ break;
case 0x7309:
playSound(66, 5);
playSound(67, 11);
playActorAnimation(976);
- displayMessage(0x5955);
- return true;
+ displayMessage(dsAddr_emptyMsg); // "It's Empty"
+ break;
case 0x77d5:
- if (CHECK_FLAG(0xdbd7, 1) && !CHECK_FLAG(0xdbd8, 1)) { //disallow exiting through the first door until switch turned on, not present in original game
- displayMessage(0x52cb);
- return true;
+ if (CHECK_FLAG(dsAddr_MansionThruFanByTimePillFlag, 1) && !CHECK_FLAG(dsAddr_MansionVentFanStoppedFlag, 1)) { // disallow exiting through the first door until switch turned on, not present in original game
+ displayMessage(dsAddr_noSaladMsg); // "I don't want to turn myself into a salad"
+ } else {
+ playSound(89, 6);
+ playActorAnimation(978);
+ loadScene(31, 298, 177, 4);
}
- playSound(89, 6);
- playActorAnimation(978);
- loadScene(31, 298, 177, 4);
- return true;
+ break;
case 0x79e4:
- processCallback(0x6849);
- return false;
+ fnEgoBottomRightTurn();
+ retVal = false;
+ break;
- case 0x79eb: //color of the book
- displayMessage(res->dseg.get_word(0x5f3c + GET_FLAG(0xDBC1) * 2 - 2));
- return true;
+ case 0x79eb: // color of the book
+ // FIXME - Replace with internal lookup and switch
+ displayMessage(res->dseg.get_word(dsAddr_bookColorMsgPtr + GET_FLAG(dsAddr_drawerPuzzleBookValue) * 2 - 2));
+ break;
case 0x79fd:
- if (CHECK_FLAG(0xDBB7, 1)) {
- displayMessage(0x4b6c);
- return true;
- } else
- return false;
+ if (CHECK_FLAG(dsAddr_blueDrawerOpenFlag, 1))
+ displayMessage(dsAddr_blueInteriorMsg); // "It's got a blue interior"
+ else
+ retVal = false;
+ break;
case 0x7a0f:
- if (CHECK_FLAG(0xDBB8, 1)) {
- if (!CHECK_FLAG(0xDBBF, 1)) {
- displayMessage(0x4c32);
+ if (CHECK_FLAG(dsAddr_redDrawerOpenFlag, 1)) {
+ if (!CHECK_FLAG(dsAddr_drawerGotPolaroidFlag, 1)) {
+ displayMessage(dsAddr_foundPolaroidMsg); // "There's a polaroid inside! I might need that"
playSound(5, 11);
playActorAnimation(690);
- inventory->add(53);
- SET_FLAG(0xDBBF, 1);
+ inventory->add(kInvItemPolaroidCamera);
+ SET_FLAG(dsAddr_drawerGotPolaroidFlag, 1);
}
- displayMessage(0x4b87);
- return true;
+ displayMessage(dsAddr_redInteriorMsg); // "It's got a red interior"
} else
- return false;
+ retVal = false;
+ break;
case 0x7a49:
- if (CHECK_FLAG(0xDBB9, 1)) {
- displayMessage(0x4ba1);
- return true;
- } else
- return false;
+ if (CHECK_FLAG(dsAddr_greyDrawerOpenFlag, 1))
+ displayMessage(dsAddr_greyInteriorMsg); // "It's got a grey interior"
+ else
+ retVal = false;
+ break;
case 0x7a5b:
- if (CHECK_FLAG(0xDBBA, 1)) {
- displayMessage(0x4bbc);
- return true;
- } else
- return false;
+ if (CHECK_FLAG(dsAddr_greenDrawerOpenFlag, 1))
+ displayMessage(dsAddr_greenInteriorMsg); // "It's got a green interior"
+ else
+ retVal = false;
+ break;
case 0x7a6d:
- if (CHECK_FLAG(0xDBBB, 1)) {
- displayMessage(0x4bd8);
- return true;
- } else
- return false;
+ if (CHECK_FLAG(dsAddr_brownDrawerOpenFlag, 1))
+ displayMessage(dsAddr_brownInteriorMsg); // "It's got a brown interior"
+ else
+ retVal = false;
+ break;
case 0x7a7f:
- if (CHECK_FLAG(0xDBBC, 1)) {
- if (!CHECK_FLAG(0xDBBE, 1)) {
- displayMessage(0x4c0f); //there's dictaphone inside!
+ if (CHECK_FLAG(dsAddr_pinkDrawerOpenFlag, 1)) {
+ if (!CHECK_FLAG(dsAddr_drawerGotDictaphoneFlag, 1)) {
+ displayMessage(dsAddr_dictaphoneInsideMsg); // "Wow! There's a dictaphone inside!"
playSound(5, 12);
playActorAnimation(689);
- inventory->add(52);
- SET_FLAG(0xDBBE, 1);
+ inventory->add(kInvItemDictaphoneNoBatteries);
+ SET_FLAG(dsAddr_drawerGotDictaphoneFlag, 1);
}
- displayMessage(0x4bf4);
- return true;
+ displayMessage(dsAddr_pinkInteriorMsg); // "It's got a pink interior"
} else
- return false;
+ retVal = false;
+ break;
case 0x7af7:
- if (CHECK_FLAG(0xDBD0, 1)) {
- displayMessage(0x5082);
- return true;
- } else
- return false;
-
- case 0x7b09: {
- byte v = GET_FLAG(0xDBD6);
- switch (v) {
- case 1:
- displayMessage(0x51f8);
- return true;
- case 2:
- displayMessage(0x538d);
- return true;
- default:
- return false;
- }
- }
+ if (CHECK_FLAG(dsAddr_MansionPutBurningPaperInFridgeFlag, 1))
+ displayMessage(dsAddr_yummyMsg); // "Yummy"
+ else
+ retVal = false;
+ break;
- case 0x9166:
- if (CHECK_FLAG(0xDBD1, 1)) {
- return true;
- } else {
- displayMessage(0x50a6);
- return false;
+ case 0x7b09:
+ {
+ byte v = GET_FLAG(dsAddr_MansionSinkState);
+ switch (v) {
+ case 1:
+ displayMessage(dsAddr_corkInHoleMsg); // "The cork is stuck in the hole"
+ break;
+ case 2:
+ displayMessage(dsAddr_sinkFullMsg); // "The sink is full of hot water"
+ break;
+ default:
+ retVal = false;
+ break;
+ }
}
+ break;
- case 0x9175:
- if (CHECK_FLAG(0xDBD2, 0) || CHECK_FLAG(0xDBD3, 0) || CHECK_FLAG(0xDBD4, 0))
- return true;
+ case csAddr_robotSafeAlreadyUnlockedCheck:
+ fnRobotSafeAlreadyUnlockedCheck();
+ break;
- waitLanAnimationFrame(1, 1);
- playSound(89, 2);
- playActorAnimation(731);
- setOns(0, 70);
- setLan(1, 0);
- disableObject(1);
- enableObject(2);
- enableObject(3);
- return true;
+ case csAddr_robotSafeUnlockCheck:
+ fnRobotSafeUnlockCheck();
+ break;
- case 0x90bc: //handle on the hole
+ case 0x90bc: // handle on the hole
playSound(5, 3);
playSound(6, 9);
playActorAnimation(807);
setOns(0, 83);
- inventory->remove(73);
+ inventory->remove(kInvItemHandle);
disableObject(2);
enableObject(3);
- SET_FLAG(0xDBEF, 1);
- return true;
-
- case 0x90fc: //dictaphone on robot
- if (!processCallback(0x9166))
- return true;
-
- if (CHECK_FLAG(0xDBD2, 1)) {
- displayMessage(0x50c3);
- return true;
- }
+ SET_FLAG(dsAddr_mansionHandleInDoorHoleFlag, 1);
+ break;
- if (!CHECK_FLAG(0xDBCB, 1)) {
- displayMessage(0x5101);
- return true;
+ case 0x90fc: // dictaphone on robot
+ if (fnRobotSafeAlreadyUnlockedCheck()) {
+ if (CHECK_FLAG(dsAddr_MansionRobotSafeVoiceTestPassedFlag, 1)) {
+ displayMessage(dsAddr_fooledOnceMsg); // "I'd already fooled him once"
+ } else {
+ if (!CHECK_FLAG(dsAddr_usedDictaphoneOnTVFlag, 1)) {
+ displayMessage(dsAddr_notMyVoiceMsg); // "I won't cheat Mike with MY voice"
+ } else {
+ displayMessage(dsAddr_mikeVoiceTestMsg); // "Mike, activate the voice test"
+ waitLanAnimationFrame(1, 1);
+
+ playSound(5, 3);
+ playSound(5, 39);
+ displayAsyncMessage(dsAddr_singingMsg, 68, 126, 9, 35, textColorJohnNoty); // "siiiiinging!"
+ playActorAnimation(728);
+
+ waitLanAnimationFrame(1, 1);
+ dialog->show(98, scene, 0, 727, textColorMark, textColorMike, 0, 1);
+ SET_FLAG(dsAddr_MansionRobotSafeVoiceTestPassedFlag, 1);
+ fnRobotSafeUnlockCheck();
+ }
+ }
}
+ break;
- displayMessage(0x50e1);
- waitLanAnimationFrame(1, 1);
-
- playSound(5, 3);
- playSound(5, 39);
- displayAsyncMessage(0x5124, 40388, 9, 35, 0xd0);
- playActorAnimation(728);
-
- waitLanAnimationFrame(1, 1);
- Dialog::show(scene, 0x3d17, 0, 727, 0xd1, 0xef, 0, 1);
- SET_FLAG(0xDBD2, 1);
- processCallback(0x9175);
- return true;
+ case 0x91cb: // use socks on robot
+ if (fnRobotSafeAlreadyUnlockedCheck()) {
+ if (CHECK_FLAG(dsAddr_MansionRobotSafeScentTestPassedFlag, 1)) {
+ displayMessage(dsAddr_fooledOnceMsg); // "I'd already fooled him once"
+ } else {
+ displayMessage(dsAddr_mikeScentTestMsg); // "Mike, let's get on with the scent test"
- case 0x91cb: //use socks on robot
- if (!processCallback(0x9166))
- return true;
+ waitLanAnimationFrame(1, 1);
+ playSound(5, 3);
+ playSound(5, 23);
+ playActorAnimation(729);
- if (CHECK_FLAG(0xDBD3, 1)) {
- displayMessage(0x50c3);
- return true;
+ waitLanAnimationFrame(1, 1);
+ dialog->show(99, scene, 0, 727, textColorMark, textColorMike, 0, 1);
+ SET_FLAG(dsAddr_MansionRobotSafeScentTestPassedFlag, 1);
+ fnRobotSafeUnlockCheck();
+ }
}
- displayMessage(0x5138);
-
- waitLanAnimationFrame(1, 1);
- playSound(5, 3);
- playSound(5, 23);
- playActorAnimation(729);
+ break;
- waitLanAnimationFrame(1, 1);
- Dialog::show(scene, 0x3d70, 0, 727, 0xd1, 0xef, 0, 1);
- SET_FLAG(0xDBD3, 1);
- processCallback(0x9175);
- return true;
+ case 0x9209: // photo on robot
+ if (fnRobotSafeAlreadyUnlockedCheck()) {
+ if (CHECK_FLAG(dsAddr_MansionRobotSafeViewTestPassedFlag, 1)) {
+ displayMessage(dsAddr_fooledOnceMsg); // "I'd already fooled him once"
+ } else {
+ displayMessage(dsAddr_mikeViewTestMsg); // "Mike, run the view test"
+ waitLanAnimationFrame(1, 1);
- case 0x9209: //photo on robot
- if (!processCallback(0x9166))
- return true;
+ playSound(5, 3);
+ playSound(5, 25);
+ playActorAnimation(730);
- if (CHECK_FLAG(0xDBD4, 1)) {
- displayMessage(0x50c3);
- return true;
+ waitLanAnimationFrame(1, 1);
+ dialog->show(100, scene, 0, 727, textColorMark, textColorMike, 0, 1);
+ SET_FLAG(dsAddr_MansionRobotSafeViewTestPassedFlag, 1);
+ fnRobotSafeUnlockCheck();
+ }
}
- displayMessage(0x5161);
- waitLanAnimationFrame(1, 1);
-
- playSound(5, 3);
- playSound(5, 25);
- playActorAnimation(730);
+ break;
- waitLanAnimationFrame(1, 1);
- Dialog::show(scene, 0x3dd6, 0, 727, 0xd1, 0xef, 0, 1);
- SET_FLAG(0xDBD4, 1);
- processCallback(0x9175);
- return true;
+ case 0x9247:
+ displayMessage(dsAddr_sameBottleMsg); // "The bottle's the same, but I doubt if it's enough to fool anyone"
+ break;
case 0x924e:
setOns(2, 64);
@@ -3613,9 +4477,9 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playSound(52, 10);
playActorAnimation(711);
moveRel(0, 0, 4);
- Dialog::show(scene, 0x3b21, 0, 709, 0xd1, 0xef, 0, 1);
+ dialog->show(95, scene, 0, 709, textColorMark, textColorCook, 0, 1);
moveTo(300, 190, 4);
- inventory->remove(64);
+ inventory->remove(kInvItemFakeChilli);
disableObject(8);
playAnimation(712, 0);
setOns(2, 0);
@@ -3623,90 +4487,90 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playSound(15, 28);
playSound(16, 37);
playAnimation(713, 0);
- Dialog::show(scene, 0x3c0d, 0, 709, 0xd1, 0xef, 0, 1);
+ dialog->show(96, scene, 0, 709, textColorMark, textColorCook, 0, 1);
playSound(85, 2);
playAnimation(714, 0);
setLan(1, 0);
disableObject(1);
{
Object *obj = scene->getObject(2);
- obj->actor_rect.left = obj->actor_rect.right = 81;
- obj->actor_rect.top = obj->actor_rect.bottom = 160;
- obj->actor_orientation = 4;
+ obj->actorRect.left = obj->actorRect.right = 81;
+ obj->actorRect.top = obj->actorRect.bottom = 160;
+ obj->actorOrientation = 4;
obj->save();
}
{
Object *obj = scene->getObject(3);
- obj->actor_rect.left = obj->actor_rect.right = 64;
- obj->actor_rect.top = obj->actor_rect.bottom = 168;
- obj->actor_orientation = 4;
+ obj->actorRect.left = obj->actorRect.right = 64;
+ obj->actorRect.top = obj->actorRect.bottom = 168;
+ obj->actorOrientation = 4;
obj->save();
}
{
Object *obj = scene->getObject(10);
- obj->actor_rect.left = obj->actor_rect.right = 105;
- obj->actor_rect.top = obj->actor_rect.bottom = 160;
- obj->actor_orientation = 1;
+ obj->actorRect.left = obj->actorRect.right = 105;
+ obj->actorRect.top = obj->actorRect.bottom = 160;
+ obj->actorOrientation = 1;
obj->save();
}
- SET_FLAG(0xDBCC, 1);
- return true;
+ SET_FLAG(dsAddr_MansionCookGoneFlag, 1);
+ break;
case 0x9472:
playSound(5, 4);
playSound(19, 14);
playActorAnimation(793);
- displayMessage(0x5218);
- inventory->remove(60);
- SET_FLAG(0xDBD6, 1);
- return true;
+ displayMessage(dsAddr_fitsPerfectMsg); // "It fits perfectly!"
+ inventory->remove(kInvItemWrappedCork);
+ SET_FLAG(dsAddr_MansionSinkState, 1);
+ break;
- case 0x9449: //meat + stew
+ case 0x9449: // meat + stew
playSound(5, 4);
playSound(63, 12);
playActorAnimation(726);
- displayMessage(0x508a);
- inventory->remove(69);
- inventory->add(70);
- return true;
+ displayMessage(dsAddr_dislikeVealMsg); // "I never liked veal anyway"
+ inventory->remove(kInvItemMeat);
+ inventory->add(kInvItemPlasticBag);
+ break;
case 0x949b:
- if (CHECK_FLAG(0xDBD6, 2)) {
+ if (CHECK_FLAG(dsAddr_MansionSinkState, 2)) {
playSound(5, 4);
playSound(5, 25);
playActorAnimation(802);
- displayMessage(0x5272);
- inventory->remove(62);
- inventory->add(74);
- inventory->add(65);
+ displayMessage(dsAddr_labelOffMsg); // "The label has come off!"
+ inventory->remove(kInvItemChilliWithLabel);
+ inventory->add(kInvItemChilliNoLabel);
+ inventory->add(kInvItemLabel);
} else
- displayMessage(0x524f);
- return true;
+ displayMessage(dsAddr_noHotWaterMsg); // "There's no hot water in the sink"
+ break;
case 0x94d4:
- if (inventory->has(70)) {
+ if (inventory->has(kInvItemPlasticBag)) {
setOns(0, 0);
playSound(5, 3);
playSound(5, 18);
playSound(13, 12);
playActorAnimation(803);
disableObject(7);
- inventory->remove(70);
- inventory->add(71);
+ inventory->remove(kInvItemPlasticBag);
+ inventory->add(kInvItemSocks);
} else
- displayMessage(0x53ad);
- return true;
+ displayMessage(dsAddr_noSockStoreMsg); // "I don't have anything to store these socks in"
+ break;
case 0x951b:
playSound(5, 4);
playSound(5, 22);
playActorAnimation(804);
- displayMessage(0x528b);
- return true;
+ displayMessage(dsAddr_corkTooSmallMsg); // "The cork is a bit too small"
+ break;
case 0x73a3:
- if (CHECK_FLAG(0xdbc5, 1)) {
- SET_FLAG(0xdbc5, 0);
+ if (CHECK_FLAG(dsAddr_mansionTVOnFlag, 1)) {
+ SET_FLAG(dsAddr_mansionTVOnFlag, 0);
//call 73e6
playSound(71, 3);
@@ -3714,92 +4578,94 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playAnimation(0, 0, true);
reloadLan();
- if (CHECK_FLAG(0xDBC6, 1)) {
- displayMessage(0x4da6);
+ if (CHECK_FLAG(dsAddr_mansionVCRPlayingTapeFlag, 1)) {
+ displayMessage(dsAddr_muchBetterMsg); // "That's much better"
}
} else {
- SET_FLAG(0xdbc5, 1);
+ SET_FLAG(dsAddr_mansionTVOnFlag, 1);
//call 73e6
playSound(71, 3);
playActorAnimation(700);
reloadLan();
}
- return true;
+ break;
- case 0x9537: //using remote on VCR
+ case 0x9537: // using remote on VCR
playSound(5, 3);
playSound(5, 16);
playActorAnimation(703);
- if (!CHECK_FLAG(0xDBC8, 1)) {
- displayMessage(0x4D80); //nothing happened
- return true;
- }
-
- //0x955a
- if (CHECK_FLAG(0xDBC6, 0)) {
- if (CHECK_FLAG(0xDBC5, 1)) { //tv on
- if (!CHECK_FLAG(0xDBC7, 1))
- displayMessage(0x4d93); //the tape started
-
- SET_FLAG(0xDBC6, 1);
- reloadLan();
- if (!CHECK_FLAG(0xDBC7, 1)) {
- Dialog::show(scene, 0x392c, 0, 702, 0xd1, 0xd0, 0, 1);
- SET_FLAG(0xDBC7, 1);
+ if (!CHECK_FLAG(dsAddr_mansionVCRTapeLoadedFlag, 1))
+ displayMessage(dsAddr_NotHappenMsg); // "Nothing happened"
+ else {
+ //0x955a
+ if (CHECK_FLAG(dsAddr_mansionVCRPlayingTapeFlag, 0)) {
+ if (CHECK_FLAG(dsAddr_mansionTVOnFlag, 1)) {
+ if (!CHECK_FLAG(dsAddr_mansionVCRPlayedTapeBeforeFlag, 1))
+ displayMessage(dsAddr_tapeStartedMsg); // "The tape started!"
+
+ SET_FLAG(dsAddr_mansionVCRPlayingTapeFlag, 1);
+ reloadLan();
+ if (!CHECK_FLAG(dsAddr_mansionVCRPlayedTapeBeforeFlag, 1)) {
+ dialog->show(93, scene, 0, 702, textColorMark, textColorJohnNoty, 0, 1);
+ SET_FLAG(dsAddr_mansionVCRPlayedTapeBeforeFlag, 1);
+ }
+ } else
+ displayMessage(dsAddr_tvOffMsg); // "I just realised that the TV is off"
+ } else {
+ SET_FLAG(dsAddr_mansionVCRPlayingTapeFlag, 0);
+ if (CHECK_FLAG(dsAddr_mansionTVOnFlag, 1)) {
+ reloadLan();
+ displayMessage(dsAddr_muchBetterMsg); // "That's much better"
}
- } else
- displayMessage(0x4d5b); //i just realized that tv is off
- } else {
- SET_FLAG(0xDBC6, 0);
- if (CHECK_FLAG(0xDBC5, 1)) { //tv on
- reloadLan();
- displayMessage(0x4da6); //much better!
}
}
- return true;
+ break;
- case 0x95eb: //polaroid + tv
- if (CHECK_FLAG(0xDBC6, 1)) {
- if (CHECK_FLAG(0xDBCA, 1)) {
- displayMessage(0x4de6);
+ case 0x95eb: // polaroid + tv
+ if (CHECK_FLAG(dsAddr_mansionVCRPlayingTapeFlag, 1)) {
+ if (CHECK_FLAG(dsAddr_usedPolaroidOnTVFlag, 1)) {
+ displayMessage(dsAddr_enoughPhotosMsg); // "I don't need any more photos"
} else {
playSound(5, 3);
playSound(5, 24);
playSound(90, 18);
playActorAnimation(707);
- inventory->add(61);
- SET_FLAG(0xDBCA, 1);
+ inventory->add(kInvItemPhoto);
+ SET_FLAG(dsAddr_usedPolaroidOnTVFlag, 1);
}
} else
- displayMessage(0x4ea5);
- return true;
+ displayMessage(dsAddr_notRightMomentMsg); // "I don't think this is the right moment"
+ break;
- case 0x962f: //polaroid + tv
- if (CHECK_FLAG(0xDBC6, 1)) {
- if (CHECK_FLAG(0xDBCB, 1)) {
- displayMessage(0x4e32);
+ case 0x962f: // dictaphone + tv
+ if (CHECK_FLAG(dsAddr_mansionVCRPlayingTapeFlag, 1)) {
+ if (CHECK_FLAG(dsAddr_usedDictaphoneOnTVFlag, 1)) {
+ displayMessage(dsAddr_alreadyRecordedMsg); // "I already recorded what I wanted to"
} else {
- displayMessage(0x4e05);
+ displayMessage(dsAddr_recordScareMsg); // "Yeah, I can record this and scare the cats"
playSound(5, 3);
playSound(5, 27);
playActorAnimation(708);
- SET_FLAG(0xDBCB, 1);
+ SET_FLAG(dsAddr_usedDictaphoneOnTVFlag, 1);
}
} else
- displayMessage(0x4ea5);
- return true;
-
+ displayMessage(dsAddr_notRightMomentMsg); // "I don't think this is the right moment"
+ break;
case 0x95c8:
playSound(5, 3);
playSound(91, 12);
playActorAnimation(706);
- inventory->remove(54);
- SET_FLAG(0xDBC8, 1);
- return true;
+ inventory->remove(kInvItemVideoTape);
+ SET_FLAG(dsAddr_mansionVCRTapeLoadedFlag, 1);
+ break;
- case 0x9673: //hit fatso - final scene
+ case 0x966c:
+ displayMessage(dsAddr_cantRecordNoBatteriesMsg); // "I can't record anything until I find some batteries"
+ break;
+
+ case 0x9673: // hit fatso - final scene
playSound(5, 3);
playSound(24, 10);
playActorAnimation(798);
@@ -3811,12 +4677,12 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
wait(100);
playActorAnimation(805);
moveTo(50, 170, 3);
- displayMessage(0x5349);
+ displayMessage(dsAddr_onlyChilliMsg); // "Good this red stuff is only a chilli"
//moveTo(105, 157, 0, true);
playMusic(3);
loadScene(11, 105, 157, 4);
- Dialog::show(scene, 0x8409, 0, 938, 0xd1, 0xec, 0, 1);
+ dialog->show(203, scene, 0, 938, textColorMark, textColorCaptain, 0, 1);
playAnimation(939, 0, true, true);
playActorAnimation(942, true);
@@ -3837,9 +4703,9 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playActorAnimation(945, true);
waitAnimation();
- Dialog::show(scene, 0x844f, 0, 938, 0xd1, 0xec, 0, 1);
+ dialog->show(204, scene, 0, 938, textColorMark, textColorCaptain, 0, 1);
playAnimation(946, 0);
- Dialog::show(scene, 0x87c7, 0, 938, 0xd1, 0xec, 0, 1);
+ dialog->show(205, scene, 0, 938, textColorMark, textColorCaptain, 0, 1);
playSound(24, 7);
playAnimation(948, 0, true);
@@ -3847,16 +4713,16 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
waitAnimation();
loadScene(40, 198, 186, 1);
- Dialog::show(scene, 0x8890, 0, 920, 0xd1, 0xe7, 0, 1);
- Dialog::show(scene, 0x8a2f, 0, 921, 0xd1, 0xe7, 0, 1);
+ dialog->show(206, scene, 0, 920, textColorMark, textColorRGBBoss, 0, 1);
+ dialog->show(207, scene, 0, 921, textColorMark, textColorRGBBoss, 0, 1);
playAnimation(923, 0);
- Dialog::show(scene, 0x8aa7, 0, 920, 0xd1, 0xe7, 0, 1);
+ dialog->show(208, scene, 0, 920, textColorMark, textColorRGBBoss, 0, 1);
moveTo(237, 186, 0);
moveTo(237, 177, 0);
moveTo(192, 177, 4);
playAnimation(949, 0);
- Dialog::showMono(scene, 0x8af6, 950, 0xe7, 1);
+ dialog->showMono(209, scene, 950, textColorRGBBoss, 1);
playSound(32, 5);
playSound(40, 14);
@@ -3869,98 +4735,89 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
displayCredits();
loadScene(39, 192, 177, 0);
hideActor();
- Dialog::showMono(scene, 0x8b4d, 953, 0xe3, 1); //well...
+ dialog->showMono(210, scene, 953, textColorMarkEnd, 1);
playSound(5, 15);
playAnimation(954, 0);
- Dialog::showMono(scene, 0x8b7a, 955, 0xe3, 1); //that's all folks
+ dialog->showMono(211, scene, 955, textColorMarkEnd, 1);
playMusic(2);
- displayCredits(0xe47c, 4500); //3 minutes (infinite until key pressed in original)
+ displayCredits(dsAddr_finalCredits6, 4500); // 3 minutes (infinite until key pressed in original)
scene->push(SceneEvent(SceneEvent::kQuit));
+ break;
- return true;
-
- case 0x9921: { //using diving eq
- int id = scene->getId();
- if (id != 15) {
- displayMessage(id == 16 ? 0x38ce : 0x38a7);
- } else {
- playSound(5, 3);
- playSound(38, 16);
- playSound(38, 22);
- playActorAnimation(614);
- playSound(5, 3);
- playSound(44, 10);
- playSound(20, 26);
- playActorAnimation(615);
- loadScene(17, 156, 180, 3);
- SET_FLAG(0, 4);
- playSound(64, 7);
- playSound(64, 21);
- playSound(64, 42);
- playSound(64, 63);
- setTimerCallback(0x9a1d, 30);
- playActorAnimation(617, false, true);
+ case csAddr_useDivingEquipment: // using diving eq
+ // FIXME - Some code is missing here as displayMessage(dsAddr_cantTalkUnderwaterMsg),
+ // displayMessage(dsAddr_notSwimmingThereMsg), displayMessage(dsAddr_tooLittleAirMsg)
+ // displayMessage(dsAddr_fishDontWorryMsg) are never called.
+ {
+ int id = scene->getId();
+ if (id != 15) {
+ if (id == 16)
+ displayMessage(dsAddr_notHereMsg); // "Not here"
+ else
+ displayMessage(dsAddr_notBestPlaceMsg); // "It's not the best place for diving"
+ } else {
+ playSound(5, 3);
+ playSound(38, 16);
+ playSound(38, 22);
+ playActorAnimation(614);
+ playSound(5, 3);
+ playSound(44, 10);
+ playSound(20, 26);
+ playActorAnimation(615);
+ loadScene(17, 156, 180, 3);
+ SET_FLAG(dsAddr_timedCallbackState, 4);
+ playSound(64, 7);
+ playSound(64, 21);
+ playSound(64, 42);
+ playSound(64, 63);
+ setTimerCallback(csAddr_noAnchorTimeout, 30);
+ playActorAnimation(617, false, true);
+ }
}
- }
- return true;
+ break;
- case 0x9a1d: //no anchor, timeout
- SET_FLAG(0, 0);
- processCallback(0x9a7a);
- INC_FLAG(0xDBA6);
- switch (GET_FLAG(0xDBA6)) {
+ case csAddr_noAnchorTimeout: // no anchor, timeout
+ SET_FLAG(dsAddr_timedCallbackState, 0);
+ fnGetOutOfLake();
+ INC_FLAG(dsAddr_lakeDivingExitMessage);
+ switch (GET_FLAG(dsAddr_lakeDivingExitMessage)) {
case 1:
- displayMessage(0x39ae);
+ displayMessage(dsAddr_seaweedMsg); // "This seaweed is just like the flowers I gave mum on her last birthday"
break;
case 2:
- displayMessage(0x39f6);
+ displayMessage(dsAddr_fishBoatMsg); // "I wonder what fish do inside this boat at night"
break;
case 3:
- displayMessage(0x3a28);
+ displayMessage(dsAddr_fishSomethingMsg); // "I think I have to fish out something down there"
break;
case 4:
- displayMessage(0x3a85);
+ displayMessage(dsAddr_notRedHerringMsg); // "I hope all this fish stuff is not a red herring"
break;
case 5:
- displayMessage(0x39ae);
+ displayMessage(dsAddr_seaweedMsg); // "This seaweed is just like the flowers I gave mum on her last birthday"
break;
default:
- displayMessage(0x3ab7);
+ displayMessage(dsAddr_niceDownMsg); // "It's nice down there"
+ break;
}
- return true;
+ break;
- case 0x99e0: //success getting an anchor
- SET_FLAG(0, 0);
- setTimerCallback(0, 0);
- scene->getActorAnimation()->free();
- playSound(64, 7);
- playActorAnimation(618);
- disableObject(5);
- setOns(0, 0);
- playSound(31, 1);
- playActorAnimation(619);
- processCallback(0x9a7a);
- inventory->add(42);
- displayMessage(0x3989);
- return true;
+ case csAddr_gotAnchor:
+ fnGotAnchor();
+ break;
- case 0x9a7a:
- loadScene(15, 156, 180, 3);
- playSound(5, 5);
- playSound(38, 14);
- playSound(38, 20);
- playSound(5, 25);
- playActorAnimation(616);
- return true;
+ case csAddr_getOutOfLake:
+ fnGetOutOfLake();
+ break;
- case 0x9aca:
+ case csAddr_digMansionWall:
if (scene->getId() == 13) {
moveTo(172, 181, 1);
playSound(26, 19);
for (uint i = 0; i < 8; ++i)
playSound(26, 30 + i * 11);
playActorAnimation(661);
- displayCutsceneMessage(0x3c80, 30484);
+ displayCutsceneMessage(dsAddr_cutsceneMsgA, 84, 95); // "Hundred moments later"
playSound(56, 10);
playSound(56, 21);
@@ -3974,7 +4831,7 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
waitAnimation();
setOns(1, 49);
- displayCutsceneMessage(0x3c9a, 30453);
+ displayCutsceneMessage(dsAddr_cutsceneMsgB, 53, 95); // "Another hundred moments later"
moveTo(162, 184, 0, true);
playSound(26, 6);
playSound(26, 17);
@@ -3986,27 +4843,32 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
playActorAnimation(664);
playAnimation(665, 1);
wait(100);
- displayMessage(0x3cbc);
+ displayMessage(dsAddr_foundCrudeOilMsg); // "At least I found crude oil and I'll be rich"
wait(100);
- displayMessage(0x3cea);
- inventory->remove(37);
- processCallback(0x9d45); //another mansion try
+ displayMessage(dsAddr_myLifeMsg); // "That's my life"
+ inventory->remove(kInvItemShovelAct2);
+ fnMansionIntrusionAttempt();
} else
- displayMessage(0x3c58);
- return true;
+ displayMessage(dsAddr_notThinkRightPlaceMsg); // "I don't think this is the right place"
+ break;
- case 0x9c6d:
- displayMessage(0x49d1);
- SET_FLAG(0xDBB5, 1);
- return false;
+ case csAddr_tooDarkHere:
+ displayMessage(dsAddr_cantDoTooDarkMsg); // "I can't do anything here, it's too dark"
+ break;
+
+ case csAddr_examineBanknote:
+ displayMessage(dsAddr_bankNoteMsg); // "It's a note from some bank..."
+ SET_FLAG(dsAddr_examinedBanknoteFlag, 1);
+ retVal = false;
+ break;
- case 0x9c79: //use pills
+ case csAddr_useTimePills: // use pills
if (scene->getId() != 36) {
- displayMessage(0x52a9);
- } else if (CHECK_FLAG(0xDBF1, 1)) {
- displayMessage(0x52F6);
+ displayMessage(dsAddr_notTryNowMsg); // "There's no need to try them now"
+ } else if (CHECK_FLAG(dsAddr_mansionAlreadyUsedTimePillsFlag, 1)) {
+ displayMessage(dsAddr_nahMsg); // "Nah"
} else {
- SET_FLAG(0xDBF1, 1);
+ SET_FLAG(dsAddr_mansionAlreadyUsedTimePillsFlag, 1);
moveTo(102, 195, 2);
playSound(5, 3);
playSound(75, 12);
@@ -4020,131 +4882,59 @@ bool TeenAgentEngine::processCallback(uint16 addr) {
{
Walkbox *w = scene->getWalkbox(0);
w->rect.left = 0;
- w->rect.bottom = 199;
+ w->rect.bottom = kScreenHeight-1;
w->save();
}
setLan(1, 0xff);
- Dialog::showMark(scene, 0x58a9);
+ dialog->showMark(130, scene);
Object *obj = scene->getObject(1);
- obj->actor_rect.left = obj->actor_rect.right = 270;
- obj->actor_rect.top = obj->actor_rect.bottom = 193;
- obj->actor_orientation = 2;
+ obj->actorRect.left = obj->actorRect.right = 270;
+ obj->actorRect.top = obj->actorRect.bottom = 193;
+ obj->actorOrientation = 2;
obj->save();
obj = scene->getObject(3);
- obj->actor_rect.left = obj->actor_rect.right = 254;
- obj->actor_rect.top = obj->actor_rect.bottom = 193;
- obj->actor_orientation = 1;
+ obj->actorRect.left = obj->actorRect.right = 254;
+ obj->actorRect.top = obj->actorRect.bottom = 193;
+ obj->actorOrientation = 1;
obj->save();
- SET_FLAG(0xDBD7, 1);
+ SET_FLAG(dsAddr_MansionThruFanByTimePillFlag, 1);
}
- return true;
+ break;
- case 0x9d45: {
- wait(50);
- byte attempts = ++ *(res->dseg.ptr(0xDBEA));
- debug(0, "mansion intrusion attempt #%u", attempts);
- if (attempts >= 7)
- return false;
+ case csAddr_mansionIntrusionAttempt:
+ retVal = fnMansionIntrusionAttempt();
+ break;
- uint16 ptr = res->dseg.get_word((attempts - 2) * 2 + 0x6035);
- debug(0, "mansion callback = %04x", ptr);
- byte id = scene->getId();
+ case csAddr_secondMansionIntrusion:
+ fnSecondMansionIntrusion();
+ break;
- playMusic(11);
- displayCutsceneMessage(0x580a, 30484);
- processCallback(ptr);
- playMusic(6);
- if (getFlag(0xdbec) != 1 || ptr != 0x9f3e) //ptr check eq. scene_id == 11
- loadScene(id, scene->getPosition());
- return true;
- }
+ case csAddr_thirdMansionIntrusion:
+ fnThirdMansionIntrusion();
+ break;
- case 0x9d90:
- hideActor();
- loadScene(34, scene->getPosition());
- playAnimation(986, 0, true);
- playAnimation(987, 1, true);
- waitAnimation();
- Dialog::show(scene, 0x6f60, 988, 989, 0xd9, 0xd0, 1, 2);
- playAnimation(990, 0, true);
- playAnimation(991, 1, true);
- waitAnimation();
- showActor();
- return true;
-
- case 0x9de5:
- hideActor();
- loadScene(30, scene->getPosition());
- playAnimation(887, 1);
- playAnimation(888, 2, true, true, true);
- //waitAnimation();
- Dialog::showMono(scene, 0x6fb8, 889, 0xd9, 2);
- playSound(26, 3);
- playAnimation(891, 1, true, true, true);
- playAnimation(892, 2);
- waitAnimation();
- Dialog::show(scene, 0x6ff0, 890, 889, 0xd0, 0xd9, 3, 2);
- showActor();
- return true;
-
- case 0x9e54:
- hideActor();
- loadScene(32, scene->getPosition());
- playAnimation(894, 1, true, true, true);
- playAnimation(893, 2, true);
- waitAnimation();
- Dialog::showMono(scene, 0x706e, 895, 0xd9, 3);
- playSound(75, 9);
- playAnimation(898, 1, true);
- playAnimation(897, 2, true);
- Dialog::show(scene, 0x7096, 896, 895, 0xd0, 0xd9, 2, 3);
- showActor();
- return true;
+ case csAddr_fourthMansionIntrusion:
+ fnFourthMansionIntrusion();
+ break;
- case 0x9ec3:
- hideActor();
- loadScene(29, scene->getPosition());
- playActorAnimation(901, true);
- playAnimation(900, 1, true);
- waitAnimation();
- Dialog::show(scene, 0x7161, 903, 902, 0xd0, 0xd9, 2, 3);
- for (byte i = 3; i <= 9; i += 2)
- playSound(56, i);
+ case csAddr_fifthMansionIntrusion:
+ fnFifthMansionIntrusion();
+ break;
- playActorAnimation(905, true);
- playAnimation(904, 1, true);
- Dialog::show(scene, 0x71c6, 903, 902, 0xd0, 0xd9, 2, 3);
- showActor();
- return true;
+ case csAddr_sixthMansionIntrusion:
+ fnSixthMansionIntrusion();
+ break;
- case 0x9f3e:
- hideActor();
- loadScene(35, scene->getPosition());
- playAnimation(907, 2, true);
- playAnimation(906, 3, true);
- waitAnimation();
- Dialog::show(scene, 0x7243, 908, 909, 0xd9, 0xd0, 2, 3);
- Dialog::show(scene, 0x7318, 910, 908, 0xd0, 0xd9, 3, 2);
- loadScene(11, scene->getPosition());
- showActor();
- setOns(3, 51);
- playAnimation(911, 1);
- playAnimation(899, 1);
- setFlag(0xDBEC, 1);
- reloadLan();
- wait(200);
- enableObject(8);
- setLan(2, 8);
- return true;
+ default:
+ error("unknown callback 0x%04x called", addr);
+ break;
}
- //error("invalid callback %04x called", addr);
- warning("invalid callback %04x called", addr);
- return true;
+ return retVal;
}
} // End of namespace TeenAgent
diff --git a/engines/teenagent/detection.cpp b/engines/teenagent/detection.cpp
index 2de6f49c44..0c1268a5fc 100644
--- a/engines/teenagent/detection.cpp
+++ b/engines/teenagent/detection.cpp
@@ -26,6 +26,7 @@
#include "base/plugins.h"
#include "engines/advancedDetector.h"
+#include "teenagent/resources.h"
#include "teenagent/teenagent.h"
#include "graphics/thumbnail.h"
@@ -168,7 +169,7 @@ public:
Common::String desc = buf;
- in->seek(0x777a);
+ in->seek(TeenAgent::saveStateSize);
if (!Graphics::checkThumbnailHeader(*in))
return SaveStateDescriptor(slot, desc);
diff --git a/engines/teenagent/dialog.cpp b/engines/teenagent/dialog.cpp
index 400bd7cec2..870aca6400 100644
--- a/engines/teenagent/dialog.cpp
+++ b/engines/teenagent/dialog.cpp
@@ -22,99 +22,103 @@
#include "teenagent/dialog.h"
#include "teenagent/resources.h"
#include "teenagent/scene.h"
+#include "teenagent/teenagent.h"
namespace TeenAgent {
+void Dialog::show(uint16 dialogNum, Scene *scene, uint16 animation1, uint16 animation2, byte color1, byte color2, byte slot1, byte slot2) {
+ uint16 addr = _vm->res->getDialogAddr(dialogNum);
+ // WORKAROUND: For Dialog 163, The usage of this in the engine overlaps the previous dialog i.e. the
+ // starting offset used is two bytes early, thus implicitly changing the first command of this dialog
+ // from NEW_LINE to CHANGE_CHARACTER.
+ // FIXME: Unsure if this is correct behaviour or if this is a regression from the original. Check this.
+ // Similar issue occurs with Dialog 190 which is used from dialogue stack at 0x7403, rather than start of 0x7405
+ // Similar issue occurs with Dialog 0 which is used from dialogue stack at 0x0001, rather than start of 0x0000
+ if (dialogNum == 163)
+ addr -= 2;
+ show(scene, addr, animation1, animation2, color1, color2, slot1, slot2);
+}
+
void Dialog::show(Scene *scene, uint16 addr, uint16 animation1, uint16 animation2, byte color1, byte color2, byte slot1, byte slot2) {
- debug(0, "Dialog::show(%04x, %u:%u, %u:%u)", addr, slot1, animation1, slot2, animation2);
- Resources *res = Resources::instance();
+ debugC(0, kDebugDialog, "Dialog::show(%04x, %u:%u, %u:%u)", addr, slot1, animation1, slot2, animation2);
int n = 0;
Common::String message;
byte color = color1;
if (animation1 != 0) {
- SceneEvent e(SceneEvent::kPlayAnimation);
- e.animation = animation1;
- e.slot = 0xc0 | slot1; //looped, paused
- scene->push(e);
+ SceneEvent e1(SceneEvent::kPlayAnimation);
+ e1.animation = animation1;
+ e1.slot = 0xc0 | slot1; //looped, paused
+ scene->push(e1);
}
if (animation2 != 0) {
- SceneEvent e(SceneEvent::kPlayAnimation);
- e.animation = animation2;
- e.slot = 0xc0 | slot2; //looped, paused
- scene->push(e);
+ SceneEvent e2(SceneEvent::kPlayAnimation);
+ e2.animation = animation2;
+ e2.slot = 0xc0 | slot2; //looped, paused
+ scene->push(e2);
}
while (n < 4) {
- byte c = res->eseg.get_byte(addr++);
- //debug(0, "%02x: %c", c, c > 0x20? c: '.');
+ byte c = _vm->res->eseg.get_byte(addr++);
+ debugC(1, kDebugDialog, "%02x: %c", c, c > 0x20? c: '.');
switch (c) {
case 0:
++n;
switch (n) {
case 1:
- //debug(0, "new line\n");
+ debugC(1, kDebugDialog, "new line\n");
if (!message.empty())
message += '\n';
break;
case 2:
- //debug(0, "displaymessage %s", message.c_str());
+ debugC(1, kDebugDialog, "displaymessage %s", message.c_str());
if (color == color2) {
//pause animation in other slot
- {
- SceneEvent e(SceneEvent::kPauseAnimation);
- e.slot = 0x80 | slot1;
- scene->push(e);
- }
- {
- SceneEvent e(SceneEvent::kPlayAnimation);
- e.animation = animation2;
- e.slot = 0x80 | slot2;
- scene->push(e);
- }
+ SceneEvent e1(SceneEvent::kPauseAnimation);
+ e1.slot = 0x80 | slot1;
+ scene->push(e1);
+
+ SceneEvent e2(SceneEvent::kPlayAnimation);
+ e2.animation = animation2;
+ e2.slot = 0x80 | slot2;
+ scene->push(e2);
} else if (color == color1) {
//pause animation in other slot
- {
- SceneEvent e(SceneEvent::kPauseAnimation);
- e.slot = 0x80 | slot2;
- scene->push(e);
- }
- {
- SceneEvent e(SceneEvent::kPlayAnimation);
- e.animation = animation1;
- e.slot = 0x80 | slot1;
- scene->push(e);
- }
- }
+ SceneEvent e2(SceneEvent::kPauseAnimation);
+ e2.slot = 0x80 | slot2;
+ scene->push(e2);
- {
- message.trim();
- if (message.empty())
- break;
+ SceneEvent e1(SceneEvent::kPlayAnimation);
+ e1.animation = animation1;
+ e1.slot = 0x80 | slot1;
+ scene->push(e1);
+ }
- SceneEvent e(SceneEvent::kMessage);
- e.message = message;
- e.color = color;
+ message.trim();
+ if (!message.empty()) {
+ SceneEvent em(SceneEvent::kMessage);
+ em.message = message;
+ em.color = color;
if (color == color1)
- e.slot = slot1;
+ em.slot = slot1;
if (color == color2)
- e.slot = slot2;
- scene->push(e);
+ em.slot = slot2;
+ scene->push(em);
message.clear();
}
break;
case 3:
- color = color == color1 ? color2 : color1;
- //debug(0, "changing color to %02x", color);
+ color = (color == color1) ? color2 : color1;
+ debugC(1, kDebugDialog, "changing color to %02x", color);
break;
}
break;
case 0xff: {
- //fixme : wait for the next cycle of the animation
+ //FIXME : wait for the next cycle of the animation
}
break;
@@ -124,21 +128,20 @@ void Dialog::show(Scene *scene, uint16 addr, uint16 animation1, uint16 animation
}
}
- SceneEvent e(SceneEvent::kClearAnimations);
- scene->push(e);
+ SceneEvent ec(SceneEvent::kClearAnimations);
+ scene->push(ec);
}
uint16 Dialog::pop(Scene *scene, uint16 addr, uint16 animation1, uint16 animation2, byte color1, byte color2, byte slot1, byte slot2) {
- debug(0, "Dialog::pop(%04x, %u:%u, %u:%u)", addr, slot1, animation1, slot2, animation2);
- Resources *res = Resources::instance();
+ debugC(0, kDebugDialog, "Dialog::pop(%04x, %u:%u, %u:%u)", addr, slot1, animation1, slot2, animation2);
uint16 next;
do {
- next = res->dseg.get_word(addr);
+ next = _vm->res->dseg.get_word(addr);
addr += 2;
} while (next == 0);
- uint16 next2 = res->dseg.get_word(addr);
+ uint16 next2 = _vm->res->dseg.get_word(addr);
if (next2 != 0xffff)
- res->dseg.set_word(addr - 2, 0);
+ _vm->res->dseg.set_word(addr - 2, 0);
show(scene, next, animation1, animation2, color1, color2, slot1, slot2);
return next;
}
diff --git a/engines/teenagent/dialog.h b/engines/teenagent/dialog.h
index 3bb7d818c1..6672ce7206 100644
--- a/engines/teenagent/dialog.h
+++ b/engines/teenagent/dialog.h
@@ -27,20 +27,59 @@
namespace TeenAgent {
+// Text Color Symbols
+enum {
+ textColorJohnNoty = 0xd0,
+ textColorCampGuard = 0xd0,
+ textColorShockedCaptain = 0xd0,
+ textColorMark = 0xd1,
+ textColorCredits = 0xd1,
+ textColorBankGuard = 0xd7,
+ textColorGrandpa = 0xd8,
+ textColorMansionGuard = 0xd9,
+ textColorMarkEnd = 0xe3,
+ textColorProfessor = 0xe5,
+ textColorOldLady = 0xe5,
+ textColorAnne = 0xe5,
+ textColorWellEcho = 0xe5,
+ textColorSonny = 0xe5,
+ textColorEskimo = 0xe5,
+ textColorRGBBoss = 0xe7,
+ textColorGoldDriver = 0xe7,
+ textColorFortuneTeller = 0xeb,
+ textColorCaptain = 0xec,
+ textColorMike = 0xef,
+ textColorCook = 0xef,
+ textColorBarman = 0xef
+};
+
class Scene;
+class TeenAgentEngine;
+
class Dialog {
public:
- static uint16 pop(Scene *scene, uint16 addr, uint16 animation1, uint16 animation2, byte color1, byte color2, byte slot1, byte slot2);
- static uint16 popMark(Scene *scene, uint16 addr) {
- return pop(scene, addr, 0, 0, 0xd1, 0xd1, 0, 0);
+ Dialog(TeenAgentEngine *vm) : _vm(vm) { }
+
+ uint16 pop(Scene *scene, uint16 addr, uint16 animation1, uint16 animation2, byte color1, byte color2, byte slot1, byte slot2);
+
+ uint16 popMark(Scene *scene, uint16 addr) {
+ return pop(scene, addr, 0, 0, textColorMark, textColorMark, 0, 0);
}
- static void show(Scene *scene, uint16 addr, uint16 animation1, uint16 animation2, byte color1, byte color2, byte slot1, byte slot2);
- static void showMono(Scene *scene, uint16 addr, uint16 animation, byte color, byte slot) {
- show(scene, addr, animation, animation, color, color, slot, slot);
+
+ void show(uint16 dialogNum, Scene *scene, uint16 animation1, uint16 animation2, byte color1, byte color2, byte slot1, byte slot2);
+
+ void showMono(uint16 dialogNum, Scene *scene, uint16 animation, byte color, byte slot) {
+ show(dialogNum, scene, animation, animation, color, color, slot, slot);
}
- static void showMark(Scene *scene, uint16 addr) {
- show(scene, addr, 0, 0, 0xd1, 0xd1, 0, 0);
+
+ void showMark(uint16 dialogNum, Scene *scene) {
+ show(dialogNum, scene, 0, 0, textColorMark, textColorMark, 0, 0);
}
+
+private:
+ TeenAgentEngine *_vm;
+
+ void show(Scene *scene, uint16 addr, uint16 animation1, uint16 animation2, byte color1, byte color2, byte slot1, byte slot2);
};
} // End of namespace TeenAgent
diff --git a/engines/teenagent/font.cpp b/engines/teenagent/font.cpp
index f7558b60f2..47f52ff90f 100644
--- a/engines/teenagent/font.cpp
+++ b/engines/teenagent/font.cpp
@@ -20,8 +20,10 @@
*/
#include "teenagent/font.h"
+
#include "teenagent/pack.h"
-#include "common/debug.h"
+#include "teenagent/teenagent.h"
+
#include "common/endian.h"
#include "common/stream.h"
#include "common/textconsole.h"
@@ -30,34 +32,41 @@
namespace TeenAgent {
-Font::Font() : grid_color(0xd0), shadow_color(0), height(0), width_pack(0), data(0) {
+Font::Font() : _gridColor(0xd0), _shadowColor(0), _height(0), _widthPack(0), _data(0) {
+}
+
+Font::~Font() {
+ delete[] _data;
}
-void Font::load(const Pack &pack, int id) {
- delete[] data;
- data = NULL;
+void Font::load(const Pack &pack, int id, byte height, byte widthPack) {
+ delete[] _data;
+ _data = NULL;
Common::ScopedPtr<Common::SeekableReadStream> s(pack.getStream(id));
if (!s)
error("loading font %d failed", id);
- data = new byte[s->size()];
- s->read(data, s->size());
- debug(0, "font size: %d", s->size());
+ _data = new byte[s->size()];
+ s->read(_data, s->size());
+ debugC(0, kDebugFont, "font size: %d", s->size());
+
+ _height = height;
+ _widthPack = widthPack;
}
uint Font::render(Graphics::Surface *surface, int x, int y, char c, byte color) {
unsigned idx = (unsigned char)c;
if (idx < 0x20 || idx >= 0x81) {
- debug(0, "unhandled char 0x%02x", idx);
+ debugC(0, kDebugFont, "unhandled char 0x%02x", idx);
return 0;
}
idx -= 0x20;
- byte *glyph = data + READ_LE_UINT16(data + idx * 2);
+ byte *glyph = _data + READ_LE_UINT16(_data + idx * 2);
int h = glyph[0], w = glyph[1];
- if (surface == NULL || surface->pixels == NULL || y + h <= 0 || y >= 200 || x + w <= 0 || x >= 320)
- return w - width_pack;
+ if (surface == NULL || surface->pixels == NULL || y + h <= 0 || y >= kScreenHeight || x + w <= 0 || x >= kScreenWidth)
+ return w - _widthPack;
int i0 = 0, j0 = 0;
if (x < 0) {
@@ -68,7 +77,7 @@ uint Font::render(Graphics::Surface *surface, int x, int y, char c, byte color)
i0 = -y;
y = 0;
}
- //debug(0, "char %c, width: %dx%d", c, w, h);
+ debugC(0, kDebugFont, "char %c, width: %dx%d", c, w, h);
glyph += 2;
glyph += i0 * w + j0;
byte *dst = (byte *)surface->getBasePtr(x, y);
@@ -80,7 +89,7 @@ uint Font::render(Graphics::Surface *surface, int x, int y, char c, byte color)
case 0:
break;
case 1:
- dst[j] = shadow_color;
+ dst[j] = _shadowColor;
break;
case 2:
dst[j] = color;
@@ -91,57 +100,57 @@ uint Font::render(Graphics::Surface *surface, int x, int y, char c, byte color)
}
dst += surface->pitch;
}
- return w - width_pack;
+ return w - _widthPack;
}
-static uint find_in_str(const Common::String &str, char c, uint pos = 0) {
+static uint findInStr(const Common::String &str, char c, uint pos = 0) {
while (pos < str.size() && str[pos] != c) ++pos;
return pos;
}
-uint Font::render(Graphics::Surface *surface, int x, int y, const Common::String &str, byte color, bool show_grid) {
+uint Font::render(Graphics::Surface *surface, int x, int y, const Common::String &str, byte color, bool showGrid) {
if (surface != NULL) {
- uint max_w = render(NULL, 0, 0, str, false);
- if (show_grid)
- grid(surface, x - 4, y - 2, max_w + 8, 8 + 6, grid_color);
+ uint maxW = render(NULL, 0, 0, str, false);
+ if (showGrid)
+ grid(surface, x - 4, y - 2, maxW + 8, 8 + 6, _gridColor);
uint i = 0, j;
do {
- j = find_in_str(str, '\n', i);
+ j = findInStr(str, '\n', i);
Common::String line(str.c_str() + i, j - i);
- //debug(0, "line: %s", line.c_str());
+ debugC(0, kDebugFont, "line: %s", line.c_str());
- if (y + (int)height >= 0) {
+ if (y + (int)_height >= 0) {
uint w = render(NULL, 0, 0, line, false);
- int xp = x + (max_w - w) / 2;
+ int xp = x + (maxW - w) / 2;
for (uint k = 0; k < line.size(); ++k) {
xp += render(surface, xp, y, line[k], color);
}
- } else if (y >= 200)
+ } else if (y >= kScreenHeight)
break;
- y += height;
+ y += _height;
i = j + 1;
} while (i < str.size());
- return max_w;
+ return maxW;
} else {
- //surface == NULL;
- uint w = 0, max_w = 0;
+ // surface == NULL;
+ uint w = 0, maxW = 0;
for (uint i = 0; i < str.size(); ++i) {
char c = str[i];
if (c == '\n') {
- y += height;
- if (w > max_w)
- max_w = w;
+ y += _height;
+ if (w > maxW)
+ maxW = w;
w = 0;
continue;
}
w += render(NULL, 0, 0, c, color);
}
- if (w > max_w)
- max_w = w;
+ if (w > maxW)
+ maxW = w;
- return max_w;
+ return maxW;
}
}
@@ -156,8 +165,4 @@ void Font::grid(Graphics::Surface *surface, int x, int y, int w, int h, byte col
}
}
-Font::~Font() {
- delete[] data;
-}
-
} // End of namespace TeenAgent
diff --git a/engines/teenagent/font.h b/engines/teenagent/font.h
index 5146ace21f..a61f145fa6 100644
--- a/engines/teenagent/font.h
+++ b/engines/teenagent/font.h
@@ -28,20 +28,24 @@
namespace TeenAgent {
class Pack;
+
class Font {
public:
- byte grid_color, shadow_color;
- byte height, width_pack;
-
Font();
- void load(const Pack &pack, int id);
- uint render(Graphics::Surface *surface, int x, int y, const Common::String &str, byte color, bool grid = false);
+ ~Font();
+
+ void load(const Pack &pack, int id, byte height, byte widthPack);
+ uint render(Graphics::Surface *surface, int x, int y, const Common::String &str, byte color, bool showGrid = false);
uint render(Graphics::Surface *surface, int x, int y, char c, byte color);
static void grid(Graphics::Surface *surface, int x, int y, int w, int h, byte color);
- ~Font();
+ byte getHeight() { return _height; }
+ void setShadowColor(byte color) { _shadowColor = color; }
private:
- byte *data;
+ byte *_data;
+
+ byte _gridColor, _shadowColor;
+ byte _height, _widthPack;
};
} // End of namespace TeenAgent
diff --git a/engines/teenagent/inventory.cpp b/engines/teenagent/inventory.cpp
index 59dd44baa3..354371666c 100644
--- a/engines/teenagent/inventory.cpp
+++ b/engines/teenagent/inventory.cpp
@@ -24,6 +24,7 @@
#include "common/textconsole.h"
#include "teenagent/inventory.h"
+
#include "teenagent/resources.h"
#include "teenagent/objects.h"
#include "teenagent/teenagent.h"
@@ -31,47 +32,44 @@
namespace TeenAgent {
-Inventory::Inventory(TeenAgentEngine *engine) {
- _engine = engine;
+Inventory::Inventory(TeenAgentEngine *vm) : _vm(vm) {
_active = false;
FilePack varia;
varia.open("varia.res");
- {
- Common::ScopedPtr<Common::SeekableReadStream> s(varia.getStream(3));
- if (!s)
- error("no inventory background");
- debug(0, "loading inventory background...");
- _background.load(*s, Surface::kTypeOns);
- }
+ Common::ScopedPtr<Common::SeekableReadStream> s(varia.getStream(3));
+ if (!s)
+ error("no inventory background");
+ debugC(0, kDebugInventory, "loading inventory background...");
+ _background.load(*s, Surface::kTypeOns);
- uint32 items_size = varia.getSize(4);
- if (items_size == 0)
+ uint32 itemsSize = varia.getSize(4);
+ if (itemsSize == 0)
error("invalid inventory items size");
- debug(0, "loading items, size: %u", items_size);
- _items = new byte[items_size];
- varia.read(4, _items, items_size);
+ debugC(0, kDebugInventory, "loading items, size: %u", itemsSize);
+ _items = new byte[itemsSize];
+ varia.read(4, _items, itemsSize);
byte offsets = _items[0];
- assert(offsets == 92);
+ assert(offsets == kNumInventoryItems);
for (byte i = 0; i < offsets; ++i) {
_offset[i] = READ_LE_UINT16(_items + i * 2 + 1);
}
- _offset[92] = items_size;
+ _offset[kNumInventoryItems] = itemsSize;
- Resources *res = Resources::instance();
- for (byte i = 0; i <= 92; ++i) {
+ InventoryObject ioBlank;
+ _objects.push_back(ioBlank);
+ for (byte i = 0; i < kNumInventoryItems; ++i) {
InventoryObject io;
- uint16 obj_addr = res->dseg.get_word(0xc4a4 + i * 2);
- if (obj_addr != 0)
- io.load(res->dseg.ptr(obj_addr));
+ uint16 objAddr = vm->res->dseg.get_word(dsAddr_inventoryItemDataPtrTable + i * 2);
+ io.load(vm->res->dseg.ptr(objAddr));
_objects.push_back(io);
}
- _inventory = res->dseg.ptr(0xc48d);
+ _inventory = vm->res->dseg.ptr(dsAddr_inventory);
- for (int y = 0; y < 4; ++y)
+ for (int y = 0; y < 4; ++y) {
for (int x = 0; x < 6; ++x) {
int i = y * 6 + x;
_graphics[i]._rect.left = 28 + 45 * x - 1;
@@ -79,6 +77,7 @@ Inventory::Inventory(TeenAgentEngine *engine) {
_graphics[i]._rect.right = _graphics[i]._rect.left + 40;
_graphics[i]._rect.bottom = _graphics[i]._rect.top + 26;
}
+ }
varia.close();
_hoveredObj = _selectedObj = NULL;
@@ -89,7 +88,7 @@ Inventory::~Inventory() {
}
bool Inventory::has(byte item) const {
- for (int i = 0; i < 24; ++i) {
+ for (int i = 0; i < kInventorySize; ++i) {
if (_inventory[i] == item)
return true;
}
@@ -97,34 +96,34 @@ bool Inventory::has(byte item) const {
}
void Inventory::remove(byte item) {
- debug(0, "removing %u from inventory", item);
+ debugC(0, kDebugInventory, "removing %u from inventory", item);
int i;
- for (i = 0; i < 24; ++i) {
+ for (i = 0; i < kInventorySize; ++i) {
if (_inventory[i] == item) {
break;
}
}
- for (; i < 23; ++i) {
+ for (; i < (kInventorySize - 1); ++i) {
_inventory[i] = _inventory[i + 1];
_graphics[i].free();
}
- _inventory[23] = 0;
- _graphics[23].free();
+ _inventory[kInventorySize - 1] = kInvItemNoItem;
+ _graphics[kInventorySize - 1].free();
}
void Inventory::clear() {
- debug(0, "clearing inventory");
- for (int i = 0; i < 24; ++i) {
- _inventory[i] = 0;
+ debugC(0, kDebugInventory, "clearing inventory");
+ for (int i = 0; i < kInventorySize; ++i) {
+ _inventory[i] = kInvItemNoItem;
_graphics[i].free();
}
}
void Inventory::reload() {
- for (int i = 0; i < 24; ++i) {
+ for (int i = 0; i < kInventorySize; ++i) {
_graphics[i].free();
uint item = _inventory[i];
- if (item != 0)
+ if (item != kInvItemNoItem)
_graphics[i].load(this, item);
}
}
@@ -132,9 +131,9 @@ void Inventory::reload() {
void Inventory::add(byte item) {
if (has(item))
return;
- debug(0, "adding %u to inventory", item);
- for (int i = 0; i < 24; ++i) {
- if (_inventory[i] == 0) {
+ debugC(0, kDebugInventory, "adding %u to inventory", item);
+ for (int i = 0; i < kInventorySize; ++i) {
+ if (_inventory[i] == kInvItemNoItem) {
_inventory[i] = item;
return;
}
@@ -143,13 +142,14 @@ void Inventory::add(byte item) {
}
bool Inventory::tryObjectCallback(InventoryObject *obj) {
- byte id = obj->id;
- uint i = 0;
- for (byte *table = Resources::instance()->dseg.ptr(0xBB6F + 3); table[0] != 0 && i < 7; table += 3, ++i) {
- if (table[0] == id) {
+ byte objId = obj->id;
+ for (uint i = 0; i < 7; ++i) {
+ byte tableId = _vm->res->dseg.get_byte(dsAddr_objCallbackTablePtr + (3 * i));
+ uint16 callbackAddr = _vm->res->dseg.get_word(dsAddr_objCallbackTablePtr + (3 * i) + 1);
+ if (tableId == objId) {
resetSelectedObject();
activate(false);
- if (_engine->processCallback(READ_LE_UINT16(table + 1)))
+ if (_vm->processCallback(callbackAddr))
return true;
}
}
@@ -157,8 +157,6 @@ bool Inventory::tryObjectCallback(InventoryObject *obj) {
}
bool Inventory::processEvent(const Common::Event &event) {
- Resources *res = Resources::instance();
-
switch (event.type) {
case Common::EVENT_MOUSEMOVE:
@@ -178,9 +176,9 @@ bool Inventory::processEvent(const Common::Event &event) {
_mouse = event.mouse;
_hoveredObj = NULL;
- for (int i = 0; i < 24; ++i) {
+ for (int i = 0; i < kInventorySize; ++i) {
byte item = _inventory[i];
- if (item == 0)
+ if (item == kInvItemNoItem)
continue;
_graphics[i]._hovered = _graphics[i]._rect.in(_mouse);
@@ -197,14 +195,14 @@ bool Inventory::processEvent(const Common::Event &event) {
if (_hoveredObj == NULL)
return true;
- debug(0, "lclick on %u:%s", _hoveredObj->id, _hoveredObj->name.c_str());
+ debugC(0, kDebugInventory, "lclick on %u:%s", _hoveredObj->id, _hoveredObj->name.c_str());
if (_selectedObj == NULL) {
if (tryObjectCallback(_hoveredObj))
return true;
//activate(false);
- int w = res->font7.render(NULL, 0, 0, _hoveredObj->description, 0xd1);
- _engine->scene->displayMessage(_hoveredObj->description, 0xd1, Common::Point((320 - w) / 2, 162));
+ int w = _vm->res->font7.render(NULL, 0, 0, _hoveredObj->description, textColorMark);
+ _vm->scene->displayMessage(_hoveredObj->description, textColorMark, Common::Point((kScreenWidth - w) / 2, 162));
return true;
}
@@ -213,30 +211,27 @@ bool Inventory::processEvent(const Common::Event &event) {
if (id1 == id2)
return true;
- debug(0, "combine(%u, %u)!", id1, id2);
- byte *table = res->dseg.ptr(0xC335);
+ debugC(0, kDebugInventory, "combine(%u, %u)!", id1, id2);
+ byte *table = _vm->res->dseg.ptr(dsAddr_objCombiningTablePtr);
while (table[0] != 0 && table[1] != 0) {
- if (
- (id1 == table[0] && id2 == table[1]) ||
- (id2 == table[0] && id1 == table[1])
- ) {
- byte new_obj = table[2];
- if (new_obj != 0) {
+ if ((id1 == table[0] && id2 == table[1]) || (id2 == table[0] && id1 == table[1])) {
+ byte newObj = table[2];
+ if (newObj != 0) {
remove(id1);
remove(id2);
- debug(0, "adding object %u", new_obj);
- add(new_obj);
- _engine->playSoundNow(69);
+ debugC(0, kDebugInventory, "adding object %u", newObj);
+ add(newObj);
+ _vm->playSoundNow(69);
}
uint16 msg = READ_LE_UINT16(table + 3);
- _engine->displayMessage(msg);
+ _vm->displayMessage(msg);
activate(false);
resetSelectedObject();
return true;
}
table += 5;
}
- _engine->displayMessage(0xc3e2);
+ _vm->displayMessage(dsAddr_objCombineErrorMsg);
activate(false);
resetSelectedObject();
return true;
@@ -247,14 +242,15 @@ bool Inventory::processEvent(const Common::Event &event) {
return false;
if (_hoveredObj != NULL) {
- debug(0, "rclick object %u:%s", _hoveredObj->id, _hoveredObj->name.c_str());
- if (_hoveredObj->id != 51 && tryObjectCallback(_hoveredObj)) //do not process callback for banknote on r-click
+ debugC(0, kDebugInventory, "rclick object %u:%s", _hoveredObj->id, _hoveredObj->name.c_str());
+ // do not process callback for banknote on r-click
+ if (_hoveredObj->id != kInvItemBanknote && tryObjectCallback(_hoveredObj))
return true;
}
_selectedObj = _hoveredObj;
if (_selectedObj)
- debug(0, "selected object %s", _selectedObj->name.c_str());
+ debugC(0, kDebugInventory, "selected object %s", _selectedObj->name.c_str());
return true;
case Common::EVENT_KEYDOWN:
@@ -262,7 +258,7 @@ bool Inventory::processEvent(const Common::Event &event) {
activate(false);
return true;
}
- if (event.kbd.keycode == Common::KEYCODE_RETURN) { //triangle button on psp
+ if (event.kbd.keycode == Common::KEYCODE_RETURN) {
activate(!_active);
return true;
}
@@ -277,7 +273,6 @@ bool Inventory::processEvent(const Common::Event &event) {
}
}
-
void Inventory::Item::free() {
_animation.free();
_surface.free();
@@ -294,30 +289,29 @@ void Inventory::Item::backgroundEffect(Graphics::Surface *s) {
}
}
-void Inventory::Item::load(Inventory *inventory, uint item_id) {
- InventoryObject *obj = &inventory->_objects[item_id];
+void Inventory::Item::load(Inventory *inventory, uint itemId) {
+ InventoryObject *obj = &inventory->_objects[itemId];
if (obj->animated) {
if (_animation.empty()) {
- debug(0, "loading item %d from offset %x", obj->id, inventory->_offset[obj->id - 1]);
+ debugC(0, kDebugInventory, "loading item %d from offset %x", obj->id, inventory->_offset[obj->id - 1]);
Common::MemoryReadStream s(inventory->_items + inventory->_offset[obj->id - 1], inventory->_offset[obj->id] - inventory->_offset[obj->id - 1]);
_animation.load(s, Animation::kTypeInventory);
}
} else {
if (_surface.empty()) {
- debug(0, "loading item %d from offset %x", obj->id, inventory->_offset[obj->id - 1]);
+ debugC(0, kDebugInventory, "loading item %d from offset %x", obj->id, inventory->_offset[obj->id - 1]);
Common::MemoryReadStream s(inventory->_items + inventory->_offset[obj->id - 1], inventory->_offset[obj->id] - inventory->_offset[obj->id - 1]);
_surface.load(s, Surface::kTypeOns);
}
}
}
-void Inventory::Item::render(Inventory *inventory, uint item_id, Graphics::Surface *dst, int delta) {
- InventoryObject *obj = &inventory->_objects[item_id];
- Resources *res = Resources::instance();
+void Inventory::Item::render(Inventory *inventory, uint itemId, Graphics::Surface *dst, int delta) {
+ InventoryObject *obj = &inventory->_objects[itemId];
backgroundEffect(dst);
_rect.render(dst, _hovered ? 233 : 234);
- load(inventory, item_id);
+ load(inventory, itemId);
if (obj->animated) {
if (_hovered) {
Surface *s = _animation.currentFrame(delta);
@@ -342,15 +336,16 @@ void Inventory::Item::render(Inventory *inventory, uint item_id, Graphics::Surfa
if (inventory->_selectedObj != inventory->_hoveredObj)
name += obj->name;
- if (_hovered && inventory->_engine->scene->getMessage().empty()) {
- int w = res->font7.render(NULL, 0, 0, name, 0xd1, true);
- res->font7.render(dst, (320 - w) / 2, 180, name, 0xd1, true);
+ if (_hovered && inventory->_vm->scene->getMessage().empty()) {
+ int w = inventory->_vm->res->font7.render(NULL, 0, 0, name, textColorMark, true);
+ inventory->_vm->res->font7.render(dst, (kScreenWidth - w) / 2, 180, name, textColorMark, true);
}
}
void Inventory::render(Graphics::Surface *surface, int delta) {
if (!_active)
return;
+ debugC(0, kDebugInventory, "Inventory::render()");
_background.render(surface);
@@ -358,11 +353,10 @@ void Inventory::render(Graphics::Surface *surface, int delta) {
for (int x = 0; x < 6; x++) {
int idx = x + 6 * y;
byte item = _inventory[idx];
- if (item == 0)
- continue;
-
- //debug(0, "%d,%d -> %u", x0, y0, item);
- _graphics[idx].render(this, item, surface, delta);
+ if (item != 0) {
+ debugC(0, kDebugInventory, "\t(x, y): %d,%d -> item: %u", x, y, item);
+ _graphics[idx].render(this, item, surface, delta);
+ }
}
}
}
diff --git a/engines/teenagent/inventory.h b/engines/teenagent/inventory.h
index 61e5364542..d487848c2c 100644
--- a/engines/teenagent/inventory.h
+++ b/engines/teenagent/inventory.h
@@ -33,9 +33,112 @@ namespace TeenAgent {
struct InventoryObject;
class TeenAgentEngine;
+// Maximum number of items found within game
+const uint8 kNumInventoryItems = 92;
+
+// Inventory Item Ids
+enum {
+ kInvItemNoItem = 0, // No item i.e. empty inventory slot
+ kInvItemFeather = 1,
+ kInvItemShotgun = 2,
+ kInvItemToolboxFull = 3, // Contains Car Jack and Spanner
+ kInvItemToolboxHalfEmpty = 4, // Contains Spanner
+ kInvItemSpanner = 5,
+ kInvItemComb = 6,
+ kInvItemFan = 7,
+ kInvItemBrokenPaddle = 8,
+ kInvItemPaddle = 9, // Repaired - BrokenPaddle combined with Branch (with Glue)
+ kInvItemFirstFlower = 10, // Smells nice
+ kInvItemSecondFlower = 11, // Really beautiful
+ kInvItemFeatherDusterClean = 12,
+ kInvItemChainsaw = 13, // Unfueled
+ kInvItemDrunkenChainsaw = 14, // Fueled with Whisky (Chainsaw combined with Whiskey)
+ kInvItemBranch = 15,
+ kInvItemWhisky = 16,
+ kInvItemNeedle = 17,
+ kInvItemWrapper = 18,
+ kInvItemChocCandy = 19,
+ kInvItemPotato = 20,
+ kInvItemRakeBroken = 21,
+ kInvItemHeartShapedCandy = 22,
+ kInvItemWrappedCandy = 23, // HeartShapedCandy combined with Wrapper
+ kInvItemRibbon = 24,
+ kInvItemRakeFixed = 25, // Rake combined with Ribbon
+ kInvItemNut = 26,
+ kInvItemPlasticApple = 27,
+ kInvItemCone = 28,
+ kInvItemSuperGlue = 29,
+ kInvItemConeAndNeedle = 30, // Cone combined with Needle
+ kInvItemConeAndFeather = 31, // Cone combined with Feather
+ kInvItemDart = 32, // Needle combined with ConeAndFeather or Feather combined with ConeAndNeedle
+ kInvItemFeatherDusterDirty = 33,
+ kInvItemPaintedPotato = 34, // Potato combined with Dirty Feather Duster (Soot)
+ kInvItemCarJack = 35,
+ kInvItemBone = 36,
+ kInvItemShovelAct2 = 37,
+ kInvItemRopeAct2 = 38,
+ kInvItemMask = 39,
+ kInvItemFins = 40,
+ kInvItemDiveEquipment = 41, // Mask combined with Fins
+ kInvItemAnchor = 42,
+ kInvItemGrapplingHook = 43,
+ kInvItemSickleBlunt = 44,
+ kInvItemCheese = 45,
+ kInvItemSickleSharp = 46,
+ kInvItemHandkerchief = 47,
+ kInvItemMouse = 48,
+ kInvItemRock = 49,
+ kInvItemNugget = 50,
+ kInvItemBanknote = 51,
+ kInvItemDictaphoneNoBatteries = 52,
+ kInvItemPolaroidCamera = 53,
+ kInvItemVideoTape = 54,
+ kInvItemSheetOfPaper = 55,
+ kInvItemCognac = 56,
+ kInvItemRemoteControl = 57,
+ kInvItemIceTongs = 58,
+ kInvItemCork = 59,
+ kInvItemWrappedCork = 60, // Cork combined with Sheet Of Paper
+ kInvItemPhoto = 61,
+ kInvItemChilliWithLabel = 62,
+ kInvItemPastryRoller = 63,
+ kInvItemFakeChilli = 64,
+ kInvItemLabel = 65,
+ kInvItemBatteries = 66,
+ kInvItemDictaphoneWithBatteries = 67, // Dictaphone combined with Batteries
+ kInvItemBurningPaper = 68,
+ kInvItemMeat = 69,
+ kInvItemPlasticBag = 70,
+ kInvItemSocks = 71,
+ kInvItemTimePills = 72,
+ kInvItemHandle = 73,
+ kInvItemChilliNoLabel = 74,
+ kInvItemPass = 75,
+ kInvItemBulb = 76,
+ kInvItemJailKey = 77,
+ kInvItemDelicatePlant = 78,
+ kInvItemSwissArmyKnife = 79,
+ kInvItemSpring = 80,
+ kInvItemShovelAct1 = 81,
+ kInvItemKaleidoscope = 82,
+ kInvItemSoldierNews = 83,
+ kInvItemGrenade = 84,
+ kInvItemMug = 85, // Empty
+ kInvItemMugOfMud = 86, // Full of mud
+ kInvItemCrumbs = 87,
+ kInvItemRopeAct1 = 88,
+ kInvItemRopeAndGrenade = 89, // Rope combined with Grenade
+ kInvItemMedicine = 90,
+ kInvItemDruggedFood = 91, // Crumbs combined with Medicine
+ kInvItemBird = 92
+};
+
+// Maximum number of inventory items held by Ego (Mark)
+const uint8 kInventorySize = 24;
+
class Inventory {
public:
- Inventory(TeenAgentEngine *engine);
+ Inventory(TeenAgentEngine *vm);
~Inventory();
void render(Graphics::Surface *surface, int delta);
@@ -55,10 +158,10 @@ public:
void resetSelectedObject() { _selectedObj = NULL; }
private:
- TeenAgentEngine *_engine;
+ TeenAgentEngine *_vm;
Surface _background;
byte *_items;
- uint _offset[93];
+ uint _offset[kNumInventoryItems+1];
Common::Array<InventoryObject> _objects;
byte *_inventory;
@@ -71,12 +174,12 @@ private:
Item() : _hovered(false) {}
void free();
- void load(Inventory *inventory, uint item_id);
+ void load(Inventory *inventory, uint itemId);
void backgroundEffect(Graphics::Surface *s);
- void render(Inventory *inventory, uint item_id, Graphics::Surface *surface, int delta);
+ void render(Inventory *inventory, uint itemId, Graphics::Surface *surface, int delta);
};
- Item _graphics[24];
+ Item _graphics[kInventorySize];
bool _active;
Common::Point _mouse;
diff --git a/engines/teenagent/music.cpp b/engines/teenagent/music.cpp
index 1f44e9cfcb..b06a5f1f5e 100644
--- a/engines/teenagent/music.cpp
+++ b/engines/teenagent/music.cpp
@@ -22,6 +22,8 @@
#include "teenagent/music.h"
#include "teenagent/resources.h"
+#include "teenagent/teenagent.h"
+
#include "common/debug.h"
#include "common/ptr.h"
#include "common/textconsole.h"
@@ -34,36 +36,36 @@ static const uint32 noteToPeriod[3][12] = {
{214, 201, 189, 179, 170, 160, 151, 143, 135, 127, 120, 113}
};
-MusicPlayer::MusicPlayer() : Paula(false, 44100, 5000), _id(0) {
+MusicPlayer::MusicPlayer(TeenAgentEngine *vm) : Paula(false, 44100, 5000), _vm(vm), _id(0) {
}
MusicPlayer::~MusicPlayer() {
+ stop();
}
bool MusicPlayer::load(int id) {
- Resources *res = Resources::instance();
-
- Common::ScopedPtr<Common::SeekableReadStream> stream(res->mmm.getStream(id));
+ debugC(0, kDebugMusic, "MusicPlayer::load(%d)", id);
+ Common::ScopedPtr<Common::SeekableReadStream> stream(_vm->res->mmm.getStream(id));
if (!stream)
return false;
char header[4];
stream->read(header, 4);
- //check header?
+ // check header?
Common::StackLock lock(_mutex);
// Load the samples
sampleCount = stream->readByte();
- debug(0, "sampleCount = %d", sampleCount);
+ debugC(0, kDebugMusic, "sampleCount = %d", sampleCount);
for (byte currSample = 0; currSample < sampleCount; currSample++) {
byte sample = stream->readByte();
// Load the sample data
- byte sampleResource = ((sample >> 4) & 0x0F) * 10 + (sample & 0x0F);
- debug(0, "currSample = %d, sample = 0x%02x, resource: %d", currSample, sample, sampleResource);
- uint32 sampleSize = res->sam_mmm.getSize(sampleResource);
+ byte sampleResource = ((sample >> 4) & 0x0f) * 10 + (sample & 0x0f);
+ debugC(0, kDebugMusic, "currSample = %d, sample = 0x%02x, resource: %d", currSample, sample, sampleResource);
+ uint32 sampleSize = _vm->res->sam_mmm.getSize(sampleResource);
if (sampleSize == 0) {
warning("load: invalid sample %d (0x%02x)", sample, sample);
_samples[sample].clear();
@@ -71,7 +73,7 @@ bool MusicPlayer::load(int id) {
}
_samples[sample].resize(sampleSize);
- res->sam_mmm.read(sampleResource, _samples[sample].data, sampleSize);
+ _vm->res->sam_mmm.read(sampleResource, _samples[sample].data, sampleSize);
}
// Load the music data
@@ -87,17 +89,17 @@ bool MusicPlayer::load(int id) {
row.channels[1].note = stream->readByte();
row.channels[2].note = stream->readByte();
_rows.push_back(row);
- } else if ((cmd & 0xF0) == 0x50) {
+ } else if ((cmd & 0xf0) == 0x50) {
byte sample = stream->readByte();
- //debug(1, "%02x: set sample %02x", cmd, sample);
- row.channels[(cmd & 0x0F) - 1].sample = sample;
- } else if ((cmd & 0xF0) == 0x40) {
+ debugC(1, kDebugMusic, "%02x: set sample %02x", cmd, sample);
+ row.channels[(cmd & 0x0f) - 1].sample = sample;
+ } else if ((cmd & 0xf0) == 0x40) {
byte vol = stream->readByte();
- //debug(1, "%02x: set volume %02x -> %02x", cmd, row.channels[(cmd & 0x0F) - 1].volume, vol);
- //channel volume 0x40 * music volume 0x40 mixed with high bytes
- row.channels[(cmd & 0x0F) - 1].volume = vol * 16;
+ debugC(1, kDebugMusic, "%02x: set volume %02x -> %02x", cmd, row.channels[(cmd & 0x0f) - 1].volume, vol);
+ // channel volume 0x40 * music volume 0x40 mixed with high bytes
+ row.channels[(cmd & 0x0f) - 1].volume = vol * 16;
} else {
- debug(0, "unhandled music command %02x", cmd);
+ debugC(0, kDebugMusic, "unhandled music command %02x", cmd);
}
}
_currRow = 0;
@@ -124,13 +126,13 @@ void MusicPlayer::interrupt() {
for (int chn = 0; chn < 3; ++chn) {
setChannelVolume(chn, row->channels[chn].volume);
- //debug(0, "row->channels[%d].volume = %d", chn, row->channels[chn].volume);
+ debugC(2, kDebugMusic, "row->channels[%d].volume = %d", chn, row->channels[chn].volume);
byte sample = (row->channels[chn].sample);
if (row->channels[chn].note != 0 && sample != 0) {
- //debug(0, "row->channels[%d].note = %d", chn, row->channels[chn].note);
- //debug(0, "row->channels[%d].sample = %d", chn, row->channels[chn].sample);
+ debugC(2, kDebugMusic, "row->channels[%d].note = %d", chn, row->channels[chn].note);
+ debugC(2, kDebugMusic, "row->channels[%d].sample = %d", chn, row->channels[chn].sample);
byte note = row->channels[chn].note;
if (_samples[sample].size == 0) {
@@ -139,11 +141,11 @@ void MusicPlayer::interrupt() {
}
setChannelData(chn, (const int8 *)_samples[sample].data, NULL, _samples[sample].size, 0);
- setChannelPeriod(chn, noteToPeriod[((note >> 4) & 0x0F) - 1][(note & 0x0F)]);
+ setChannelPeriod(chn, noteToPeriod[((note >> 4) & 0x0f) - 1][(note & 0x0f)]);
}
}
- //debug(0, "------------------------------------------------");
+ debugC(2, kDebugMusic, "------------------------------------------------");
++_currRow;
}
diff --git a/engines/teenagent/music.h b/engines/teenagent/music.h
index 22b4fa5e8e..408436cf3a 100644
--- a/engines/teenagent/music.h
+++ b/engines/teenagent/music.h
@@ -28,10 +28,11 @@
namespace TeenAgent {
+class TeenAgentEngine;
+
class MusicPlayer : public Audio::Paula {
public:
-
- MusicPlayer();
+ MusicPlayer(TeenAgentEngine *vm);
~MusicPlayer();
bool load(int id);
@@ -41,6 +42,8 @@ public:
void stop();
private:
+ TeenAgentEngine *_vm;
+
int _id;
struct Row {
diff --git a/engines/teenagent/objects.cpp b/engines/teenagent/objects.cpp
index 748f342d54..5dad9ab99d 100644
--- a/engines/teenagent/objects.cpp
+++ b/engines/teenagent/objects.cpp
@@ -21,8 +21,10 @@
#include "common/debug.h"
#include "common/memstream.h"
+
#include "teenagent/objects.h"
#include "teenagent/resources.h"
+#include "teenagent/teenagent.h"
namespace TeenAgent {
@@ -51,7 +53,6 @@ void Rect::render(Graphics::Surface *surface, uint8 color) const {
surface->vLine(right, bottom, top, color);
}
-
void Object::load(byte *src) {
_base = src;
@@ -59,39 +60,39 @@ void Object::load(byte *src) {
rect.load(src);
src += 8;
- actor_rect.load(src);
+ actorRect.load(src);
src += 8;
- actor_orientation = *src++;
+ actorOrientation = *src++;
enabled = *src++;
name = (const char *)src;
- description = parse_description((const char *)src);
+ description = parseDescription((const char *)src);
}
void Object::save() const {
assert(_base != NULL);
rect.save();
- actor_rect.save();
- _base[17] = actor_orientation;
+ actorRect.save();
+ _base[17] = actorOrientation;
_base[18] = enabled;
}
-void Object::setName(const Common::String &new_name) {
+void Object::setName(const Common::String &newName) {
assert(_base != 0);
- strcpy((char *)(_base + 19), new_name.c_str());
- name = new_name;
+ strcpy((char *)(_base + 19), newName.c_str());
+ name = newName;
}
void Object::dump(int level) const {
- debug(level, "object: %u %u [%u,%u,%u,%u], actor: [%u,%u,%u,%u], orientation: %u, name: %s", id, enabled,
+ debugC(level, kDebugObject, "object: %u %u [%u,%u,%u,%u], actor: [%u,%u,%u,%u], orientation: %u, name: %s", id, enabled,
rect.left, rect.top, rect.right, rect.bottom,
- actor_rect.left, actor_rect.top, actor_rect.right, actor_rect.bottom,
- actor_orientation, name.c_str()
+ actorRect.left, actorRect.top, actorRect.right, actorRect.bottom,
+ actorOrientation, name.c_str()
);
}
-Common::String Object::parse_description(const char *name) {
+Common::String Object::parseDescription(const char *name) {
const char *desc = name + strlen(name) + 1;
if (*desc == 0)
return Common::String();
@@ -101,7 +102,7 @@ Common::String Object::parse_description(const char *name) {
while (*desc != 1 && *desc != 0) {
Common::String line;
while (*desc != 1 && *desc != 0) {
- //debug(0, "%02x ", *desc);
+ debugC(2, kDebugObject, "%02x ", *desc);
line += *desc++;
}
@@ -115,7 +116,7 @@ Common::String Object::parse_description(const char *name) {
if (!result.empty())
result.deleteLastChar();
else
- result = "Cool.";
+ result = "Cool."; // FIXME - Use dsAddr_coolMsg ?
return result;
}
@@ -124,31 +125,31 @@ void InventoryObject::load(byte *src) {
id = *src++;
animated = *src++;
name = (const char *)src;
- description = Object::parse_description((const char *)src);
+ description = Object::parseDescription((const char *)src);
}
void UseHotspot::load(byte *src) {
Common::MemoryReadStream in(src, 9);
- inventory_id = in.readByte();
- object_id = in.readByte();
+ inventoryId = in.readByte();
+ objectId = in.readByte();
orientation = in.readByte();
- actor_x = in.readUint16LE();
- actor_y = in.readUint16LE();
+ actorX = in.readUint16LE();
+ actorY = in.readUint16LE();
callback = in.readUint16LE();
}
void UseHotspot::dump(int level) const {
- debug(level,
- "hotspot: inv_id: %02x, obj_id: %02x, orientation?: %02x, actor position: (%d,%d), callback: %04x",
- inventory_id, object_id, orientation, actor_x, actor_y, callback
+ debugC(level, kDebugObject,
+ "hotspot: invId: %02x, objId: %02x, orientation: %02x, actor position: (%d,%d), callback: %04x",
+ inventoryId, objectId, orientation, actorX, actorY, callback
);
}
void Walkbox::dump(int level) const {
- debug(level, "walkbox %02x %02x [%d, %d, %d, %d] top: %u, right: %u, bottom: %u, left: %u",
+ debugC(level, kDebugObject, "walkbox %02x %02x [%d, %d, %d, %d] top: %u, right: %u, bottom: %u, left: %u",
type, orientation,
rect.left, rect.top, rect.right, rect.bottom,
- side_hint[0], side_hint[1], side_hint[2], side_hint[3]);
+ sideHint[0], sideHint[1], sideHint[2], sideHint[3]);
}
void Walkbox::load(byte *src) {
@@ -159,7 +160,7 @@ void Walkbox::load(byte *src) {
rect.load(src);
src += 8;
for (byte i = 0; i < 4; ++i)
- side_hint[i] = *src++;
+ sideHint[i] = *src++;
}
void Walkbox::save() const {
diff --git a/engines/teenagent/objects.h b/engines/teenagent/objects.h
index 555287fc56..6e7955766f 100644
--- a/engines/teenagent/objects.h
+++ b/engines/teenagent/objects.h
@@ -26,6 +26,8 @@
#include "common/rect.h"
#include "graphics/surface.h"
+#include "teenagent/teenagent.h"
+
namespace TeenAgent {
enum {kActorUp = 1, kActorRight = 2, kActorDown = 3, kActorLeft = 4 };
@@ -46,13 +48,13 @@ struct Rect {
}
inline bool valid() const {
- return left >= 0 && left < 320 && right >= 0 && right < 320 && top >= 0 && top < 200 && bottom >= 0 && bottom < 200;
+ return left >= 0 && left < kScreenWidth && right >= 0 && right < kScreenWidth && top >= 0 && top < kScreenHeight && bottom >= 0 && bottom < kScreenHeight;
}
void render(Graphics::Surface *surface, uint8 color) const;
void dump(int level = 0) const {
- debug(level, "rect[%u, %u, %u, %u]", left, top, right, bottom);
+ debugC(level, kDebugObject, "rect[%u, %u, %u, %u]", left, top, right, bottom);
}
inline void clear() {
@@ -154,22 +156,21 @@ protected:
};
struct Object {
-
byte id; //0
Rect rect; //1
- Rect actor_rect; //9
- byte actor_orientation; //17
+ Rect actorRect; //9
+ byte actorOrientation; //17
byte enabled; //18
//19
Common::String name, description;
Object(): _base(NULL) {}
void dump(int level = 0) const;
- void setName(const Common::String &name);
+ void setName(const Common::String &newName);
void load(byte *addr);
void save() const;
- static Common::String parse_description(const char *name);
+ static Common::String parseDescription(const char *name);
protected:
byte *_base;
@@ -188,10 +189,10 @@ protected:
};
struct UseHotspot {
- byte inventory_id;
- byte object_id;
+ byte inventoryId;
+ byte objectId;
byte orientation;
- uint16 actor_x, actor_y;
+ uint16 actorX, actorY;
uint16 callback;
void load(byte *src);
void dump(int level = 0) const;
@@ -201,7 +202,7 @@ struct Walkbox {
byte type;
byte orientation;
Rect rect;
- byte side_hint[4];
+ byte sideHint[4];
Walkbox() : _base(NULL) {}
void dump(int level = 0) const;
diff --git a/engines/teenagent/pack.cpp b/engines/teenagent/pack.cpp
index 5302e2eceb..2e6c913a72 100644
--- a/engines/teenagent/pack.cpp
+++ b/engines/teenagent/pack.cpp
@@ -20,6 +20,8 @@
*/
#include "teenagent/pack.h"
+#include "teenagent/teenagent.h"
+
#include "common/util.h"
#include "common/debug.h"
#include "common/memstream.h"
@@ -44,7 +46,7 @@ bool FilePack::open(const Common::String &filename) {
return false;
_fileCount = file.readUint32LE();
- debug(0, "opened %s, found %u entries", filename.c_str(), _fileCount);
+ debugC(0, kDebugPack, "opened %s, found %u entries", filename.c_str(), _fileCount);
offsets = new uint32[_fileCount + 1];
for (uint32 i = 0; i <= _fileCount; ++i) {
offsets[i] = file.readUint32LE();
@@ -65,18 +67,17 @@ uint32 FilePack::read(uint32 id, byte *dst, uint32 size) const {
file.seek(offsets[id - 1]);
uint32 rsize = offsets[id] - offsets[id - 1];
uint32 r = file.read(dst, MIN(rsize, size));
- //debug(0, "read(%u, %u) = %u", id, size, r);
+ debugC(0, kDebugPack, "read(%u, %u) = %u", id, size, r);
return r;
}
Common::SeekableReadStream *FilePack::getStream(uint32 id) const {
if (id < 1 || id > _fileCount)
return NULL;
- //debug(0, "stream: %04x-%04x", offsets[id - 1], offsets[id]);
+ debugC(0, kDebugPack, "stream: %04x-%04x", offsets[id - 1], offsets[id]);
return new Common::SeekableSubReadStream(&file, offsets[id - 1], offsets[id]);
}
-
TransientFilePack::TransientFilePack() : offsets(0) {}
TransientFilePack::~TransientFilePack() {
@@ -97,7 +98,7 @@ bool TransientFilePack::open(const Common::String &filename) {
return false;
_fileCount = file.readUint32LE();
- debug(0, "opened %s, found %u entries", filename.c_str(), _fileCount);
+ debugC(0, kDebugPack, "opened %s, found %u entries", filename.c_str(), _fileCount);
offsets = new uint32[_fileCount + 1];
for (uint32 i = 0; i <= _fileCount; ++i) {
offsets[i] = file.readUint32LE();
@@ -124,14 +125,14 @@ uint32 TransientFilePack::read(uint32 id, byte *dst, uint32 size) const {
uint32 rsize = offsets[id] - offsets[id - 1];
uint32 r = file.read(dst, MIN(rsize, size));
file.close();
- //debug(0, "read(%u, %u) = %u", id, size, r);
+ debugC(0, kDebugPack, "read(%u, %u) = %u", id, size, r);
return r;
}
Common::SeekableReadStream *TransientFilePack::getStream(uint32 id) const {
if (id < 1 || id > _fileCount)
return NULL;
- //debug(0, "stream: %04x-%04x", offsets[id - 1], offsets[id]);
+ debugC(0, kDebugPack, "stream: %04x-%04x", offsets[id - 1], offsets[id]);
Common::File file;
if (!file.open(_filename))
return NULL;
@@ -146,7 +147,6 @@ Common::SeekableReadStream *TransientFilePack::getStream(uint32 id) const {
return new Common::MemoryReadStream(ptr, r, DisposeAfterUse::YES);
}
-
void MemoryPack::close() {
chunks.clear();
}
@@ -157,7 +157,7 @@ bool MemoryPack::open(const Common::String &filename) {
return false;
uint32 count = file.readUint32LE();
- debug(0, "opened %s, found %u entries [memory]", filename.c_str(), count);
+ debugC(0, kDebugPack, "opened %s, found %u entries [memory]", filename.c_str(), count);
for (uint32 i = 0; i < count; ++i) {
uint32 offset = file.readUint32LE();
int32 pos = file.pos();
@@ -199,5 +199,4 @@ Common::SeekableReadStream *MemoryPack::getStream(uint32 id) const {
return new Common::MemoryReadStream(c.data, c.size, DisposeAfterUse::NO);
}
-
} // End of namespace TeenAgent
diff --git a/engines/teenagent/resources.cpp b/engines/teenagent/resources.cpp
index dff58f98e2..442d0abf16 100644
--- a/engines/teenagent/resources.cpp
+++ b/engines/teenagent/resources.cpp
@@ -27,14 +27,10 @@
namespace TeenAgent {
-Resources::Resources() {}
-
-Resources *Resources::instance() {
- static Resources i;
- return &i;
+Resources::Resources() {
}
-void Resources::deinit() {
+Resources::~Resources() {
off.close();
on.close();
ons.close();
@@ -61,6 +57,36 @@ quick note on varia resources:
11: quit shareware
*/
+#define CSEG_SIZE 46000 // 0xb3b0
+#define DSEG_SIZE 59280 // 0xe790
+#define ESEG_SIZE 35810 // 0x8be2
+
+void Resources::precomputeDialogOffsets() {
+ dialogOffsets.push_back(0);
+ int n = 0;
+ uint8 current, last = 0xff;
+ for (uint i = 0; i < eseg.size(); i++) {
+ current = eseg.get_byte(i);
+
+ if (n == 4) {
+ dialogOffsets.push_back(i);
+ n = 0;
+ }
+
+ if (current != 0x00 && last == 0x00)
+ n = 0;
+
+ if (current == 0x00)
+ n++;
+
+ last = current;
+ }
+
+ debug(1, "Resources::precomputeDialogOffsets() - Found %d dialogs", dialogOffsets.size());
+ for (uint i = 0; i < dialogOffsets.size(); i++)
+ debug(1, "\tDialog #%d: Offset 0x%04x", i, dialogOffsets[i]);
+}
+
bool Resources::loadArchives(const ADGameDescription *gd) {
Common::File *dat_file = new Common::File();
if (!dat_file->open("teenagent.dat")) {
@@ -93,18 +119,17 @@ bool Resources::loadArchives(const ADGameDescription *gd) {
}
#endif
- cseg.read(dat, 0xb3b0);
- dseg.read(dat, 0xe790);
- eseg.read(dat, 0x8be2);
+ dat->skip(CSEG_SIZE);
+ dseg.read(dat, DSEG_SIZE);
+ eseg.read(dat, ESEG_SIZE);
delete dat;
+ precomputeDialogOffsets();
+
FilePack varia;
varia.open("varia.res");
- font7.load(varia, 7);
- font7.width_pack = 1;
- font7.height = 11;
- font8.load(varia, 8);
- font8.height = 31;
+ font7.load(varia, 7, 11, 1);
+ font8.load(varia, 8, 31, 0);
varia.close();
off.open("off.res");
@@ -150,13 +175,13 @@ Common::SeekableReadStream *Resources::loadLan000(uint32 id) const {
switch (id) {
case 81:
- if (dseg.get_byte(0xDBAD))
+ if (dseg.get_byte(dsAddr_dogHasBoneFlag))
return lan500.getStream(160);
break;
case 137:
- if (dseg.get_byte(0xDBC5) == 1) {
- if (dseg.get_byte(0xDBC6) == 1)
+ if (dseg.get_byte(dsAddr_mansionTVOnFlag) == 1) {
+ if (dseg.get_byte(dsAddr_mansionVCRPlayingTapeFlag) == 1)
return lan500.getStream(203);
else
return lan500.getStream(202);
@@ -164,31 +189,31 @@ Common::SeekableReadStream *Resources::loadLan000(uint32 id) const {
break;
case 25:
- if (dseg.get_byte(0xDBDF) == 2) {
+ if (dseg.get_byte(dsAddr_FirstActTrialState) == 2) {
return lan500.getStream(332);
}
break;
case 37:
- if (dseg.get_byte(0xdbe2) == 1) {
+ if (dseg.get_byte(dsAddr_act1GuardState) == 1) {
return lan500.getStream(351);
- } else if (dseg.get_byte(0xdbe2) == 2) {
+ } else if (dseg.get_byte(dsAddr_act1GuardState) == 2) {
return lan500.getStream(364);
}
break;
case 29:
- if (dseg.get_byte(0xDBE7) == 1) {
+ if (dseg.get_byte(dsAddr_birdOnBarRadioAntennaFlag) == 1) {
return lan500.getStream(380);
}
case 30:
- if (dseg.get_byte(0xDBE7) == 1) {
+ if (dseg.get_byte(dsAddr_birdOnBarRadioAntennaFlag) == 1) {
return lan500.getStream(381);
}
case 42:
- if (dseg.get_byte(0xDBEC) == 1) {
+ if (dseg.get_byte(dsAddr_johnNotyOutsideMansionDoorFlag) == 1) {
return lan500.getStream(400);
}
}
diff --git a/engines/teenagent/resources.h b/engines/teenagent/resources.h
index 5c08a46489..7aae2f9ec8 100644
--- a/engines/teenagent/resources.h
+++ b/engines/teenagent/resources.h
@@ -31,18 +31,1144 @@ struct ADGameDescription;
namespace TeenAgent {
+// Code Segment Addresses (Read Only)
+// Intro function : 0x024c
+const uint16 csAddr_intro = 0x024c;
+// Pole Climb Fail function : 0x4173
+const uint16 csAddr_poleClimbFail = 0x4173;
+// Move Ego (Mark) To Suspicious Position function : 0x505c
+const uint16 csAddr_egoSuspiciousPosition = 0x505c;
+// Guard Scare Timeout function : 0x516d
+const uint16 csAddr_guardScareTimeout = 0x516d;
+// Guard Drinking function : 0x5189
+const uint16 csAddr_guardDrinking = 0x5189;
+// Move Ego (Mark) To Default Position function : 0x557e
+const uint16 csAddr_egoDefaultPosition = 0x557e;
+// Cave NOP function : 0x599b
+const uint16 csAddr_caveNOP = 0x599b;
+// Enter Cave function : 0x5a21
+const uint16 csAddr_enterCave = 0x5a21;
+// Ego (Mark) Scared By Spider function : 0x60b5
+const uint16 csAddr_egoScaredBySpider = 0x60b5;
+// Move to Ladder and Leave Cellar function : 0x60d9
+const uint16 csAddr_moveToLadderAndLeaveCellar = 0x60d9;
+// Leave Cellar function : 0x612b
+const uint16 csAddr_leaveCellar = 0x612b;
+// Too Dark function : 0x61fe
+const uint16 csAddr_TooDark = 0x61fe;
+// Move Ego (Mark) To Bottom-Right or Turn function : 0x6849
+const uint16 csAddr_egoBottomRightTurn = 0x6849;
+// Checking Drawers function : 0x68e6
+const uint16 csAddr_checkingDrawers = 0x68e6;
+// Drawer Open Message function : 0x6b86
+const uint16 csAddr_DrawerOpenMessage = 0x6b86;
+// Is Cook Gone function : 0x70e0
+const uint16 csAddr_isCookGone = 0x70e0;
+// Giving Flower to Old Lady function : 0x88de
+const uint16 csAddr_givingFlowerToOldLady = 0x88de;
+// Give Another Flower to Old Lady function : 0x890b
+const uint16 csAddr_giveAnotherFlowerToOldLady = 0x890b;
+// Giving Flower to Anne function : 0x8942
+const uint16 csAddr_givingFlowerToAnne = 0x8942;
+// Give Another Flower to Anne function : 0x89aa
+const uint16 csAddr_giveAnotherFlowerToAnne = 0x89aa;
+// Putting Rock in Hole function : 0x8d57
+const uint16 csAddr_putRockInHole = 0x8d57;
+// Mouse Out Of Hole Timeout function : 0x8d79
+const uint16 csAddr_mouseOutOfHoleTimeout = 0x8d79;
+// Robot Safe (Mike) Already Unlocked Check function : 0x9166
+const uint16 csAddr_robotSafeAlreadyUnlockedCheck = 0x9166;
+// Robot Safe (Mike) Unlock Check function : 0x9175
+const uint16 csAddr_robotSafeUnlockCheck = 0x9175;
+// Open Full Toolbox function : 0x98fa
+const uint16 csAddr_openFullToolbox = 0x98fa;
+// Open Half Empty Toolbox function : 0x9910
+const uint16 csAddr_openHalfEmptyToolbox = 0x9910;
+// Use Diving Equipment function : 0x9921
+const uint16 csAddr_useDivingEquipment = 0x9921;
+// Successfully Got Anchor function : 0x99e0
+const uint16 csAddr_gotAnchor = 0x99e0;
+// No Anchor Timeout function : 0x9a1d
+const uint16 csAddr_noAnchorTimeout = 0x9a1d;
+// Get Out of Lake function : 0x9a7a
+const uint16 csAddr_getOutOfLake = 0x9a7a;
+// Dig Under Mansion Wall function : 0x9aca
+const uint16 csAddr_digMansionWall = 0x9aca;
+// Too Dark Here function : 0x9c66
+const uint16 csAddr_tooDarkHere = 0x9c66;
+// Examine Banknote function : 0x9c6d
+const uint16 csAddr_examineBanknote = 0x9c6d;
+// Use Time Pills function : 0x9c79
+const uint16 csAddr_useTimePills = 0x9c79;
+// Mansion Intrusion Attempt function : 0x9d45
+const uint16 csAddr_mansionIntrusionAttempt = 0x9d45;
+// Second Mansion Intrusion function : 0x9d90
+const uint16 csAddr_secondMansionIntrusion = 0x9d90;
+// Third Mansion Intrusion function : 0x9de5
+const uint16 csAddr_thirdMansionIntrusion = 0x9de5;
+// Fourth Mansion Intrusion function : 0x9e54
+const uint16 csAddr_fourthMansionIntrusion = 0x9e54;
+// Fifth Mansion Intrusion function : 0x9ec3
+const uint16 csAddr_fifthMansionIntrusion = 0x9ec3;
+// Sixth Mansion Intrusion function : 0x9f3e
+const uint16 csAddr_sixthMansionIntrusion = 0x9f3e;
+// Display Message function : 0xa055
+const uint16 csAddr_displayMsg = 0xa055;
+// Reject Message function : 0xa4d6
+const uint16 csAddr_rejectMsg = 0xa4d6;
+
+// Data Segment Addresses
+// Timed Callback State Variable : 0x0000
+const uint16 dsAddr_timedCallbackState = 0x0000; // 1 byte
+
+// Cursor Graphic 8*12px : 0x00da to 0x0139 (Read Only)
+const uint16 dsAddr_cursor = 0x00da;
+
+// Reject Message Address Pointers : (4 * 2-byte) = 0x339e to 0x33a5
+const uint16 dsAddr_rejectMsgPtr = 0x339e;
+// Reject Message #0 : 0x33a6 to 0x33c9
+const uint16 dsAddr_rejectMsg0 = 0x33a6; // "I have no idea what to do with it"
+// Reject Message #1 : 0x33ca to 0x33f5
+const uint16 dsAddr_rejectMsg1 = 0x33ca; // "I can't imagine what I could do with this"
+// Reject Message #2 : 0x33f6 to 0x3425
+const uint16 dsAddr_rejectMsg2 = 0x33f6; // "I can't figure out what I should do with this"
+// Reject Message #3 : 0x3426 to 0x344f
+const uint16 dsAddr_rejectMsg3 = 0x3426; // "I can't find any reason to mess with it"
+// Cool Message : 0x3450 to 0x3456
+const uint16 dsAddr_coolMsg = 0x3450; // "Cool."
+// Object Usage Error Message : 0x3457 to 0x3467
+const uint16 dsAddr_objErrorMsg = 0x3457; // "That's no good"
+// Car Jack Message : 0x3468 to 0x348f
+const uint16 dsAddr_carJackMsg = 0x3468; // "Wow! There's a car jack inside! Great!"
+// Spanner Message : 0x3490 to 0x34c6
+const uint16 dsAddr_spannerMsg = 0x3490; // "There's something else inside the toolbox! A spanner!"
+// Last Chance Message : 0x34c7 to 0x34d4
+const uint16 dsAddr_lastChanceMsg = 0x34c7; // "Last chance?"
+// Give Up Message : 0x34d5 to 0x34e0
+const uint16 dsAddr_giveUpMsg = 0x34d5; // "I give up"
+// Avoid Bees Message : 0x34e1 to 0x351e
+const uint16 dsAddr_avoidBeesMsg = 0x34e1; // "I'm going to stay at least five meters away from these bees!"
+// Boat Empty Message : 0x351f to 0x3541
+const uint16 dsAddr_boatEmptyMsg = 0x351f; // "There's nothing else in the boat"
+// Too Hard Wood Message : 0x3542 to 0x3562
+const uint16 dsAddr_tooHardWoodMsg = 0x3542; // "This wood is too hard to break"
+// Boo Message : 0x3563 to 0x3569
+const uint16 dsAddr_BooMsg = 0x3563; // "Booo!"
+// Dont Push Luck Message : 0x356a to 0x358f
+const uint16 dsAddr_dontPushLuckMsg = 0x356a; // "I don't think I should push my luck"
+// Ordinary Haystack Message : 0x3590 to 0x35b1
+const uint16 dsAddr_ordinaryHaystackMsg = 0x3590; // "Just an ordinary hay stack. Now."
+// Needle Haystack Message : 0x35b2 to 0x35e7
+const uint16 dsAddr_needleHaystackMsg = 0x35b2; // "And they say you can't find a needle in a haystack"
+// No Potatoes Message : 0x35e8 to 0x3604
+const uint16 dsAddr_noPotatoMsg = 0x35e8; // "There are no more potatoes"
+// Trousers Message : 0x3605 to 0x363e
+const uint16 dsAddr_trousersMsg = 0x3605; // "Good I always asked mum for trousers with BIG pockets"
+// Life Is Brutal Message : 0x363f to 0x364f
+const uint16 dsAddr_lifeIsBrutalMsg = 0x363f; // "Life is brutal"
+// Life Brutal Message : 0x3650 to 0x3667
+const uint16 dsAddr_lifeBrutalMsg = 0x3650; // "Life is really brutal"
+// Tickled Message : 0x3668 to 0x367e
+const uint16 dsAddr_tickledMsg = 0x3668; // "Something tickled me!"
+// Its Gone Message : 0x367f to 0x3693
+const uint16 dsAddr_itsGoneMsg = 0x367f; // "At least it's gone"
+// Monsters Message : 0x3694 to 0x36c1
+const uint16 dsAddr_monstersMsg = 0x3694; // "Who knows what monsters live in there"
+// No Hands Message : 0x36c2 to 0x370e
+const uint16 dsAddr_noHandsMsg = 0x36c2; // "I'd better not put my hands in there..."
+// Totally Empty Message : 0x370f to 0x372d
+const uint16 dsAddr_totalEmptyMsg = 0x370f; // "I can see it's totally empty"
+// One Small Step Message : 0x372e to 0x3765
+const uint16 dsAddr_oneSmallStepMsg = 0x372e; // "One small step for man, one big pain in the head"
+// No Chance Message : 0x3766 to 0x378f
+const uint16 dsAddr_noChanceMsg = 0x3766; // "I won't take my chances a second time"
+// Dinosaur Bone Message : 0x3790 to 0x37b7
+const uint16 dsAddr_dinoBoneMsg = 0x3790; // "I really hope this is DINOSAUR bone"
+// Wall Shaken Message : 0x37b8 to 0x37e9
+const uint16 dsAddr_wallShakenMsg = 0x37b8; // "Wow! This must have shaken all the nearby walls!"
+// Kinda Dark Message : 0x37ea to 0x3800
+const uint16 dsAddr_kindaDarkMsg = 0x37ea; // "It's kinda dark here"
+// Not in Dark Message : 0x3801 to 0x3831
+const uint16 dsAddr_notInDarkMsg = 0x3801; // "I'm not going to wander here in the dark again"
+// Shut Valve Message : 0x3832 to 0x387b
+const uint16 dsAddr_shutValveMsg = 0x3832; // "Shutting the valve shook the dirt from the wall..."
+// Need Sunglasses Message : 0x387c to 0x38a6
+const uint16 dsAddr_needSunglassesMsg = 0x387c; // "Sorry buddy, but I need your sunglasses"
+// Not Best Place Message : 0x38a7 to 0x38cd
+const uint16 dsAddr_notBestPlaceMsg = 0x38a7; // "It's not the best place for diving"
+// Not Here Message : 0x38ce to 0x38da
+const uint16 dsAddr_notHereMsg = 0x38ce; // "Not here"
+// Can't Talk Underwater Message : 0x38db to 0x38fe
+const uint16 dsAddr_cantTalkUnderwaterMsg = 0x38db; // "I really can't talk underwater!"
+// Not Swimming There Message : 0x38ff to 0x3931
+const uint16 dsAddr_notSwimmingThereMsg = 0x38ff; // "I don't think swimming there is worth the effort"
+// Too Little Air Message : 0x3932 to 0x3988
+const uint16 dsAddr_tooLittleAirMsg = 0x3932; // "If I want to get this anchor I have to swim there when I have more air in my lungs"
+// Hooked Anchor Message : 0x3989 to 0x39ad
+const uint16 dsAddr_hookedAnchorMsg = 0x3989; // "I was really hooked on this anchor!"
+// Seaweed Message : 0x39ae to 0x39f5
+const uint16 dsAddr_seaweedMsg = 0x39ae; // "This seaweed is just like the flowers I gave mum on her last birthday"
+// Fish Boat Message : 0x39f6 to 0x3a27
+const uint16 dsAddr_fishBoatMsg = 0x39f6; // "I wonder what fish do inside this boat at night"
+// Fish Something Message : 0x3a28 to 0x3a59
+const uint16 dsAddr_fishSomethingMsg = 0x3a28; // "I think I have to fish out something down there"
+// Fish Don't Worry Message : 0x3a5a to 0x3a84
+const uint16 dsAddr_fishDontWorryMsg = 0x3a5a; // "At least fish don't worry about the rain"
+// Not Red Herring Message : 0x3a85 to 0x3ab6
+const uint16 dsAddr_notRedHerringMsg = 0x3a85; // "I hope all this fish stuff is not a red herring"
+// Nice Down Message : 0x3ab7 to 0x3acd
+const uint16 dsAddr_niceDownMsg = 0x3ab7; // "It's nice down there"
+// Hey Let Go Message : 0x3ace to 0x3ae5
+const uint16 dsAddr_heyLetGoMsg = 0x3ace; // "Hey, let go, will ya?!"
+// Aaahhh Message : 0x3ae6 to 0x3afc
+const uint16 dsAddr_aaahhhMsg = 0x3ae6; // "Aaaaaaaaaaaaahhh!"
+// Oops Message : 0x3afd to 0x3b03
+const uint16 dsAddr_oopsMsg = 0x3afd; // "Oops"
+// Found Food Message : 0x3b04 to 0x3b2e
+const uint16 dsAddr_foundFoodMsg = 0x3b04; // "People leave food in unbelievable places"
+// Come Here Message : 0x3b2f to 0x3b58
+const uint16 dsAddr_comeHereMsg = 0x3b2f; // "Come here, I've got something for you"
+// Cant Catch Message : 0x3b59 to 0x3b6b
+const uint16 dsAddr_cantCatchMsg = 0x3b59; // "I can't catch it!"
+// Trapped Mouse Message : 0x3b6c to 0x3b82
+const uint16 dsAddr_trappedMouseMsg = 0x3b6c; // "The mouse is trapped!"
+// Yikes Message : 0x3b83 to 0x3b8a
+const uint16 dsAddr_yikesMsg = 0x3b83; // "Yikes!"
+// Mouse Nerve Message : 0x3b8b to 0x3bab
+const uint16 dsAddr_mouseNerveMsg = 0x3b8b; // "Boy, this mouse has some nerve!"
+// Drawers Empty Message : 0x3bac to 0x3bd1
+const uint16 dsAddr_drawersEmptyMsg = 0x3bac; // "There's nothing else in the drawers"
+// Rid Bush Message 0x3bd2 to 0x3bf5
+const uint16 dsAddr_ridBushMsg = 0x3bd2; // "I must get rid of this bush first"
+// Mouse Gone Message : 0x3bf6 to 0x3c0a
+const uint16 dsAddr_mouseGoneMsg = 0x3bf6; // "The mouse has gone!"
+// Nonsense Message : 0x3c0b to 0x3c15
+const uint16 dsAddr_nonsenseMsg = 0x3c0b; // "Nonsense"
+// Good Doggy Message : 0x3c16 to 0x3c30
+const uint16 dsAddr_goodDoggyMsg = 0x3c16; // "I understand. Good doggy"
+// Here Boy Message : 0x3c31 to 0x3c3c
+const uint16 dsAddr_hereBoyMsg = 0x3c31; // "Here, boy"
+// Friends Now Message : 0x3c3d to 0x3c57
+const uint16 dsAddr_friendsNowMsg = 0x3c3d; // "I hope we're friends now"
+// Not Think Right Place Message : 0x3c58 to 0x3c7f
+const uint16 dsAddr_notThinkRightPlaceMsg = 0x3c58; // "I don't think this is the right place"
+// Cutscene Message A : 0x3c80 to 0x3c99
+const uint16 dsAddr_cutsceneMsgA = 0x3c80; // "Hundred moments later"
+// Cutscene Message B : 0x3c9a to 0x3cbb
+const uint16 dsAddr_cutsceneMsgB = 0x3c9a; // "Another hundred moments later"
+// Found Crude Oil Message : 0x3cbc to 0x3ce9
+const uint16 dsAddr_foundCrudeOilMsg = 0x3cbc; // "At least I found crude oil and I'll be rich"
+// My Life Message : 0x3cea to 0x3cfa
+const uint16 dsAddr_myLifeMsg = 0x3cea; // "That's my life"
+// Confusion Message : 0x3cfb to 0x3d00
+const uint16 dsAddr_ConfusionMsg = 0x3cfb; // "!?&!"
+// Grandpa Promise Message : 0x3d01 to 0x3d1f
+const uint16 dsAddr_grandpaPromiseMsg = 0x3d01; // "But grandpa, you promised!"
+// Oh Lets Go Message : 0x3d20 to 0x3d39
+const uint16 dsAddr_ohLetsGoMsg = 0x3d20; // "Oh all right. Let's go"
+// Bye Message : 0x3d3a to 0x3d3f
+const uint16 dsAddr_byeMsg = 0x3d3a; // "Bye."
+// No Need Message : 0x3d40 to 0x3d58
+const uint16 dsAddr_noNeedMsg = 0x3d40; // "No need to do it again"
+// Girl Talk Message : 0x3d59 to 0x3d85
+const uint16 dsAddr_girlTalkMsg = 0x3d59; // "I really don't know how to talk to girls"
+// Dont Work Purpose Message : 0x3d86 to 0x3dae
+const uint16 dsAddr_dontWorkPurposeMsg = 0x3d86; // "I usually don't work without a purpose"
+// Nut Real Message : 0x3daf to 0x3dc5
+const uint16 dsAddr_nutRealMsg = 0x3daf; // "Only the nut is real"
+// Hen Fly Message : 0x3dc6 to 0x3df3
+const uint16 dsAddr_henFlyMsg = 0x3dc6; // "I wonder if hens can fly. Come here, baby"
+// First Test Fail Message : 0x3df4 to 0x3e07
+const uint16 dsAddr_firstTestFailMsg = 0x3df4; // "First test failed"
+// Rid Frustations Message : 0x3e08 to 3e30
+const uint16 dsAddr_ridFrustationsMsg = 0x3e08; // "I'd already got rid of my frustrations"
+// Road Nowhere Message : 0x3e31 to 0x3e4e
+const uint16 dsAddr_roadNowhereMsg = 0x3e31; // "Nah. It's a road to nowhere"
+// Open Boot Message 0x3e4f to 0x3e62
+const uint16 dsAddr_openBootMsg = 0x3e4f; // "It opens the boot"
+// Shut Tight Message : 0x3e63 to 0x3e74
+const uint16 dsAddr_shutTightMsg = 0x3e63; // "It's shut tight"
+// Boot Empty Message : 0x3e75 to 0x3e97
+const uint16 dsAddr_bootEmptyMsg = 0x3e75; // "There's nothing else in the boot"
+// Clothes Dry Message : 0x3e98 to 0x3eb1
+const uint16 dsAddr_clothesDryMsg = 0x3e98; // "The clothes are dry now."
+// Crow Kill Message : 0x3eb2 to 0x3ed5
+const uint16 dsAddr_crowKillMsg = 0x3eb2; // "I'm sure these crows will kill me"
+// Get Rid Of Guard First Message : 0x3ed6 to 0x3f29
+const uint16 dsAddr_getRidOfGuardFirstMsg = 0x3ed6; // "If I want to get inside I must get rid of this guard first..."
+// Wall Too Smooth Message : 0x3f2a to 0x3f53
+const uint16 dsAddr_wallTooSmoothMsg = 0x3f2a; // "The wall surface is too smooth to climb"
+// Too Much Resin To Climb Message : 0x3f54 to 0x3f84
+const uint16 dsAddr_tooMuchResinToClimbMsg = 0x3f54; // "I could climb it if there wasn't so much resin"
+// Only Green Rect Message : 0x3f85 to 0x3feb
+const uint16 dsAddr_onlyGreenRectMsg = 0x3f85; // "The only green stuff that I like is that rectangular piece of paper with..."
+// Don't Wanna Touch Hedgehog Message : 0x3fec to 0x402d
+const uint16 dsAddr_dontWannaTouchHedgehogMsg = 0x3fec; // "I don't wanna touch it. Its spines could hurt my delicate hands"
+// Not Hungry Message : 0x402e to 0x4046
+const uint16 dsAddr_notHungryMsg = 0x402e; // "Thanks, I'm not hungry"
+// No Long Hands Message : 0x4047 to 0x406c
+const uint16 dsAddr_noLongHandsMsg = 0x4047; // "I really don't have such long hands"
+// Too Far To Swim Message : 0x406d to 0x4089
+const uint16 dsAddr_tooFarToSwimMsg = 0x406d; // "It's too far to swim there"
+// Echo Message : 0x408a to 0x4090
+const uint16 dsAddr_echoMsg = 0x408a; // "Echo!"
+// Loud Echo Message : 0x4091 to 0x4097
+const uint16 dsAddr_loudEchoMsg = 0x4091; // "ECHO!"
+// Who There Message : 0x4098 to 0x40a6
+const uint16 dsAddr_whoThereMsg = 0x4098; // "Who's there?!"
+// Loud Who There Message : 0x40a7 to 0x40b5
+const uint16 dsAddr_loudWhoThereMsg = 0x40a7; // "WHO'S THERE?!"
+// Dont Copy Message : 0x40b6 to 0x40cd
+const uint16 dsAddr_dontCopyMsg = 0x40b6; // "DON'T COPY ME!"
+// Loud Dont Copy Message : 0x40ce to 0x40e7
+const uint16 dsAddr_loudDontCopyMsg = 0x40ce; // "DON'T COPY ME!!!"
+// Throw Rock Message : 0x40e8 to 0x410e
+const uint16 dsAddr_throwRockMsg = 0x40e8; // "OR I WILL THROW A ROCK DOWN THERE!"
+// Or I Will Message : 0x410f to 0x411c
+const uint16 dsAddr_orIWillMsg = 0x410f; // "OR I WILL"
+// Still There Message : 0x411d to 0x4132
+const uint16 dsAddr_stillThereMsg = 0x411d; // "Are you still there?"
+// No Bucket Message : 0x4133 to 0x4163
+const uint16 dsAddr_noBucketMsg = 0x4133; // "It's not a barrel-organ. And there's no bucket."
+// Dont Need To Open Message : 0x4164 to 0x417d
+const uint16 dsAddr_dontNeedToOpenMsg = 0x4164; // "I don't need to open it"
+// Hmm Grass Message : 0x417e to 41b0
+const uint16 dsAddr_hmmGrassMsg = 0x417e; // "Hmmm. Grass..."
+// Find Nut Message : 0x41b1 to 0x41ee
+const uint16 dsAddr_findNutMsg = 0x41b1; // "I won't find the nut just like that. The grass is too dense"
+// Not Horny Message : 0x41ef to 0x41fe
+const uint16 dsAddr_notHornyMsg = 0x41ef; // "I'm not horny"
+// Can't Jump So High Message : 0x41ff to 0x423e
+const uint16 dsAddr_CantJumpMsg = 0x41ff; // "No way I can jump so high, cause, err, white men can't jump"
+// Don't Need It Message : 0x423f to 0x4250
+const uint16 dsAddr_dontNeedItMsg = 0x423f; // "I don't need it"
+// Not Santa Claus Message : 0x4251 to 0x4266
+const uint16 dsAddr_notSantaClausMsg = 0x4251; // "I'm not Santa Claus"
+// No Plastic Imitations Message : 0x4267 to 0x4288
+const uint16 dsAddr_noPlasticImitationsMsg = 0x4267; // "I don't need plastic imitations"
+// Too Fragile Message : 0x4289 to 0x42ab
+const uint16 dsAddr_tooFragileMsg = 0x4289; // "It's too fragile to carry around"
+// Keep It Open Message : 0x42ac to 0x42c6
+const uint16 dsAddr_keepItOpenMsg = 0x42ac; // "I'd like to keep it open"
+// Not Taking Socks Message : 0x42c7 to 0x4305
+const uint16 dsAddr_notTakingSocksMsg = 0x42c7; // "I really don't want to walk around with someone else's socks"
+// Not Tired Message : 0x4306 to 0x431d
+const uint16 dsAddr_notTiredMsg = 0x4306; // "Thanks, I'm not tired"
+// Too Big Message : 0x431e to 0x434d
+const uint16 dsAddr_tooBigMsg = 0x431e; // "It's too big and I doubt if I'll ever need it"
+// No Secret Passage Message : 0x434e to 0x437f
+const uint16 dsAddr_noSecretPassageMsg = 0x434e; // "I don't think there's any secret passage inside"
+// No Fruit Message : 0x4380 to 0x43ab
+const uint16 dsAddr_noFruitMsg = 0x4380; // "There are no more interesting fruits here"
+// Jug Me Message : 0x43ac to 0x43cd
+const uint16 dsAddr_jugMeMsg = 0x43ac; // "They can jug me if I steal this"
+// Leave Flowers Alone Message : 0x43ce to 0x4411
+const uint16 dsAddr_leaveFlowersAloneMsg = 0x43ce; // "I'd better leave it. Women are really oversensitive about flowers."
+// Mirror Mirror Message : 0x4412 to 0x444e
+const uint16 dsAddr_mirrorMirrorMsg = 0x4412; // "Mirror, Mirror on the wall...."
+// Think Too Long Message : 0x444f to 0x446a
+const uint16 dsAddr_thinkTooLongMsg = 0x444f; // "Hey, don't think too long"
+// Hint Male Message : 0x446b to 0x4491
+const uint16 dsAddr_HintMaleMsg = 0x446b; // "A hint: Someone in this room, a male"
+// OK Wait Message : 0x4492 to 0x44a6
+const uint16 dsAddr_okWaitMsg = 0x4492; // "OK, take your time"
+// Busy Thinking Message : 0x44a7 to 0x44d5
+const uint16 dsAddr_busyThinkingMsg = 0x44a7; // "I'd better not interrupt it's thought process"
+// No Dentists Message : 0x44d6 to 0x450d
+const uint16 dsAddr_noDentistsMsg = 0x44d6; // "I don't want to have anything in common with dentists"
+// Too Heavy Message : 0x450e to 0x4531
+const uint16 dsAddr_tooHeavyMsg = 0x450e; // "It's too heavy. Not that I'm wimp"
+// What Got Message : 0x4532 to 0x4554
+const uint16 dsAddr_whatGotMsg = 0x4532; // "Let's look what we've got here"
+// Strawberry Jam Message : 0x4555 to 0x4567
+const uint16 dsAddr_strawberryJamMsg = 0x4555; // "Strawberry jam"
+// Gooseberry Jam Message : 0x4568 to 0x457a
+const uint16 dsAddr_gooseberryJamMsg = 0x4568; // "Gooseberry jam"
+// Blackberry Jam Message : 0x457b to 0x458d
+const uint16 dsAddr_blackberryJamMsg = 0x457b; // "Blackberry jam"
+// Bilberry Jam Message : 0x458e to 0x459e
+const uint16 dsAddr_bilberryJamMsg = 0x458e; // "Bilberry jam"
+// Get Me Out Jam Message : 0x459f to 0x45b7
+const uint16 dsAddr_getMeOutJamMsg = 0x459f; // "Get me out of this jam!"
+// Rosemary Jam Message : 0x45b8 to 0x45d9
+const uint16 dsAddr_rosemaryJamMsg = 0x45b8; // "Oh, and there is Rosemary jam"
+// Know Rosemary Message : 0x45da to 0x4602
+const uint16 dsAddr_knowRosemaryMsg = 0x45da; // "I used to know someone called Rosemary"
+// Unwanted Jams Message : 0x4603 to 0x461c
+const uint16 dsAddr_unwantedJamsMsg = 0x4603; // "I don't want those jams"
+// Too Dark Message : 0x461d to 0x463b
+const uint16 dsAddr_TooDarkMsg = 0x461d; // "It's too dark to see clearly"
+// Yeow Message : 0x463c to 0x4649
+const uint16 dsAddr_yeowMsg = 0x463c; // "YEEEOOOWWWW!"
+// Yawn Message : 0x464a to 0x4651
+const uint16 dsAddr_yawnMsg = 0x464a; // "(yawn)"
+// Laughter Message : 0x4652 to 0x465d
+const uint16 dsAddr_laughterMsg = 0x4652; // "(laughter)"
+// No Hands Sharp Thorns Message : 0x465e to 0x46a0
+const uint16 dsAddr_noHandsSharpThornsMsg = 0x465e; // "I can't remove it with my hands. these thorns look really sharp"
+// No Chainsaw Fuel Message : 0x46a1 to 0x46c2
+const uint16 dsAddr_noChainsawFuelMsg = 0x46a1; // "There's no fuel in the chainsaw"
+// Thorns Too Thin Message : 0x46c3 to 0x46f6
+const uint16 dsAddr_thornsTooThinMsg = 0x46c3; // "Thorns are too thin, the chainsaw is useless here"
+// Rock Walking Gee Message : 0x46f7 to 0x473c
+const uint16 dsAddr_rockWalkingGeeMsg = 0x46f7; // "Yeah, great idea. Let's take this rock and walk around a bit. Gee..."
+// Butterfly Message : 0x473d to 0x477a
+const uint16 dsAddr_butterflyMsg = 0x473d; // "I'd better leave them alone, they make this place beautiful"
+// Not Sure If Alive Message : 0x477b to 0x4797
+const uint16 dsAddr_notSureIfAliveMsg = 0x477b; // "I'm not sure if it's alive"
+
+// FIXME - Unknown where this is used.. Talking to SOMETHING...
+// Unknown Language Message : 0x4798 to 0x47be
+const uint16 dsAddr_unknownLanguageMsg = 0x4798; // "I don't know what language it speaks"
+
+// Hole Too Narrow Message : 0x47bf to 0x47e6
+const uint16 dsAddr_holeTooNarrowMsg = 0x47bf; // "The hole is too narrow to fit my hand"
+// Bird Attack Message : 0x47e7 to 0x4807
+const uint16 dsAddr_birdAttackMsg = 0x47e7; // "Hey You! Wake up! Bird attack!"
+// No Search Warrant Message : 0x4808 to 0x4827
+const uint16 dsAddr_noSearchWarrantMsg = 0x4808; // "I don't have a search-warrant"
+// Uninteresting Haystack Message : 0x4828 to 0x485f
+const uint16 dsAddr_uninterestingHaystackMsg = 0x4828; // "I don't see anything interesting about this haystack"
+// More Complicated Message : 0x4860 to 0x4881
+const uint16 dsAddr_moreComplicatedMsg = 0x4860; // "It's more complicated than that"
+// Nut Rake Message : 0x4882 to 0x48be
+const uint16 dsAddr_nutRakeMsg = 0x4882; // "It's pointless, the nut will slip between the rake's teeth"
+// Paddle Broken Message : 0x48bf to 0x48d5
+const uint16 dsAddr_paddleBrokenMsg = 0x48bf; // "The paddle is BROKEN"
+// Branch Not Paddle Message : 0x48d6 to 0x4912
+const uint16 dsAddr_branchNotPaddleMsg = 0x48d6; // "This branch is not a paddle. It doesn't even look like one"
+// Try Somewhere Else Message : 0x4913 to 0x495b
+const uint16 dsAddr_trySomewhereElseMsg = 0x4913; // "I'd better try somewhere else - I suppose this side is heavily guarded"
+// Sharpen Not Pulverize Message : 0x495c to 0x4983
+const uint16 dsAddr_sharpenNotPulverizeMsg = 0x495c; // "I needed to sharpen it, not pulverize"
+// Can't Do Anything Too Dark Message : 0x4984 to 0x49ad
+const uint16 dsAddr_cantDoTooDarkMsg = 0x4984; // "I can't do anything here, it's too dark"
+// Bribe Message : 0x49ae to 0x49d0
+const uint16 dsAddr_BribeMsg = 0x49ae; // "Here, let's make your pocket fat."
+// Bank Note Message : 0x49d1 to 0x4a28
+const uint16 dsAddr_bankNoteMsg = 0x49d1; // "It's a note from some bank..."
+// Show Her Money Message : 0x4a29 to 0x4a5a
+const uint16 dsAddr_showHerMoneyMsg = 0x4a29; // "If I just show her the money, she might take it"
+// Hundred Bucks Message : 0x4a5b to 0x4a6e
+const uint16 dsAddr_hundredBucksMsg = 0x4a5b; // "A hundred bucks!!!"
+// Want Blood Message : 0x4a6f to 0x4a7d
+const uint16 dsAddr_wantBloodMsg = 0x4a6f; // "I want Blood!"
+// Dont Leave Mansion Message : 0x4a7e to 0x4aaf
+const uint16 dsAddr_dontLeaveMansionMsg = 0x4a7e; // "I don't want to leave the mansion, I want blood!"
+// Wimp Message : 0x4ab0 to 0x4acc
+const uint16 dsAddr_WimpMsg = 0x4ab0; // "I'm a pathetic little wimp"
+// Strange Drawer Message : 0x4acd to 0x4b0c
+const uint16 dsAddr_strangeDrawerMsg = 0x4acd; // "Strange, but the drawer is stuck if the next drawer is open"
+// Not Ordinary Drawers Message : 0x4b0d to 0x4b38
+const uint16 dsAddr_notOrdinaryDrawersMsg = 0x4b0d; // "Maybe these are not just ordinary drawers!"
+// Drawer Open Message : 0x4b39 to 0x4b6b
+const uint16 dsAddr_drawerOpenMsg = 0x4b39; // "I cannot open the drawer if the next one is open!"
+// Blue Interior Message 0x4b6c to 0x4b86
+const uint16 dsAddr_blueInteriorMsg = 0x4b6c; // "It's got a blue interior"
+// Red Interior Message : 0x4b87 to 0x4ba0
+const uint16 dsAddr_redInteriorMsg = 0x4b87; // "It's got a red interior"
+// Grey Interior Message : 0x4ba1 to 0x4bbb
+const uint16 dsAddr_greyInteriorMsg = 0x4ba1; // "It's got a grey interior"
+// Green Interior Message : 0x4bbc to 0x4bd7
+const uint16 dsAddr_greenInteriorMsg = 0x4bbc; // "It's got a green interior"
+// Brown Interior Message : 0x4bd8 to 0x4bf3
+const uint16 dsAddr_brownInteriorMsg = 0x4bd8; // "It's got a brown interior"
+// Pink Interior Message : 0x4bf4 to 0x4c0e
+const uint16 dsAddr_pinkInteriorMsg = 0x4bf4; // "It's got a pink interior"
+// Dictaphone Inside Message : 0x4c0f to 0x4c31
+const uint16 dsAddr_dictaphoneInsideMsg = 0x4c0f; // "Wow! There's a dictaphone inside!"
+// Found Polaroid Message : 0x4c32 to 0x4c60
+const uint16 dsAddr_foundPolaroidMsg = 0x4c32; // "There's a polaroid inside! I might need that"
+// Book Held Message : 0x4c61 to 0x4c83
+const uint16 dsAddr_bookHeldMsg = 0x4c61; // "Something's got hold of the book!"
+// Secret Compartment Message : 0x4c84 to 0x4c9f
+const uint16 dsAddr_secretCompartmentMsg = 0x4c84; // "Wow! A secret compartment!"
+// Dont Mess Message : 0x4ca0 to 0x4cc6
+const uint16 dsAddr_dontMessMsg = 0x4ca0; // "I don't need to mess with it anymore"
+// Full Automatic Message : 0x4cc7 to 0x4cd8
+const uint16 dsAddr_fullAutomaticMsg = 0x4cc7; // "Fully Automatic"
+// No More Sheets Message : 0x4cd9 to 0x4d01
+const uint16 dsAddr_noMoreSheetsMsg = 0x4cd9; // "Right now I don't need any more sheets"
+// No Deprave Message : 0x4d02 to 0x4d29
+const uint16 dsAddr_noDepraveMsg = 0x4d02; // "Nah, I don't want to deprave the kids"
+// No Read Again Message : 0x4d2a to 0x4d5a
+const uint16 dsAddr_noReadAgainMsg = 0x4d2a; // "I don't want to read it again. I might like it."
+// TV Off Message : 0x4d5b to 0x4d7f
+const uint16 dsAddr_tvOffMsg = 0x4d5b; // "I just realised that the TV is off"
+// Not Happen Message : 0x4d80 to 0x4d92
+const uint16 dsAddr_NotHappenMsg = 0x4d80; // "Nothing happened"
+// Tape Started Message : 0x4d93 to 0x4da5
+const uint16 dsAddr_tapeStartedMsg = 0x4d93; // "The tape started!"
+// Much Better Message : 0x4da6 to 0x4dba
+const uint16 dsAddr_muchBetterMsg = 0x4da6; // "That's much better"
+// No Sleep Message : 0x4dbb to 0x4dd2
+const uint16 dsAddr_noSleepMsg = 0x4dbb; // "I don't want to sleep"
+// Just Cork Message : 0x4dd3 to 0x4de5
+const uint16 dsAddr_justCorkMsg = 0x4dd3; // "It's just a cork"
+// Enough Photos Message : 0x4de6 to 0x4e04
+const uint16 dsAddr_enoughPhotosMsg = 0x4de6; // "I don't need any more photos"
+// Record Scare Message : 0x4e05 to 0x4e31
+const uint16 dsAddr_recordScareMsg = 0x4e05; // "Yeah, I can record this and scare the cats"
+// Already Recorded Message : 0x4e32 to 0x4e57
+const uint16 dsAddr_alreadyRecordedMsg = 0x4e32; // "I already recorded what I wanted to"
+// Can't Record No Batteries Message : 0x4e58 to 0x4e8d
+const uint16 dsAddr_cantRecordNoBatteriesMsg = 0x4e58; // "I can't record anything until I find some batteries"
+
+// FIXME - Not sure how to get this message. Dictaphone with no batteries somewhere? Radio?
+// No Batteries No Fun Message : 0x4e8e to 0x4ea4
+const uint16 dsAddr_NoBatteriesNoFunMsg = 0x4e8e; // "No batteries, no fun"
+
+// Not Right Moment Message : 0x4ea5 to 0x4ecd
+const uint16 dsAddr_notRightMomentMsg = 0x4ea5; // "I don't think this is the right moment"
+// Cook Around Message : 0x4ece to 0x4ef9
+const uint16 dsAddr_cookAroundMsg = 0x4ece; // "I can't do anything with this cook around"
+// Same Bottle Message : 0x4efa to 0x4f3c
+const uint16 dsAddr_sameBottleMsg = 0x4efa; // "The bottle's the same, but I doubt if it's enough to fool anyone"
+// Break Flatten Message : 0x4f3d to 0x4f68
+const uint16 dsAddr_breakFlattenMsg = 0x4f3d; // "I wanted to break it, not to flatten it!"
+// What Inside Message : 0x4f69 to 0x4f9a
+const uint16 dsAddr_whatInsideMsg = 0x4f69; // "I was always curious what's inside these things"
+// Rest Useless Message : 0x4f9b to 0x4fb0
+const uint16 dsAddr_restUselessMsg = 0x4f9b; // "The rest is useless"
+// Two Batteries Message : 0x4fb1 to 0x4fca
+const uint16 dsAddr_twoBatteriesMsg = 0x4fb1; // "Wow! Two 1.5V batteries!"
+// One Taken Message : 0x4fcb to 0x4fe1
+const uint16 dsAddr_oneTakenMsg = 0x4fcb; // "This one's taken, OK?"
+// Slight Mad Message : 0x4fe2 to 0x5009
+const uint16 dsAddr_slightMadMsg = 0x4fe2; // "It finally happened. I'm slightly mad"
+// Paper Burnt Message : 0x500a to 0x502a
+const uint16 dsAddr_paperBurntMsg = 0x500a; // "The paper burnt out completely!"
+// Burn Baby Message : 0x502b to 0x503d
+const uint16 dsAddr_burnBabyMsg = 0x502b; // "Burn, baby, burn!"
+// Voila Message : 0x503e to 0x5045
+const uint16 dsAddr_voilaMsg = 0x503e; // "Voila"
+// Too Hot Message : 0x5046 to 0x505d
+const uint16 dsAddr_tooHotMsg = 0x5046; // "It's too hot to touch!"
+// Frozen Shelf Message : 0x505e to 0x5081
+const uint16 dsAddr_frozenShelfMsg = 0x505e; // "It has frozen hard onto the shelf!"
+// Yummy Message : 0x5082 to 0x5089
+const uint16 dsAddr_yummyMsg = 0x5082; // "Yummy"
+// Dislike Veal Message : 0x508a to 0x50a5
+const uint16 dsAddr_dislikeVealMsg = 0x508a; // "I never liked veal anyway"
+// No Reason Message : 0x50a6 to 0x50c2
+const uint16 dsAddr_noReasonMsg = 0x50a6; // "There's no reason to do it"
+// Fooled Once Message : 0x50c3 to 0x50e0
+const uint16 dsAddr_fooledOnceMsg = 0x50c3; // "I'd already fooled him once"
+// Mike Voice Test Message : 0x50e1 to 0x5100
+const uint16 dsAddr_mikeVoiceTestMsg = 0x50e1; // "Mike, activate the voice test"
+// Not My Voice Message : 0x5101 to 0x5123
+const uint16 dsAddr_notMyVoiceMsg = 0x5101; // "I won't cheat Mike with MY voice"
+// Singing Message : 0x5124 to 0x5137
+const uint16 dsAddr_singingMsg = 0x5124; // "siiiiinging!"
+// Mike Scent Test Message : 0x5138 to 0x5160
+const uint16 dsAddr_mikeScentTestMsg = 0x5138; // "Mike, let's get on with the scent test"
+// Mike View Test Message : 0x5161 to 0x517a
+const uint16 dsAddr_mikeViewTestMsg = 0x5161; // "Mike, run the view test"
+// Cutscene Message #0 : 0x517b to 0x51a6
+const uint16 dsAddr_cutsceneMsg0 = 0x517b; // "A secret diary of ..."
+// Cant Hide Message : 0x51a7 to 0x51ba
+const uint16 dsAddr_cantHideMsg = 0x51a7; // "I can't hide here!"
+// John Outside Message : 0x51bb to 0x51e6
+const uint16 dsAddr_johnOutsideMsg = 0x51bb; // "There's John Noty outside! I can't go out!"
+// Was Close Message : 0x51e7 to 0x51f7
+const uint16 dsAddr_wasCloseMsg = 0x51e7; // "That was close"
+// Cork In Hole Message : 0x51f8 to 0x5217
+const uint16 dsAddr_corkInHoleMsg = 0x51f8; // "The cork is stuck in the hole"
+// Fits Perfect Message : 0x5218 to 0x522b
+const uint16 dsAddr_fitsPerfectMsg = 0x5218; // "It fits perfectly!"
+// Enough Water Message : 0x522c to 0x524e
+const uint16 dsAddr_enoughWaterMsg = 0x522c; // "There's enough water in the sink"
+// No Hot Water Message : 0x524f to 0x5271
+const uint16 dsAddr_noHotWaterMsg = 0x524f; // "There's no hot water in the sink"
+// Label Off Message : 0x5272 to 0x528a
+const uint16 dsAddr_labelOffMsg = 0x5272; // "The label has come off!"
+// Cork Too Small Message : 0x528b to 0x52a8
+const uint16 dsAddr_corkTooSmallMsg = 0x528b; // "The cork is a bit too small"
+// Not Try Now Message : 0x52a9 to 0x52ca
+const uint16 dsAddr_notTryNowMsg = 0x52a9; // "There's no need to try them now"
+// No Salad Message : 0x52cb to 0x52f5
+const uint16 dsAddr_noSaladMsg = 0x52cb; // "I don't want to turn myself into a salad"
+// Nah Message : 0x52f6 to 0x52fd
+const uint16 dsAddr_nahMsg = 0x52f6; // "Nah"
+// Vent First Message : 0x52fe to 0x5325
+const uint16 dsAddr_ventFirstMsg = 0x52fe; // "I'd better stop this ventilator first"
+// Catch John First Message : 0x5326 to 0x5348
+const uint16 dsAddr_catchJohnFirstMsg = 0x5326; // "I'd better catch John Noty first"
+// Only Chilli Message : 0x5349 to 0x5371
+const uint16 dsAddr_onlyChilliMsg = 0x5349; // "Good this red stuff is only a chilli"
+// Water Hot Message : 0x5372 to 0x538c
+const uint16 dsAddr_waterHotMsg = 0x5372; // "The water looks very hot"
+// Sink Full Message : 0x538d to 0x53ac
+const uint16 dsAddr_sinkFullMsg = 0x538d; // "The sink is full of hot water"
+// No Sock Store Message : 0x53ad to 0x53dc
+const uint16 dsAddr_noSockStoreMsg = 0x53ad; // "I don't have anything to store these socks in"
+// Show Papers Message : 0x53dd to 0x53f1
+const uint16 dsAddr_showPapersMsg = 0x53dd; // "Here are my papers"
+// Got Permission Message : 0x53f2 to 0x5410
+const uint16 dsAddr_gotPermissionMsg = 0x53f2; // "I already got the permission"
+// Saving Fine Message : 0x5411 to 0x5462
+const uint16 dsAddr_SavingFineMsg = 0x5411; // "Saving is a very fine thing..."
+// Love Captain Message : 0x5463 to 0x5474
+const uint16 dsAddr_loveCaptainMsg = 0x5463; // "I love captain"
+// Soccer Rulz Message : 0x5475 to 0x5483
+const uint16 dsAddr_soccerRulzMsg = 0x5475; // "Soccer rulz"
+// Tree Cut Message : 0x5484 to 0x54c3
+const uint16 dsAddr_treeCutMsg = 0x5484; // "Don't cut the trees..."
+// Visa Accepted Message : 0x54c4 to 0x54d4
+const uint16 dsAddr_visaAcceptedMsg = 0x54c4; // "VISA Accepted"
+// Other Graffiti Message : 0x54d5 to 0x54f6
+const uint16 dsAddr_otherGraffitiMsg = 0x54d5; // "The rest of graffiti is obscene"
+// First Trial Message : 0x54f7 to 0x5510
+const uint16 dsAddr_firstTrialMsg = 0x54f7; // "Sir, I'm Mark. A rookie"
+// Locked Message : 0x5511 to 0x551e
+const uint16 dsAddr_lockedMsg = 0x5511; // "It's Locked!"
+// Thanks Message : 0x551f to 0x5527
+const uint16 dsAddr_ThanksMsg = 0x551f; // "Thanks."
+// Unknown Usage Message : 0x5528 to 0x555c
+const uint16 dsAddr_unkUsageMsg = 0x5528; // "I don't have any idea what to do with it right now"
+// Idea Message : 0x555d to 0x5576
+const uint16 dsAddr_ideaMsg = 0x555d; // "That gives me an idea"
+// Check Works Message : 0x5577 to 0x5599
+const uint16 dsAddr_checkWorksMsg = 0x5577; // "Now I got to check if it works"
+// Time To Call Message : 0x559a to 0x55bf
+const uint16 dsAddr_timeToCallMsg = 0x559a; // "I think it is time to call captain"
+// Meal Finished Message : 0x55c0 to 0x55da
+const uint16 dsAddr_mealFinishedMsg = 0x55c0; // "Hey! I finished my meal."
+// Bowl Welded Message : 0x55db to 0x55fe
+const uint16 dsAddr_bowlWeldedMsg = 0x55db; // "Wow. He got welded to the bowl"
+// Gotcha Message : 0x55ff to 0x5607
+const uint16 dsAddr_gotchaMsg = 0x55ff; // "Gotcha"
+// No Pocket Message : 0x5608 to 0x5631
+const uint16 dsAddr_noPocketMsg = 0x5608; // "I don't want to touch his pockets again."
+// Does Not Work Message : 0x5632 to 0x5645
+const uint16 dsAddr_doesNotWorkMsg = 0x5632; // "That doesn't work"
+// Message : 0x5646 to 0x5655
+const uint16 dsAddr_fnMsg1 = 0x5646; // "Piece of cake"
+// Message : 0x5656 to 0x5679
+const uint16 dsAddr_fnMsg2 = 0x5656; // "And how am I supposed to get back?"
+// Message : 0x567a to 0x5681
+const uint16 dsAddr_fnMsg3 = 0x567a; // "Great"
+// Message : 0x5682 to 0x5695
+const uint16 dsAddr_fnMsg4 = 0x5682; // "Oh, yeah, right"
+// Pull Object Message #1 : 0x5696 to 0x56ab
+const uint16 dsAddr_pullObjMsg1 = 0x5696; // "I can't pull it out"
+// Dont Want To Touch Message : 0x56ac to 0x56d9
+const uint16 dsAddr_dontWantToTouchMsg = 0x56ac; // "I don't want to touch it - I might get hurt"
+// Fence Blocks Message : 0x56da to 0x56f6
+const uint16 dsAddr_fenceBlocksMsg = 0x56da; // "The fence blocks the way"
+// Not Want To Sleep Message : 0x56f7 to 0x570e
+const uint16 dsAddr_notWantToSleepMsg = 0x56f7; // "I don't want to sleep"
+// Pull Object Message #2 : 0x570f to 0x5721
+const uint16 dsAddr_pullObjMsg2 = 0x570f; // "I can't reach it"
+// Hello Question Message : 0x5722 to 0x5729
+const uint16 dsAddr_helloQMsg = 0x5722; // "Hello?"
+// Totally Addicted Message : 0x572a to 0x5741
+const uint16 dsAddr_totallyAddictedMsg = 0x572a; // "He's totally addicted"
+// What About Message : 0x5742 to 0x5756
+const uint16 dsAddr_whatAboutMsg = 0x5742; // "What about a new"
+// Hot Off Message : 0x5757 to 0x576f
+const uint16 dsAddr_hotOffMsg = 0x5757; // "hot off the press"
+// Full Color Message : 0x5770 to 0x5781
+const uint16 dsAddr_fullColorMsg = 0x5770; // "full-color"
+// Special Edition Message : 0x5782 to 0x5798
+const uint16 dsAddr_specialEdMsg = 0x5782; // "special edition"
+// Soldier News Message : 0x5799 to 0x57b1
+const uint16 dsAddr_soldierNewsMsg = 0x5799; // "of Soldier News?!"
+// Pole Climb Done Message : 0x57b2 to 0x57bf
+const uint16 dsAddr_poleClimbDoneMsg = 0x57b2; // "Never Again!"
+// Vac Message : 0x57c0 to 0x57de
+const uint16 dsAddr_vacMsg = 0x57c0; // "What am I? A vacuum cleaner?!"
+// Cutscene Message #1 : 0x57df to 0x5809
+const uint16 dsAddr_cutsceneMsg1 = 0x57df; // "sixty seven rude words later"
+// Cutscene Message #2 : 0x580a to 0x5826
+const uint16 dsAddr_cutsceneMsg2 = 0x580a; // "Meanwhile in the mansion"
+// Now Open Message : 0x5827 to 0x5836
+const uint16 dsAddr_nowOpenMsg = 0x5827; // "Now it's open"
+// Cmon Baby Message : 0x5837 to 0x5854
+const uint16 dsAddr_cmonBabyMsg = 0x5837; // "C'mon baby, it's all yours!"
+// Talk Not Now Message : 0x5855 to 0x5882
+const uint16 dsAddr_talkNotNowMsg = 0x5855; // "I've got no reason to talk to him right now."
+// Yeah Right Message : 0x5883 to 0x5893
+const uint16 dsAddr_yeahRightMsg = 0x5883; // "Yeah right!"
+// Barman Too Close Message : 0x5894 to 0x58af
+const uint16 dsAddr_barmanTooCloseMsg = 0x5894; // "The barman is too close"
+// Yuck Message : 0x58b0 to 0x58b6
+const uint16 dsAddr_yuckMsg = 0x58b0; // "Yuck!"
+// Prefer Water Message : 0x58b7 to 0x58c7
+const uint16 dsAddr_preferWaterMsg = 0x58b7; // "I prefer water"
+// Too Weak To Climb Message : 0x58c8 to 0x58e2
+const uint16 dsAddr_tooWeakToClimbMsg = 0x58c8; // "I'm too weak to climb it"
+// Spring Prick Message : 0x58e3 to 0x5904
+const uint16 dsAddr_springPrickMsg = 0x58e3; // "The springs would prick my back"
+// Food Alive Message : 0x5905 to 0x592e
+const uint16 dsAddr_foodAliveMsg = 0x5905; // "No, thanks. This food seems still alive"
+// Door Closed Message : 0x592f to 0x5954
+const uint16 dsAddr_doorClosedMsg = 0x592f; // "The door is closed. What a surprise."
+// Empty Message : 0x5955 to 0x5961
+const uint16 dsAddr_emptyMsg = 0x5955; // "It's Empty"
+// Geography Class Message : 0x5962 to 0x599c
+const uint16 dsAddr_geographyClassMsg = 0x5962; // "I should have paid more attention in geography classes."
+// Don't Need Mess Message : 0x599d to 0x59b5
+const uint16 dsAddr_dontNeedMessMsg = 0x599d; // "I don't need this mess"
+// Seen Softer Rocks Message : 0x59b6 to 0x59da
+const uint16 dsAddr_seenSofterRocksMsg = 0x59b6; // "Thanks, but I've seen softer rocks"
+// Too Blunt Message : 0x59db to 0x5a00
+const uint16 dsAddr_tooBluntMsg = 0x59db; // "They are too blunt to be of any use"
+// Useless Models Message : 0x5a01 to 0x5a1f
+const uint16 dsAddr_uselessModelsMsg = 0x5a01; // "What's the use of the models?"
+// Barman Will Notice Message : 0x5a20 to 0x5a50
+const uint16 dsAddr_barmanWillNoticeMsg = 0x5a20; // "The barman will surely notice its disappearing"
+// Too Much To Drink Message : 0x5a51 to 0x5a95
+const uint16 dsAddr_tooMuchToDrinkMsg = 0x5a51; // "It'd take too much time to drink it..."
+// 0x5a96 to 0x5a97 : 2 extra null bytes (padding?)
+// Not Thief Message : 0x5a98 to 0x5ac5
+const uint16 dsAddr_notThiefMsg = 0x5a98; // "I'm not a thief. And it's empty, by the way."
+// Too Many To Search Message : 0x5ac6 to 0x5aec
+const uint16 dsAddr_tooManyToSearchMsg = 0x5ac6; // "There are too many of them to search"
+// Captain Would Not Fit Message : 0x5aed to 0x5b26
+const uint16 dsAddr_captainWouldNotFitMsg = 0x5aed; // "Captain surely wouldn't fit them. I must look elsewhere"
+// Chickening Never Message : 0x5b27 to 0x5b3e
+const uint16 dsAddr_chickenNeverMsg = 0x5b27; // "Chickening? Me? Never!"
+// Can't Open It Message : 0x5b3f to 0x5b50
+const uint16 dsAddr_cantOpenItMsg = 0x5b3f; // "I can't open it"
+// Don't Need Them Message : 0x5b51 to 0x5b64
+const uint16 dsAddr_dontNeedThemMsg = 0x5b51; // "I don't need them"
+// Peeping Tom Message : 0x5b65 to 0x5b7f
+const uint16 dsAddr_peepingTomMsg = 0x5b65; // "What am I? A Peeping Tom?"
+// Big Pockets Message : 0x5b80 to 0x5baa
+const uint16 dsAddr_bigPocketsMsg = 0x5b80; // "I have big pockets, but there are limits"
+// Trouble With Stairs Message : 0x5bab to 0x5be6
+const uint16 dsAddr_troubleWithStairsMsg = 0x5bab; // "If I put it on I might have trouble walking up the stairs"
+// 9 Lives To Read Message : 0x5be7 to 0x5c0a
+const uint16 dsAddr_9LivesToReadMsg = 0x5be7; // "I'd need 9 lives to read them all"
+// Thanks Not Tired Message : 0x5c0b to 0x5c25
+const uint16 dsAddr_thanksNotTiredMsg = 0x5c0b; // "Thanks, I'm not so tired"
+// No Need To Turn On Message : 0x5c26 to 0x5c45
+const uint16 dsAddr_noNeedToTurnOnMsg = 0x5c26; // "There's no need to turn it on"
+// Won't Bear Weight Message : 0x5c46 to 0x5c5f
+const uint16 dsAddr_wontBearWeightMsg = 0x5c46; // "It won't bear my weight"
+// Never Learnt Message : 0x5c60 to 0x5c81
+const uint16 dsAddr_neverLearntMsg = 0x5c60; // "I never learnt to how use one"
+// So Sharp Message : 0x5c82 to 0x5cab
+const uint16 dsAddr_soSharpMsg = 0x5c82; // "They're so sharp they'd rip my trousers!"
+// Cognac Message : 0x5cac to 0x5cda
+const uint16 dsAddr_cognacMsg = 0x5cac; // "Pfui! The cognac really didn't do any good"
+// No Time For Pleasures Message : 0x5cdb to 0x5cfc
+const uint16 dsAddr_noTimeForPleasuresMsg = 0x5cdb; // "I don't have time for pleasures"
+// Not Socks With Bare Hands Message : 0x5cfd to 0x5d2b
+const uint16 dsAddr_notSocksWithBareHandsMsg = 0x5cfd; // "I won't touch these socks with my bare hands!"
+// Not Halloween Message : 0x5d2c to 0x5d40
+const uint16 dsAddr_notHalloweenMsg = 0x5d2c; // "It's not Halloween"
+// Not Manual Message : 0x5d41 to 0x5d6d
+const uint16 dsAddr_NotManualMsg = 0x5d41; // "It can't be controlled manually! I hate it!"
+// Nothing To Play Message : 0x5d6e to 0x5d86
+const uint16 dsAddr_nothingToPlayMsg = 0x5d6e; // "I have nothing to play"
+// Not Mine Message : 0x5d87 to 0x5da7
+const uint16 dsAddr_notMineMsg = 0x5d87; // "I can't take it. It's not mine."
+// Hey What's The Matter Message : 0x5da8 to 0x5dc1
+const uint16 dsAddr_HeyWtmQMsg = 0x5da8; // "Hey! What's the matter?!"
+// Its Open Message : 0x5dc2 to 0x5dcd
+const uint16 dsAddr_ItsOpenMsg = 0x5dc2; // "It's Open!"
+// Out Of Order Message : 0x5dce to 0x5de1
+const uint16 dsAddr_outOfOrderMsg = 0x5dce; // "It's out of order"
+// Captain Watching Message : 0x5de2 to 0x5e0a
+const uint16 dsAddr_captainWatchingMsg = 0x5de2; // "with captain watching? Better not"
+// Blunt Sickle Message : 0x5e0b to 0x5e24
+const uint16 dsAddr_bluntSickleMsg = 0x5e0b; // "The sickle is too blunt"
+// First Business Message : 0x5e25 to 0x5e53
+const uint16 dsAddr_firstBusinessMsg = 0x5e25; // "First I've got some business to take care of"
+// No Digging Knife Message : 0x5e54 to 0x5e8e
+const uint16 dsAddr_noDiggingKnifeMsg = 0x5e54; // "Digging it out with the knife could take a hundred years"
+
+// FIXME - Where is this message used?! Unused?
+// No Mess On Table Message : 0x5e8f to 0x5ebd
+const uint16 dsAddr_noMessOnTableMsg = 0x5e8f; // "I don't want to make more mess on this table"
+
+// Throw Crumbs To Bird Question Message : 0x5ebe to 0x5ee5
+const uint16 dsAddr_throwCrumbsToBirdQMsg = 0x5ebe; // "Should I throw the crumbs to the bird?"
+// Don't Waste Crumbs Message : 0x5ee6 to 0x5f10
+const uint16 dsAddr_dontWasteCrumbs = 0x5ee6; // "I don't want to waste these tasty crumbs"
+// Might Slip Fall In Message : 0x5f11 to 0x5f3b
+const uint16 dsAddr_mightSlipFallInMsg = 0x5f11; // "Better not... I might slip and fall in..."
+// Book Color Message Address Pointers : (6 * 2-byte) = 0x5f3c to 0x5f47
+const uint16 dsAddr_bookColorMsgPtr = 0x5f3c;
+// Book Color Message #0 : 0x5f48 to 0x5f60
+const uint16 dsAddr_bookColorMsg0 = 0x5f48; // ""The history of blues""
+// Book Color Message #1 : 0x5f61 to 0x5f8f
+const uint16 dsAddr_bookColorMsg1 = 0x5f61; // ""Manchester United, or the Red Devils story""
+// Book Color Message #2 : 0x5f90 to 0x5fb5
+const uint16 dsAddr_bookColorMsg2 = 0x5f90; // ""Greyhounds and other hunting dogs""
+// Book Color Message #3 : 0x5fb6 to 0x5fe6
+const uint16 dsAddr_bookColorMsg3 = 0x5fb6; // ""Greenhorn, or my adventures in the Wild West""
+// Book Color Message #4 : 0x5fe7 to 0x6008
+const uint16 dsAddr_bookColorMsg4 = 0x5fe7; // ""Charlie Brown and his company""
+// Book Color Message #5 : 0x6009 to 0x6034
+const uint16 dsAddr_bookColorMsg5 = 0x6009; // ""Pink Panther: an unauthorised biography""
+
+// Mansion Intrusion Function Pointers : (5 * 2-byte) = 0x6035 to 0x603e
+const uint16 dsAddr_MansionIntrusionFnPtr = 0x6035;
+
+// Save State Region : 0x6478 to 0xdbf1
+const uint16 dsAddr_saveState = 0x6478;
+const uint16 saveStateSize = 0x777a;
+
+// Save Description String (24 bytes) : 0x6478 to 0x648f
+
+// Ego (Mark) position in scene : 0x64af to 0x64b2
+const uint16 dsAddr_egoX = 0x64af; // 2 bytes
+const uint16 dsAddr_egoY = 0x64b1; // 2 bytes
+
+// Idle Animation List Table : 0x6540 to 0x????
+const uint16 dsAddr_idleAnimationListPtr = 0x6540;
+
+// Palette Effect Data : 0x6609 to 0x????
+const uint16 dsAddr_paletteEffectData = 0x6609;
+
+// Scene Fade Table (2 byte address * 42): 0x663e to 0x6691
+const uint16 dsAddr_sceneFadeTablePtr = 0x663e;
+
+// Scene Walkbox Table (2 byte LE address * 42) : 0x6746 to 0x6799
+const uint16 dsAddr_sceneWalkboxTablePtr = 0x6746;
+
+// Scene Zoom Table (2 byte address * 42) : 0x70f4 to 0x7147
+const uint16 dsAddr_sceneZoomTablePtr = 0x70f4;
+
+// Scene Object Table (2 byte address * 42) : 0x7254 to 0x72a7
+const uint16 dsAddr_sceneObjectTablePtr = 0x7254;
+
+// Scene Object Name : Sonny or whatever : 0x92e5 to 0x92f6
+const uint16 dsAddr_scnObjNameSonny = 0x92e5; // "Sonny or whatever"
+
+// Scene Object Name - Anne : 0x9820 to 0x9824
+const uint16 dsAddr_scnObjNameAnne = 0x9820; // "Anne"
+
+// Scene Object Name - Mike : 0xaa94 to 0xaa98
+const uint16 dsAddr_scnObjNameMike = 0xaa94; // "Mike"
+
+// Current Scene Id : 0xb4f3
+const uint16 dsAddr_currentScene = 0xb4f3; // 1 byte
+
+// Ons Animation Table (2 byte address * ??) : 0xb4f5 to 0x????
+const uint16 dsAddr_onsAnimationTablePtr = 0xb4f5;
+
+// Examine Object Callback Table (2 byte LE address * ??) : 0xb5ce to 0x????
+const uint16 dsAddr_objExamineCallbackTablePtr = 0xb5ce;
+
+// Use Object Callback Table (2 byte LE address * ??) : 0xb89c to 0x????
+const uint16 dsAddr_objUseCallbackTablePtr = 0xb89c;
+
+// Inventory Object Callback Table (3 byte (id, callbackAddr) * 7) : 0xbb72 to 0xbb86
+const uint16 dsAddr_objCallbackTablePtr = 0xbb72;
+// invItemToolboxFull = csAddr_openFullToolbox
+// invItemToolboxHalfEmpty = csAddr_openHalfEmptyToolbox
+// invItemDiveEquipment = csAddr_useDivingEquipment
+// invItemShovelAct2 = csAddr_digMansionWall
+// 0xff = csAddr_tooDarkHere // TODO: No object has id 0xff - Callback Disabled?
+// invItemBanknote = csAddr_examineBanknote
+// invItemTimePills = csAddr_useTimePills
+
+// Scene Hotspots Table (2 byte LE address * ??) : 0xbb87 to 0x????
+const uint16 dsAddr_sceneHotspotsPtr = 0xbb87;
+
+// Inventory Object Combining Table (5 byte (id, id, new object id, msgAddr) * 34) : 0xc335 to 0xc3de
+const uint16 dsAddr_objCombiningTablePtr = 0xc335;
+// 3 byte null terminator for Combining table 0xc3df to 0xc3e1
+
+// Object Combine Error Message : 0xc3e2 to 0xc41e
+const uint16 dsAddr_objCombineErrorMsg = 0xc3e2; // "Using these two objects ..."
+
+// Inventory (item ids held by Ego) (1 byte * 24) : 0xc48d to 0xc4a4
+const uint16 dsAddr_inventory = 0xc48d;
+// 0xc4a5 is null word alignment byte
+// Inventory item data address table (2 bytes * 92) : 0xc4a6 to 0xc55d
+const uint16 dsAddr_inventoryItemDataPtrTable = 0xc4a6;
+
+// Lans Animation Table (4 byte * ??) : 0xd89e to 0x????
+const uint16 dsAddr_lansAnimationTablePtr = 0xd89e;
+
+// Spoken With Mansion Guard Flag : 0xda96
+// FIXME - This is probably unecessary as although this location is set, it
+// doesn't now appear to be read.
+const uint16 dsAddr_spokenWithMansionGuardFlag = 0xda96; // 1 byte
+// Have Not Spoken With Mansion Guard Flag : 0xda97
+// FIXME - This is probably unecessary as although this location is set, it
+// doesn't now appear to be read.
+const uint16 dsAddr_haveNotSpokenWithMansionGuardFlag = 0xda97; // 1 byte
+
+// Dialog Stack - Pleading with Mansion Guard : 0xdaa6 to 0xdab1
+const uint16 dsAddr_dialogStackPleadingToMansionGuard = 0xdaa6;
+// Dialog Stack - Mansion Guard Drinking : 0xdab2 to 0xdab9
+// FIXME - Can't find where this is used...
+const uint16 dsAddr_dialogStackMansionGuardDrinking = 0xdab2;
+// Dialog Stack - Talking To Sonny : 0xdaba to 0xdac3
+const uint16 dsAddr_dialogStackSonny = 0xdaba;
+// Dialog Stack - Talking To Grandpa : 0xdac4 to 0xdacd
+const uint16 dsAddr_dialogStackGrandpa = 0xdac4;
+// Cave Thorns Cut Down Flag : 0xdaca
+// FIXME - Cave Thorns Flag overlap with dsAddr_dialogStackGrandpa. Bug or typo?
+const uint16 dsAddr_caveThornsCutDownFlag = 0xdaca; // 1 byte
+// Dialog Stack - Trying To Borrow Shotgun From Grandpa : 0xdace to 0xdad3
+const uint16 dsAddr_dialogStackGrandpaShotgun = 0xdace;
+// Dialog Stack - Trying To Borrow Fan From Grandpa : 0xdad4 to 0xdad9
+const uint16 dsAddr_dialogStackGrandpaFan = 0xdad4;
+// Dialog Stack - Ask Old Lady if OK : 0xdada to 0xdaef
+const uint16 dsAddr_dialogStackAskOldLadyOK = 0xdada;
+// Dialog Stack - Talking To Old Lady : 0xdaf0 to 0xdaf5
+const uint16 dsAddr_dialogStackOldLady = 0xdaf0;
+// Dialog Stack - Borrow Duster From Old Lady : 0xdaf6 to 0xdafb
+const uint16 dsAddr_dialogStackBorrowDusterFromOldLady = 0xdaf6;
+// Dialog Stack - Get Old Lady's Apple : 0xdafc to 0xdb01
+const uint16 dsAddr_dialogStackGetAppleOldLady = 0xdafc;
+// Dialog Stack - Giving Another Flower To Anne : 0xdb02 to 0xdb07
+const uint16 dsAddr_dialogStackAnotherFlowerToAnne = 0xdb02;
+// Dialog Stack - Talking To Squirrel : 0xdb08 to 0xdb13
+const uint16 dsAddr_dialogStackSquirrel = 0xdb08;
+// Dialog Stack - Talking To Dog : 0xdb14 to 0xdb1d
+const uint16 dsAddr_dialogStackDog = 0xdb14;
+// Dialog Stack - Take Axe : 0xdb1e to 0xdb23
+const uint16 dsAddr_dialogStackTakeAxe = 0xdb1e;
+// Dialog Stack - Talking To Busy Cook : 0xdb24 to 0xdb2d
+const uint16 dsAddr_dialogStackBusyCook = 0xdb24;
+// Dialog Stack - Talking To Mike the Robot Safe : 0xdb2e to 0xdb35
+const uint16 dsAddr_dialogStackRobotSafe = 0xdb2e;
+// Dialog Stack - Talking To John Noty At Endgame : 0xdb36 to 0xdb3f
+const uint16 dsAddr_dialogStackJohnNotyEndgame = 0xdb36;
+// Dialog Stack - Camp Guard Waiting For Documents : 0xdb40 to 0xdb4b
+const uint16 dsAddr_dialogStackCampGuardWantsDocuments = 0xdb40;
+// Dialog Stack - Camp Guard Reading Soldier News : 0xdb4c to 0xdb55
+const uint16 dsAddr_dialogStackCampGuardReadingNews = 0xdb4c;
+// Dialog Stack - Camp Guard Show Pass : 0xdb56 to 0xdb5b
+const uint16 dsAddr_dialogStackCampGuardShowPass = 0xdb56;
+// Dialog Stack - Jail Door Grates : 0xdb5c to 0xdb67
+const uint16 dsAddr_dialogStackJailDoorGrates = 0xdb5c;
+// Dialog Stack - Talking to Barman : 0xdb68 to 0xdb71
+const uint16 dsAddr_dialogStackBarman = 0xdb68;
+// Dialog Stack - Fall Into Mudpool : 0xdb72 to 0xdb79
+const uint16 dsAddr_dialogStackFallIntoMudpool = 0xdb72;
+// Dialog Stack - Talking To Mudpool Bird : 0xdb7a to 0xdb81
+const uint16 dsAddr_dialogStackMudpoolBird = 0xdb7a;
+// Dialog Stack - Interrogate Captain : 0xdb82 to 0xdb89
+const uint16 dsAddr_dialogStackInterrogateCaptain = 0xdb82;
+// Dialog Stack - Bar Cellar Door : 0xdb8a to 0xdb8f
+const uint16 dsAddr_dialogStackBarCellarDoor = 0xdb8a;
+// Current Music Id Playing : 0xdb90
+const uint16 dsAddr_currentMusic = 0xdb90; // 1 byte
+// Unused Byte : 0xdb91
+// Already Adjusted Hoop Pole Flag : 0xdb92
+const uint16 dsAddr_alreadyAdjustedHoopPoleFlag = 0xdb92; // 1 byte
+// Already Kicked Hen Flag : 0xdb93
+const uint16 dsAddr_alreadyKickedHenFlag = 0xdb93; // 1 byte
+// Already Pulled Trunk Release Lever Flag : 0xdb94
+const uint16 dsAddr_alreadyPulledTrunkReleaseLeverFlag = 0xdb94; // 1 byte
+// Car Trunk Empty Flag : 0xdb95
+const uint16 dsAddr_carTrunkEmptyFlag = 0xdb95; // 1 byte
+// Birds Gone From Scarecrow Flag : 0xdb96
+const uint16 dsAddr_birdsGoneFromScarecrowFlag = 0xdb96; // 1 byte
+// Already Spoken To Anne Flag : 0xdb97
+const uint16 dsAddr_alreadySpokenToAnneFlag = 0xdb97; // 1 byte
+// Flower Isle in Lake State (0 = Both Flowers Present, 1 = One Flower Taken, 2+ = Both Flowers Taken): 0xdb98
+const uint16 dsAddr_flowerIsleState = 0xdb98; // 1 byte
+// Already Got Broken Paddle Flag : 0xdb99
+const uint16 dsAddr_alreadyGotBrokenPaddleFlag = 0xdb99; // 1 byte
+// Given Flower To OldLady Already Flag : 0xdb9a
+const uint16 dsAddr_givenFlowerToOldLadyAlreadyFlag = 0xdb9a; // 1 byte
+// Given Flower To Anne Already Flag : 0xdb9b
+const uint16 dsAddr_givenFlowerToAnneAlreadyFlag = 0xdb9b; // 1 byte
+// Scared Guard Already Flag : 0xdb9c
+const uint16 dsAddr_scaredGuardAlreadyFlag = 0xdb9c; // 1 byte
+// Got Needle Already Flag : 0xdb9d
+const uint16 dsAddr_gotNeedleAlreadyFlag = 0xdb9d; // 1 byte
+// Got Potato Already Flag : 0xdb9e
+const uint16 dsAddr_gotPotatoAlreadyFlag = 0xdb9e; // 1 byte
+// Bees Gone Flag : 0xdb9f
+const uint16 dsAddr_beesGoneFlag = 0xdb9f; // 1 byte
+// Mansion Already Been Through Tunnel Flag : 0xdba0
+const uint16 dsAddr_mansionTunnelDoneFlag = 0xdba0; // 1 byte
+// Mansion Tree Hollow Empty Flag : 0xdba1
+const uint16 dsAddr_mansionTreeHollowEmptyFlag = 0xdba1; // 1 byte
+// Climbed Mansion Tree Already Flag : 0xdba2
+const uint16 dsAddr_climbedMansionTreeAlreadyFlag = 0xdba2; // 1 byte
+// Cellar Door Open Flag : 0xdba3
+const uint16 dsAddr_cellarDoorOpenFlag = 0xdba3; // 1 byte
+// Cellar Light On Flag : 0xdba4
+const uint16 dsAddr_lightOnFlag = 0xdba4; // 1 byte
+// Laundry State (0 = Wet on Line, 1 = Dry on Line, 2 = Not Present): 0xdba5
+const uint16 dsAddr_laundryState = 0xdba5; // 1 byte
+// Lake Diving Exit Message (0 to 5+) : 0xdba6
+const uint16 dsAddr_lakeDivingExitMessage = 0xdba6; // 1 byte
+// Searched Grandpa Drawers Flag : 0xdba7
+const uint16 dsAddr_SearchedGrandpaDrawersFlag = 0xdba7; // 1 byte
+// Hankerchief in Mousehole Flag : 0xdba8
+const uint16 dsAddr_HankerchiefInMouseholeFlag = 0xdba8; // 1 byte
+// Mouse Hole State : 0xdba9, 0 = Mouse Gone, 1 = Mouse Trapped, 2 = Mouse Success(?)
+const uint16 dsAddr_mouseHoleState = 0xdba9; // 1 byte
+// Mouse Nerve Message Said Flag : 0xdbaa
+const uint16 dsAddr_mouseNerveMsgSaidFlag = 0xdbaa; // 1 byte
+// Mouse Already Got Gold Nugget Flag : 0xdbab
+const uint16 dsAddr_mouseGotGoldNuggetFlag = 0xdbab; // 1 byte
+// Unused Byte : 0xdbac
+// Dog Has Bone Flag : 0xdbad
+const uint16 dsAddr_dogHasBoneFlag = 0xdbad; // 1 byte
+// Ego Already Scared By Spider Flag : 0xdbae
+const uint16 dsAddr_egoAlreadyScaredBySpiderFlag = 0xdbae; // 1 byte
+// Already Said That Anne is Beautiful Flag : 0xdbaf
+const uint16 dsAddr_alreadySaidAnneBeautifulFlag = 0xdbaf; // 1 byte
+// Squirrel's Nut State (0 = Nut in Tree, 1 = Nut in Grass, 2 = Nut Found with Rake) : 0xdbb0
+const uint16 dsAddr_squirrelNutState = 0xdbb0; // 1 byte
+// Nut Swapped For Apple in Fruit Bowl Flag : 0xdbb1
+const uint16 dsAddr_nutSwappedForAppleFlag = 0xdbb1; // 1 byte
+// Spoken To Man In Well Flag : 0xdbb2
+const uint16 dsAddr_spokenToManInWellFlag = 0xdbb2; // 1 byte
+// Spoken To Mirror Flag : 0xdbb3
+const uint16 dsAddr_spokenToMirrorFlag = 0xdbb3; // 1 byte
+// Cellar Shelves Examine Count (0 to 2(clamped))) : 0xdbb4
+const uint16 dsAddr_cellarShelfExamineCount = 0xdbb4; // 1 byte
+// Examined Bank Note Flag : 0xdbb5
+const uint16 dsAddr_examinedBanknoteFlag = 0xdbb5; // 1 byte
+// VGA Artist Quip Already Said Flag : 0xdbb6
+const uint16 dsAddr_vgaArtistQuipAlreadySaidFlag = 0xdbb6; // 1 byte
+// Mansion Desk Blue Drawer Open Flag : 0xdbb7
+const uint16 dsAddr_blueDrawerOpenFlag = 0xdbb7; // 1 byte
+// Mansion Desk Red Drawer Open Flag : 0xdbb8
+const uint16 dsAddr_redDrawerOpenFlag = 0xdbb8; // 1 byte
+// Mansion Desk Grey Drawer Open Flag : 0xdbb9
+const uint16 dsAddr_greyDrawerOpenFlag = 0xdbb9; // 1 byte
+// Mansion Desk Green Drawer Open Flag : 0xdbba
+const uint16 dsAddr_greenDrawerOpenFlag = 0xdbba; // 1 byte
+// Mansion Desk Brown Drawer Open Flag : 0xdbbb
+const uint16 dsAddr_brownDrawerOpenFlag = 0xdbbb; // 1 byte
+// Mansion Desk Pink Drawer Open Flag : 0xdbbc
+const uint16 dsAddr_pinkDrawerOpenFlag = 0xdbbc; // 1 byte
+// Mansion Colored Drawer Puzzle Hint Message Given Flag : 0xdbbd
+const uint16 dsAddr_drawerPuzzleHintGivenFlag = 0xdbbd; // 1 byte
+// Mansion Colored Drawer Got Dictaphone Flag : 0xdbbe
+const uint16 dsAddr_drawerGotDictaphoneFlag = 0xdbbe; // 1 byte
+// Mansion Colored Drawer Got Polaroid Flag : 0xdbbf
+const uint16 dsAddr_drawerGotPolaroidFlag = 0xdbbf; // 1 byte
+// Mansion Colored Drawer Puzzle Book Message Flag : 0xdbc0
+const uint16 dsAddr_drawerPuzzleBookMessageFlag = 0xdbc0; // 1 byte
+// Mansion Colored Drawer Puzzle - Random Book Color Value (0 = No Book, 1 to 6 = Books) : 0xdbc1
+const uint16 dsAddr_drawerPuzzleBookValue = 0xdbc1; // 1 byte
+// Mansion Colored Drawer Puzzle Solved Flag : 0xdbc2
+const uint16 dsAddr_drawerPuzzleSolvedFlag = 0xdbc2; // 1 byte
+// Mansion Trashcan Searched Flag : 0xdbc3
+const uint16 dsAddr_mansionTrashcanSearchedFlag = 0xdbc3; // 1 byte
+// Mansion Read Newspaper Flag : 0xdbc4
+const uint16 dsAddr_mansionReadNewspaperFlag = 0xdbc4; // 1 byte
+// Mansion TV On Flag : 0xdbc5
+const uint16 dsAddr_mansionTVOnFlag = 0xdbc5; // 1 byte
+// Mansion VCR Playing Tape Flag : 0xdbc6
+const uint16 dsAddr_mansionVCRPlayingTapeFlag = 0xdbc6; // 1 byte
+// Mansion VCR Played Tape Before Flag : 0xdbc7
+const uint16 dsAddr_mansionVCRPlayedTapeBeforeFlag = 0xdbc7; // 1 byte
+// Mansion VCR Tape Loaded Flag : 0xdbc8
+const uint16 dsAddr_mansionVCRTapeLoadedFlag = 0xdbc8; // 1 byte
+// Mansion Examined Couch Before Flag : 0xdbc9
+const uint16 dsAddr_mansionExaminedCouchBeforeFlag = 0xdbc9; // 1 byte
+// Mansion Used Polaroid on TV Flag : 0xdbca
+const uint16 dsAddr_usedPolaroidOnTVFlag = 0xdbca; // 1 byte
+// Mansion Used Dictaphone on TV Flag : 0xdbcb
+const uint16 dsAddr_usedDictaphoneOnTVFlag = 0xdbcb; // 1 byte
+// Mansion Cook Gone Flag : 0xdbcc
+const uint16 dsAddr_MansionCookGoneFlag = 0xdbcc; // 1 byte
+// Mansion Radio Broken Flag : 0xdbcd
+const uint16 dsAddr_MansionRadioBrokenFlag = 0xdbcd; // 1 byte
+// Mansion Got Radio Batteries Flag : 0xdbce
+const uint16 dsAddr_MansionGotRadioBatteriesFlag = 0xdbce; // 1 byte
+// Mansion Have Opened Fridge Before Flag : 0xdbcf
+const uint16 dsAddr_MansionHaveOpenedFridgeBeforeFlag = 0xdbcf; // 1 byte
+// Mansion Put Burning Paper In Fridge Flag : 0xdbd0
+const uint16 dsAddr_MansionPutBurningPaperInFridgeFlag = 0xdbd0; // 1 byte
+// Mansion Robot Safe Unlocked Flag : 0xdbd1
+const uint16 dsAddr_MansionRobotSafeUnlockedFlag = 0xdbd1; // 1 byte
+// Mansion Robot Safe Voice Test Passed Flag : 0xdbd2
+const uint16 dsAddr_MansionRobotSafeVoiceTestPassedFlag = 0xdbd2; // 1 byte
+// Mansion Robot Safe Scent Test Passed Flag : 0xdbd3
+const uint16 dsAddr_MansionRobotSafeScentTestPassedFlag = 0xdbd3; // 1 byte
+// Mansion Robot Safe View Test Passed Flag : 0xdbd4
+const uint16 dsAddr_MansionRobotSafeViewTestPassedFlag = 0xdbd4; // 1 byte
+// Mansion John Noty Outside Bathroom Flag : 0xdbd5
+const uint16 dsAddr_MansionJohnNotyOutsideBathroomFlag = 0xdbd5; // 1 byte
+// Mansion Sink State (0 - No Plug, Sink Empty, 1 - Plug, Sink Empty, 2 - Plug, Sink Full) : 0xdbd6
+const uint16 dsAddr_MansionSinkState = 0xdbd6; // 1 byte
+// Mansion Through Fan By Time Pill Flag : 0xdbd7
+const uint16 dsAddr_MansionThruFanByTimePillFlag = 0xdbd7; // 1 byte
+// Mansion Ventilator Fan Stopped Flag : 0xdbd8
+const uint16 dsAddr_MansionVentFanStoppedFlag = 0xdbd8; // 1 byte
+// Mansion John Noty Escaping Flag : 0xdbd9
+const uint16 dsAddr_MansionJohnNotyEscapingFlag = 0xdbd9; // 1 byte
+// Shown Pass To Guard Flag : 0xdbda
+const uint16 dsAddr_ShownPassToGuardFlag = 0xdbda; // 1 byte
+// Graffiti Message Id (0 to 6) : 0xdbdb
+const uint16 dsAddr_graffitiMsgId = 0xdbdb; // 1 byte
+// Got Food Bowl in Jail Flag : 0xdbdc
+const uint16 dsAddr_GotFoodBowlInJailFlag = 0xdbdc; // 1 byte
+// Jail Cable and Bowl State (0 = Cable not in Bowl, 1 = Cable in Bowl, 2 = Bowl Electrified 3 = Captain Shocked) : 0xdbdd
+const uint16 dsAddr_JailCableAndBowlState = 0xdbdd; // 1 byte
+// Got Jail Key Flag : 0xdbde
+const uint16 dsAddr_GotJailKeyFlag = 0xdbde; // 1 byte
+// First Act Trial State (0 = Before First Trial, 1 to 3 = Trial 1st to 3rd) : 0xdbdf
+const uint16 dsAddr_FirstActTrialState = 0xdbdf; // 1 byte
+// Already Tickled Captain Flag : 0xdbe0
+const uint16 dsAddr_AlreadyTickledCaptainFlag = 0xdbe0; // 1 byte
+// Cut Fence Flag : 0xdbe1
+const uint16 dsAddr_cutFenceFlag = 0xdbe1; // 1 byte
+// Act 1 Guard State (0 = Normal, 1 = With Kaleidoscope & Grenade, 2 = Kaleidoscope & No Grenade) : 0xdbe2
+const uint16 dsAddr_act1GuardState = 0xdbe2; // 1 byte
+// Spoken to Barman About Third Trial Flag : 0xdbe3
+const uint16 dsAddr_spokeToBarmanAboutThirdTrialFlag = 0xdbe3; // 1 byte
+// Got Mug Of Mud Flag : 0xdbe4
+const uint16 dsAddr_gotMugOfMudFlag = 0xdbe4; // 1 byte
+// Got Rope In Act 1 Flag : 0xdbe5
+const uint16 dsAddr_gotRopeAct1Flag = 0xdbe5; // 1 byte
+// Captain Drawer State : 0xdbe6
+const uint16 dsAddr_captainDrawerState = 0xdbe6; // 1 byte
+// Bird on Bar Radio Antenna Flag : 0xdbe7
+const uint16 dsAddr_birdOnBarRadioAntennaFlag = 0xdbe7; // 1 byte
+// Swapped Barman Mug Flag : 0xdbe8
+const uint16 dsAddr_swappedBarmanMugFlag = 0xdbe8; // 1 byte
+// Barman Passed Out Flag : 0xdbe9
+const uint16 dsAddr_barmanPassedOutFlag = 0xdbe9; // 1 byte
+// Counter for Mansion Intrusion Attempts : 0xdbea
+const uint16 dsAddr_mansionEntryCount = 0xdbea;// 1 byte
+// Unused Byte : 0xdbeb
+// John Noty Outside Mansion Door Flag : 0xdbec
+const uint16 dsAddr_johnNotyOutsideMansionDoorFlag = 0xdbec; // 1 byte
+// Unused Byte : 0xdbed
+// Lovestruck By Anne Flag : 0xdbee
+const uint16 dsAddr_lovestruckByAnneFlag = 0xdbee;// 1 byte
+// Mansion Handle in Door Hole Flag : 0xdbef
+const uint16 dsAddr_mansionHandleInDoorHoleFlag = 0xdbef;// 1 byte
+// Got Password Need to Speak To Barman Flag : 0xdbf0
+const uint16 dsAddr_gotPasswordNeedSpeakBarmanFlag = 0xdbf0; // 1 byte
+// Mansion Already Used Time Pills Flag : 0xdbf1
+const uint16 dsAddr_mansionAlreadyUsedTimePillsFlag = 0xdbf1; // 1 byte
+
+// Intro Credits #1 : 0xe3c2 to 0xe3e5 (Read Only)
+const uint16 dsAddr_introCredits1 = 0xe3c2; // "backgrounds ..."
+// Intro Credits #2 : 0xe3e6 to 0xe3fe (Read Only)
+const uint16 dsAddr_introCredits2 = 0xe3e6; // "music ..."
+// Intro Credits #3 : 0xe3ff to 0xe42e (Read Only)
+const uint16 dsAddr_introCredits3 = 0xe3ff; // "animation..."
+// Intro Credits #4 : 0xe42f to 0xe45b (Read Only)
+const uint16 dsAddr_introCredits4 = 0xe42f; // "programming..."
+// Credits #5 : 0xe45c to 0xe47b (Read Only)
+const uint16 dsAddr_credits5 = 0xe45c; // "after the tiring journey..."
+// Final Credits #6 : 0xe47c to 0xe487 (Read Only)
+const uint16 dsAddr_finalCredits6 = 0xe47c; // "THE END..."
+// Final Credits #7 : 0xe488 to 0xe782 (Read Only)
+const uint16 dsAddr_finalCredits7 = 0xe488; // "programming..."
+// 0xe783 to 0xe78f: 13 null bytes at end of dseg data - segment alignment padding?
+
class Resources {
-protected:
- Resources();
public:
- static Resources *instance();
+ Resources();
+ ~Resources();
bool loadArchives(const ADGameDescription *gd);
- void deinit();
+
void loadOff(Graphics::Surface &surface, byte *palette, int id);
Common::SeekableReadStream *loadLan(uint32 id) const;
Common::SeekableReadStream *loadLan000(uint32 id) const;
- //void loadOn(Graphics::Surface &surface, int id, uint16 &dst, uint16 *flags);
- //void loadOns(Graphics::Surface &surface, int id, uint16 &dst);
/*
* PSP (as the other sony playstation consoles - to be confirmed and 'ifdef'ed here too)
@@ -56,8 +1182,17 @@ public:
FilePack off, on, ons, lan000, lan500, sam_mmm, sam_sam, mmm, voices;
#endif
- Segment cseg, dseg, eseg;
+ Segment dseg;
Font font7, font8;
+
+ //const byte *getDialog(uint16 dialogNum) { return eseg.ptr(dialogOffsets[dialogNum]); }
+ uint16 getDialogAddr(uint16 dialogNum) { return dialogOffsets[dialogNum]; }
+
+ Segment eseg;
+private:
+ void precomputeDialogOffsets();
+
+ Common::Array<uint16> dialogOffsets;
};
} // End of namespace TeenAgent
diff --git a/engines/teenagent/scene.cpp b/engines/teenagent/scene.cpp
index 038c8ea05e..bdeb11a841 100644
--- a/engines/teenagent/scene.cpp
+++ b/engines/teenagent/scene.cpp
@@ -21,6 +21,7 @@
#include "common/config-manager.h"
#include "common/debug.h"
+#include "common/events.h"
#include "common/algorithm.h"
#include "common/ptr.h"
#include "common/textconsole.h"
@@ -28,24 +29,23 @@
#include "graphics/palette.h"
#include "teenagent/scene.h"
+#include "teenagent/inventory.h"
#include "teenagent/resources.h"
#include "teenagent/surface.h"
#include "teenagent/objects.h"
#include "teenagent/teenagent.h"
-#include "teenagent/dialog.h"
#include "teenagent/music.h"
namespace TeenAgent {
-Scene::Scene(TeenAgentEngine *engine, OSystem *system) : intro(false), _id(0), ons(0),
- orientation(kActorRight), actor_talking(false),
- message_timer(0), message_first_frame(0), message_last_frame(0), message_animation(NULL),
- current_event(SceneEvent::kNone), hide_actor(false), callback(0), callback_timer(0), _idle_timer(0) {
- _engine = engine;
- _system = system;
+Scene::Scene(TeenAgentEngine *vm) : _vm(vm), intro(false), _id(0), ons(0),
+ orientation(kActorRight), actorTalking(false), teenagent(vm), teenagentIdle(vm),
+ messageTimer(0), messageFirstFrame(0), messageLastFrame(0), messageAnimation(NULL),
+ currentEvent(SceneEvent::kNone), hideActor(false), callback(0), callbackTimer(0), _idleTimer(0) {
- _fade_timer = 0;
- on_enabled = true;
+ _fadeTimer = 0;
+ _fadeOld = 0;
+ onEnabled = true;
memset(palette, 0, sizeof(palette));
background.pixels = 0;
@@ -65,8 +65,8 @@ Scene::Scene(TeenAgentEngine *engine, OSystem *system) : intro(false), _id(0), o
if (!s)
error("invalid resource data");
- teenagent_idle.load(*s, Animation::kTypeVaria);
- if (teenagent_idle.empty())
+ teenagentIdle.load(*s, Animation::kTypeVaria);
+ if (teenagentIdle.empty())
error("invalid mark animation");
varia.close();
@@ -91,10 +91,10 @@ void Scene::warp(const Common::Point &_point, byte o) {
bool Scene::findPath(Scene::Path &p, const Common::Point &src, const Common::Point &dst) const {
const Common::Array<Walkbox> &scene_walkboxes = walkboxes[_id - 1];
- if (dst.x < 0 || dst.x > 319 || dst.y < 0 || dst.y > 199)
+ if (dst.x < 0 || dst.x >= kScreenWidth || dst.y < 0 || dst.y >= kScreenHeight)
return false;
- debug(1, "findPath %d,%d -> %d,%d", src.x, src.y, dst.x, dst.y);
+ debugC(1, kDebugScene, "findPath %d,%d -> %d,%d", src.x, src.y, dst.x, dst.y);
p.clear();
p.push_back(src);
p.push_back(dst);
@@ -113,7 +113,7 @@ bool Scene::findPath(Scene::Path &p, const Common::Point &src, const Common::Poi
break;
const Common::Point &p1 = *i, &p2 = *next;
- debug(1, "%d,%d -> %d,%d", p1.x, p1.y, p2.x, p2.y);
+ debugC(1, kDebugScene, "%d,%d -> %d,%d", p1.x, p1.y, p2.x, p2.y);
Common::List<uint>::iterator wi;
for (wi = boxes.begin(); wi != boxes.end(); ++wi) {
@@ -124,14 +124,14 @@ bool Scene::findPath(Scene::Path &p, const Common::Point &src, const Common::Poi
}
w.dump(1);
- debug(1, "%u: intersection mask 0x%04x, searching hints", *wi, mask);
+ debugC(1, kDebugScene, "%u: intersection mask 0x%04x, searching hints", *wi, mask);
int dx = p2.x - p1.x, dy = p2.y - p1.y;
if (dx >= 0) {
- if ((mask & 8) != 0 && w.side_hint[3] != 0) {
- debug(1, "hint left: %u", w.side_hint[3]);
+ if ((mask & 8) != 0 && w.sideHint[3] != 0) {
+ debugC(1, kDebugScene, "hint left: %u", w.sideHint[3]);
Common::Point w1, w2;
- w.rect.side(w1, w2, w.side_hint[3], p1);
- debug(1, "hint: %d,%d-%d,%d", w1.x, w1.y, w2.x, w2.y);
+ w.rect.side(w1, w2, w.sideHint[3], p1);
+ debugC(1, kDebugScene, "hint: %d,%d-%d,%d", w1.x, w1.y, w2.x, w2.y);
p.insert(next, w1);
if (mask & 2)
p.insert(next, w2);
@@ -139,11 +139,11 @@ bool Scene::findPath(Scene::Path &p, const Common::Point &src, const Common::Poi
break;
}
} else {
- if ((mask & 2) != 0 && w.side_hint[1] != 0) {
- debug(1, "hint right: %u", w.side_hint[1]);
+ if ((mask & 2) != 0 && w.sideHint[1] != 0) {
+ debugC(1, kDebugScene, "hint right: %u", w.sideHint[1]);
Common::Point w1, w2;
- w.rect.side(w1, w2, w.side_hint[1], p1);
- debug(1, "hint: %d,%d-%d,%d", w1.x, w1.y, w2.x, w2.y);
+ w.rect.side(w1, w2, w.sideHint[1], p1);
+ debugC(1, kDebugScene, "hint: %d,%d-%d,%d", w1.x, w1.y, w2.x, w2.y);
p.insert(next, w1);
if (mask & 8)
p.insert(next, w2);
@@ -153,11 +153,11 @@ bool Scene::findPath(Scene::Path &p, const Common::Point &src, const Common::Poi
}
if (dy >= 0) {
- if ((mask & 1) != 0 && w.side_hint[0] != 0) {
- debug(1, "hint top: %u", w.side_hint[0]);
+ if ((mask & 1) != 0 && w.sideHint[0] != 0) {
+ debugC(1, kDebugScene, "hint top: %u", w.sideHint[0]);
Common::Point w1, w2;
- w.rect.side(w1, w2, w.side_hint[0], p1);
- debug(1, "hint: %d,%d-%d,%d", w1.x, w1.y, w2.x, w2.y);
+ w.rect.side(w1, w2, w.sideHint[0], p1);
+ debugC(1, kDebugScene, "hint: %d,%d-%d,%d", w1.x, w1.y, w2.x, w2.y);
p.insert(next, w1);
if (mask & 4)
p.insert(next, w2);
@@ -165,11 +165,11 @@ bool Scene::findPath(Scene::Path &p, const Common::Point &src, const Common::Poi
break;
}
} else {
- if ((mask & 4) != 0 && w.side_hint[2] != 0) {
- debug(1, "hint bottom: %u", w.side_hint[2]);
+ if ((mask & 4) != 0 && w.sideHint[2] != 0) {
+ debugC(1, kDebugScene, "hint bottom: %u", w.sideHint[2]);
Common::Point w1, w2;
- w.rect.side(w1, w2, w.side_hint[2], p1);
- debug(1, "hint: %d,%d-%d,%d", w1.x, w1.y, w2.x, w2.y);
+ w.rect.side(w1, w2, w.sideHint[2], p1);
+ debugC(1, kDebugScene, "hint: %d,%d-%d,%d", w1.x, w1.y, w2.x, w2.y);
p.insert(next, w1);
if (mask & 1)
p.insert(next, w2);
@@ -187,13 +187,13 @@ bool Scene::findPath(Scene::Path &p, const Common::Point &src, const Common::Poi
void Scene::moveTo(const Common::Point &_point, byte orient, bool validate) {
Common::Point point(_point);
- debug(0, "moveTo(%d, %d, %u)", point.x, point.y, orient);
+ debugC(0, kDebugScene, "moveTo(%d, %d, %u)", point.x, point.y, orient);
const Common::Array<Walkbox> &scene_walkboxes = walkboxes[_id - 1];
for (byte i = 0; i < scene_walkboxes.size(); ++i) {
const Walkbox &w = scene_walkboxes[i];
if (w.rect.in(point)) {
- debug(0, "bumped into walkbox %u", i);
+ debugC(0, kDebugScene, "bumped into walkbox %u", i);
w.dump();
byte o = w.orientation;
switch (o) {
@@ -229,7 +229,7 @@ void Scene::moveTo(const Common::Point &_point, byte orient, bool validate) {
}
if (!findPath(path, position, point)) {
- _engine->cancel();
+ _vm->cancel();
return;
}
@@ -237,55 +237,53 @@ void Scene::moveTo(const Common::Point &_point, byte orient, bool validate) {
}
void Scene::loadObjectData() {
- Resources *res = Resources::instance();
-
//loading objects & walkboxes
objects.resize(42);
walkboxes.resize(42);
fades.resize(42);
for (byte i = 0; i < 42; ++i) {
- Common::Array<Object> &scene_objects = objects[i];
- scene_objects.clear();
+ Common::Array<Object> &sceneObjects = objects[i];
+ sceneObjects.clear();
- uint16 scene_table = res->dseg.get_word(0x7254 + i * 2);
- uint16 object_addr;
- while ((object_addr = res->dseg.get_word(scene_table)) != 0) {
+ uint16 sceneTable = _vm->res->dseg.get_word(dsAddr_sceneObjectTablePtr + (i * 2));
+ uint16 objectAddr;
+ while ((objectAddr = _vm->res->dseg.get_word(sceneTable)) != 0) {
Object obj;
- obj.load(res->dseg.ptr(object_addr));
+ obj.load(_vm->res->dseg.ptr(objectAddr));
//obj.dump();
- scene_objects.push_back(obj);
- scene_table += 2;
+ sceneObjects.push_back(obj);
+ sceneTable += 2;
}
- debug(0, "scene[%u] has %u object(s)", i + 1, scene_objects.size());
+ debugC(0, kDebugScene, "scene[%u] has %u object(s)", i + 1, sceneObjects.size());
- byte *walkboxes_base = res->dseg.ptr(READ_LE_UINT16(res->dseg.ptr(0x6746 + i * 2)));
- byte walkboxes_n = *walkboxes_base++;
- debug(0, "scene[%u] has %u walkboxes", i + 1, walkboxes_n);
+ byte *walkboxesBase = _vm->res->dseg.ptr(READ_LE_UINT16(_vm->res->dseg.ptr(dsAddr_sceneWalkboxTablePtr + i * 2)));
+ byte walkboxesCount = *walkboxesBase++;
+ debugC(0, kDebugScene, "scene[%u] has %u walkboxes", i + 1, walkboxesCount);
- Common::Array<Walkbox> &scene_walkboxes = walkboxes[i];
- for (byte j = 0; j < walkboxes_n; ++j) {
+ Common::Array<Walkbox> &sceneWalkboxes = walkboxes[i];
+ for (byte j = 0; j < walkboxesCount; ++j) {
Walkbox w;
- w.load(walkboxes_base + 14 * j);
- if ((w.side_hint[0] | w.side_hint[1] | w.side_hint[2] | w.side_hint[3]) == 0) {
- w.side_hint[0] = 2;
- w.side_hint[1] = 3;
- w.side_hint[2] = 4;
- w.side_hint[3] = 1;
+ w.load(walkboxesBase + 14 * j);
+ if ((w.sideHint[0] | w.sideHint[1] | w.sideHint[2] | w.sideHint[3]) == 0) {
+ w.sideHint[0] = 2;
+ w.sideHint[1] = 3;
+ w.sideHint[2] = 4;
+ w.sideHint[3] = 1;
}
//walkbox[i]->dump();
- scene_walkboxes.push_back(w);
+ sceneWalkboxes.push_back(w);
}
- byte *fade_table = res->dseg.ptr(res->dseg.get_word(0x663e + i * 2));
- Common::Array<FadeType> &scene_fades = fades[i];
- while (READ_LE_UINT16(fade_table) != 0xffff) {
+ byte *fadeTable = _vm->res->dseg.ptr(_vm->res->dseg.get_word(dsAddr_sceneFadeTablePtr + i * 2));
+ Common::Array<FadeType> &sceneFades = fades[i];
+ while (READ_LE_UINT16(fadeTable) != 0xffff) {
FadeType fade;
- fade.load(fade_table);
- fade_table += 9;
- scene_fades.push_back(fade);
+ fade.load(fadeTable);
+ fadeTable += 9;
+ sceneFades.push_back(fade);
}
- debug(0, "scene[%u] has %u fadeboxes", i + 1, scene_fades.size());
+ debugC(0, kDebugScene, "scene[%u] has %u fadeboxes", i + 1, sceneFades.size());
}
}
@@ -293,10 +291,10 @@ Object *Scene::findObject(const Common::Point &point) {
if (_id == 0)
return NULL;
- Common::Array<Object> &scene_objects = objects[_id - 1];
+ Common::Array<Object> &sceneObjects = objects[_id - 1];
- for (uint i = 0; i < scene_objects.size(); ++i) {
- Object &obj = scene_objects[i];
+ for (uint i = 0; i < sceneObjects.size(); ++i) {
+ Object &obj = sceneObjects[i];
if (obj.enabled != 0 && obj.rect.in(point))
return &obj;
}
@@ -304,41 +302,38 @@ Object *Scene::findObject(const Common::Point &point) {
}
byte *Scene::getOns(int id) {
- Resources *res = Resources::instance();
- return res->dseg.ptr(res->dseg.get_word(0xb4f5 + (id - 1) * 2));
+ return _vm->res->dseg.ptr(_vm->res->dseg.get_word(dsAddr_onsAnimationTablePtr + (id - 1) * 2));
}
byte *Scene::getLans(int id) {
- Resources *res = Resources::instance();
- return res->dseg.ptr(0xd89e + (id - 1) * 4);
+ return _vm->res->dseg.ptr(dsAddr_lansAnimationTablePtr + (id - 1) * 4);
}
void Scene::loadOns() {
- debug(0, "loading ons animation");
- Resources *res = Resources::instance();
+ debugC(0, kDebugScene, "loading ons animation");
- uint16 addr = res->dseg.get_word(0xb4f5 + (_id - 1) * 2);
- //debug(0, "ons index: %04x", addr);
+ uint16 addr = _vm->res->dseg.get_word(dsAddr_onsAnimationTablePtr + (_id - 1) * 2);
+ debugC(0, kDebugScene, "ons index: %04x", addr);
- ons_count = 0;
+ onsCount = 0;
byte b;
- byte on_id[16];
- while ((b = res->dseg.get_byte(addr)) != 0xff) {
- debug(0, "on: %04x = %02x", addr, b);
+ byte onId[16];
+ while ((b = _vm->res->dseg.get_byte(addr)) != 0xff) {
+ debugC(0, kDebugScene, "on: %04x = %02x", addr, b);
++addr;
if (b == 0)
continue;
- on_id[ons_count++] = b;
+ onId[onsCount++] = b;
}
delete[] ons;
ons = NULL;
- if (ons_count > 0) {
- ons = new Surface[ons_count];
- for (uint32 i = 0; i < ons_count; ++i) {
- Common::ScopedPtr<Common::SeekableReadStream> s(res->ons.getStream(on_id[i]));
+ if (onsCount > 0) {
+ ons = new Surface[onsCount];
+ for (uint32 i = 0; i < onsCount; ++i) {
+ Common::ScopedPtr<Common::SeekableReadStream> s(_vm->res->ons.getStream(onId[i]));
if (s) {
ons[i].load(*s, Surface::kTypeOns);
}
@@ -347,21 +342,20 @@ void Scene::loadOns() {
}
void Scene::loadLans() {
- debug(0, "loading lans animation");
- Resources *res = Resources::instance();
- //load lan000
+ debugC(0, kDebugScene, "loading lans animation");
+ // load lan000
for (byte i = 0; i < 4; ++i) {
animation[i].free();
- uint16 bx = 0xd89e + (_id - 1) * 4 + i;
- byte bxv = res->dseg.get_byte(bx);
- uint16 res_id = 4 * (_id - 1) + i + 1;
- debug(0, "lan[%u]@%04x = %02x, resource id: %u", i, bx, bxv, res_id);
+ uint16 bx = dsAddr_lansAnimationTablePtr + (_id - 1) * 4 + i;
+ byte bxv = _vm->res->dseg.get_byte(bx);
+ uint16 resId = 4 * (_id - 1) + i + 1;
+ debugC(0, kDebugScene, "lan[%u]@%04x = %02x, resource id: %u", i, bx, bxv, resId);
if (bxv == 0)
continue;
- Common::ScopedPtr<Common::SeekableReadStream> s(res->loadLan000(res_id));
+ Common::ScopedPtr<Common::SeekableReadStream> s(_vm->res->loadLan000(resId));
if (s) {
animation[i].load(*s, Animation::kTypeLan);
if (bxv != 0 && bxv != 0xff)
@@ -371,24 +365,23 @@ void Scene::loadLans() {
}
void Scene::init(int id, const Common::Point &pos) {
- debug(0, "init(%d)", id);
+ debugC(0, kDebugScene, "init(%d)", id);
_id = id;
- on_enabled = true; //reset on-rendering flag on loading.
+ onEnabled = true; //reset on-rendering flag on loading.
sounds.clear();
for (byte i = 0; i < 4; ++i)
- custom_animation[i].free();
+ customAnimation[i].free();
if (background.pixels == NULL)
- background.create(320, 200, Graphics::PixelFormat::createFormatCLUT8());
+ background.create(kScreenWidth, kScreenHeight, Graphics::PixelFormat::createFormatCLUT8());
warp(pos);
- Resources *res = Resources::instance();
- res->loadOff(background, palette, id);
+ _vm->res->loadOff(background, palette, id);
if (id == 24) {
- //dark scene
- if (res->dseg.get_byte(0xDBA4) != 1) {
- //dim down palette
+ // dark scene
+ if (_vm->res->dseg.get_byte(dsAddr_lightOnFlag) != 1) {
+ // dim down palette
uint i;
for (i = 0; i < 624; ++i) {
palette[i] = palette[i] > 0x20 ? palette[i] - 0x20 : 0;
@@ -399,62 +392,62 @@ void Scene::init(int id, const Common::Point &pos) {
}
}
- Common::ScopedPtr<Common::SeekableReadStream> stream(res->on.getStream(id));
- int sub_hack = 0;
- if (id == 7) { //something patched in the captains room
- switch (res->dseg.get_byte(0xdbe6)) {
+ Common::ScopedPtr<Common::SeekableReadStream> stream(_vm->res->on.getStream(id));
+ int subHack = 0;
+ if (id == 7) { // something patched in the captains room
+ switch (_vm->res->dseg.get_byte(dsAddr_captainDrawerState)) {
case 2:
break;
case 1:
- sub_hack = 1;
+ subHack = 1;
break;
default:
- sub_hack = 2;
+ subHack = 2;
}
}
- on.load(*stream, SurfaceList::kTypeOn, sub_hack);
+ on.load(*stream, subHack);
loadOns();
loadLans();
- //check music
- int now_playing = _engine->music->getId();
+ // check music
+ int nowPlaying = _vm->music->getId();
- if (now_playing != res->dseg.get_byte(0xDB90))
- _engine->music->load(res->dseg.get_byte(0xDB90));
+ if (nowPlaying != _vm->res->dseg.get_byte(dsAddr_currentMusic))
+ _vm->music->load(_vm->res->dseg.get_byte(dsAddr_currentMusic));
- _system->copyRectToScreen(background.pixels, background.pitch, 0, 0, background.w, background.h);
+ _vm->_system->copyRectToScreen(background.pixels, background.pitch, 0, 0, background.w, background.h);
setPalette(0);
}
void Scene::playAnimation(byte idx, uint id, bool loop, bool paused, bool ignore) {
- debug(0, "playAnimation(%u, %u, loop:%s, paused:%s, ignore:%s)", idx, id, loop ? "true" : "false", paused ? "true" : "false", ignore ? "true" : "false");
+ debugC(0, kDebugScene, "playAnimation(%u, %u, loop:%s, paused:%s, ignore:%s)", idx, id, loop ? "true" : "false", paused ? "true" : "false", ignore ? "true" : "false");
assert(idx < 4);
- Common::ScopedPtr<Common::SeekableReadStream> s(Resources::instance()->loadLan(id + 1));
+ Common::ScopedPtr<Common::SeekableReadStream> s(_vm->res->loadLan(id + 1));
if (!s)
error("playing animation %u failed", id);
- custom_animation[idx].load(*s);
- custom_animation[idx].loop = loop;
- custom_animation[idx].paused = paused;
- custom_animation[idx].ignore = ignore;
+ customAnimation[idx].load(*s);
+ customAnimation[idx].loop = loop;
+ customAnimation[idx].paused = paused;
+ customAnimation[idx].ignore = ignore;
}
void Scene::playActorAnimation(uint id, bool loop, bool ignore) {
- debug(0, "playActorAnimation(%u, loop:%s, ignore:%s)", id, loop ? "true" : "false", ignore ? "true" : "false");
- Common::ScopedPtr<Common::SeekableReadStream> s(Resources::instance()->loadLan(id + 1));
+ debugC(0, kDebugScene, "playActorAnimation(%u, loop:%s, ignore:%s)", id, loop ? "true" : "false", ignore ? "true" : "false");
+ Common::ScopedPtr<Common::SeekableReadStream> s(_vm->res->loadLan(id + 1));
if (!s)
error("playing animation %u failed", id);
- actor_animation.load(*s);
- actor_animation.loop = loop;
- actor_animation.ignore = ignore;
- actor_animation.id = id;
+ actorAnimation.load(*s);
+ actorAnimation.loop = loop;
+ actorAnimation.ignore = ignore;
+ actorAnimation.id = id;
}
Animation *Scene::getAnimation(byte slot) {
assert(slot < 4);
- return custom_animation + slot;
+ return customAnimation + slot;
}
byte Scene::peekFlagEvent(uint16 addr) const {
@@ -463,17 +456,17 @@ byte Scene::peekFlagEvent(uint16 addr) const {
if (e.type == SceneEvent::kSetFlag && e.callback == addr)
return e.color;
}
- return Resources::instance()->dseg.get_byte(addr);
+ return _vm->res->dseg.get_byte(addr);
}
void Scene::push(const SceneEvent &event) {
- //debug(0, "push");
+ debugC(0, kDebugScene, "push");
//event.dump();
if (event.type == SceneEvent::kWalk && !events.empty()) {
SceneEvent &prev = events.back();
if (prev.type == SceneEvent::kWalk && prev.color == event.color) {
- debug(0, "fixing double-move [skipping event!]");
- if ((event.color & 2) != 0) { //relative move
+ debugC(0, kDebugScene, "fixing double-move [skipping event!]");
+ if ((event.color & 2) != 0) { // relative move
prev.dst.x += event.dst.x;
prev.dst.y += event.dst.y;
} else {
@@ -489,7 +482,7 @@ bool Scene::processEvent(const Common::Event &event) {
switch (event.type) {
case Common::EVENT_LBUTTONDOWN:
case Common::EVENT_RBUTTONDOWN:
- if (!message.empty() && message_first_frame == 0) {
+ if (!message.empty() && messageFirstFrame == 0) {
clearMessage();
nextEvent();
return true;
@@ -505,16 +498,16 @@ bool Scene::processEvent(const Common::Event &event) {
clearMessage();
events.clear();
sounds.clear();
- current_event.clear();
- message_color = 0xd1;
+ currentEvent.clear();
+ messageColor = textColorMark;
for (int i = 0; i < 4; ++i)
- custom_animation[i].free();
- _engine->playMusic(4);
- _engine->loadScene(10, Common::Point(136, 153));
+ customAnimation[i].free();
+ _vm->playMusic(4);
+ _vm->loadScene(10, Common::Point(136, 153));
return true;
}
- if (!message.empty() && message_first_frame == 0) {
+ if (!message.empty() && messageFirstFrame == 0) {
clearMessage();
nextEvent();
return true;
@@ -534,8 +527,8 @@ bool Scene::processEvent(const Common::Event &event) {
if (event.kbd.flags & Common::KBD_CTRL) {
uint feature = event.kbd.keycode - '1';
if (feature < DebugFeatures::kMax) {
- debug_features.feature[feature] = !debug_features.feature[feature];
- debug(0, "switched feature %u %s", feature, debug_features.feature[feature] ? "on" : "off");
+ debugFeatures.feature[feature] = !debugFeatures.feature[feature];
+ debugC(0, kDebugScene, "switched feature %u %s", feature, debugFeatures.feature[feature] ? "on" : "off");
}
}
break;
@@ -556,25 +549,22 @@ struct ZOrderCmp {
};
int Scene::lookupZoom(uint y) const {
- Resources *res = Resources::instance();
- for (byte *zoom_table = res->dseg.ptr(res->dseg.get_word(0x70f4 + (_id - 1) * 2));
- zoom_table[0] != 0xff && zoom_table[1] != 0xff;
- zoom_table += 2) {
- //debug(0, "%d %d->%d", y, zoom_table[0], zoom_table[1]);
- if (y <= zoom_table[0]) {
- //debug(0, "%d %d->%d", y, zoom_table[0], zoom_table[1]);
- return 256u * (100 - zoom_table[1]) / 100;
+ debugC(2, kDebugScene, "lookupZoom(%d)", y);
+ for (byte *zoomTable = _vm->res->dseg.ptr(_vm->res->dseg.get_word(dsAddr_sceneZoomTablePtr + (_id - 1) * 2));
+ zoomTable[0] != 0xff && zoomTable[1] != 0xff;
+ zoomTable += 2) {
+ debugC(2, kDebugScene, "\t%d %d->%d", y, zoomTable[0], zoomTable[1]);
+ if (y <= zoomTable[0]) {
+ return 256u * (100 - zoomTable[1]) / 100;
}
}
return 256;
}
-
void Scene::paletteEffect(byte step) {
- Resources *res = Resources::instance();
- byte *src = res->dseg.ptr(0x6609);
- byte *dst = palette + 3 * 0xf2;
- for (byte i = 0; i < 0xd; ++i) {
+ byte *src = _vm->res->dseg.ptr(dsAddr_paletteEffectData);
+ byte *dst = palette + (3 * 242);
+ for (byte i = 0; i < 13; ++i) {
for (byte c = 0; c < 3; ++c, ++src)
*dst++ = *src > step ? *src - step : 0;
}
@@ -584,9 +574,9 @@ byte Scene::findFade() const {
if (_id <= 0)
return 0;
- const Common::Array<FadeType> &scene_fades = fades[_id - 1];
- for (uint i = 0; i < scene_fades.size(); ++i) {
- const FadeType &fade = scene_fades[i];
+ const Common::Array<FadeType> &sceneFades = fades[_id - 1];
+ for (uint i = 0; i < sceneFades.size(); ++i) {
+ const FadeType &fade = sceneFades[i];
if (fade.rect.in(position)) {
return fade.value;
}
@@ -594,110 +584,109 @@ byte Scene::findFade() const {
return 0;
}
-bool Scene::render(bool tick_game, bool tick_mark, uint32 delta) {
- Resources *res = Resources::instance();
+bool Scene::render(bool tickGame, bool tickMark, uint32 messageDelta) {
bool busy;
bool restart;
- uint32 game_delta = tick_game ? 1 : 0;
- uint32 mark_delta = tick_mark ? 1 : 0;
+ uint32 gameDelta = tickGame ? 1 : 0;
+ uint32 markDelta = tickMark ? 1 : 0;
do {
restart = false;
busy = processEventQueue();
- if (_fade_timer && game_delta != 0) {
- if (_fade_timer > 0) {
- _fade_timer -= game_delta;
- setPalette(_fade_timer);
+ if (_fadeTimer && gameDelta != 0) {
+ if (_fadeTimer > 0) {
+ _fadeTimer -= gameDelta;
+ setPalette(_fadeTimer);
} else {
- _fade_timer += game_delta;
- setPalette(_fade_timer + 4);
+ _fadeTimer += gameDelta;
+ setPalette(_fadeTimer + 4);
}
}
- switch (current_event.type) {
+ switch (currentEvent.type) {
case SceneEvent::kCredits: {
- _system->fillScreen(0);
- ///\todo: optimize me
- Graphics::Surface *surface = _system->lockScreen();
- res->font7.render(surface, current_event.dst.x, current_event.dst.y -= game_delta, current_event.message, current_event.color);
- _system->unlockScreen();
-
- if (current_event.dst.y < -(int)current_event.timer)
- current_event.clear();
+ _vm->_system->fillScreen(0);
+ // TODO: optimize me
+ Graphics::Surface *surface = _vm->_system->lockScreen();
+ _vm->res->font7.render(surface, currentEvent.dst.x, currentEvent.dst.y -= gameDelta, currentEvent.message, currentEvent.color);
+ _vm->_system->unlockScreen();
+
+ if (currentEvent.dst.y < -(int)currentEvent.timer)
+ currentEvent.clear();
}
return true;
default:
;
}
- if (!message.empty() && message_timer != 0) {
- if (message_timer <= delta) {
+ if (!message.empty() && messageTimer != 0) {
+ if (messageTimer <= messageDelta) {
clearMessage();
nextEvent();
continue;
} else
- message_timer -= delta;
+ messageTimer -= messageDelta;
}
- if (current_event.type == SceneEvent::kCreditsMessage) {
- _system->fillScreen(0);
- Graphics::Surface *surface = _system->lockScreen();
- if (current_event.lan == 8) {
- res->font8.shadow_color = current_event.orientation;
- res->font8.render(surface, current_event.dst.x, current_event.dst.y, message, current_event.color);
+ if (currentEvent.type == SceneEvent::kCreditsMessage) {
+ _vm->_system->fillScreen(0);
+ Graphics::Surface *surface = _vm->_system->lockScreen();
+ if (currentEvent.lan == 8) {
+ _vm->res->font8.setShadowColor(currentEvent.orientation);
+ _vm->res->font8.render(surface, currentEvent.dst.x, currentEvent.dst.y, message, currentEvent.color);
} else {
- res->font7.render(surface, current_event.dst.x, current_event.dst.y, message, 0xd1);
+ _vm->res->font7.render(surface, currentEvent.dst.x, currentEvent.dst.y, message, textColorCredits);
}
- _system->unlockScreen();
+ _vm->_system->unlockScreen();
return true;
}
- if (background.pixels && debug_features.feature[DebugFeatures::kShowBack]) {
- _system->copyRectToScreen(background.pixels, background.pitch, 0, 0, background.w, background.h);
+ if (background.pixels && debugFeatures.feature[DebugFeatures::kShowBack]) {
+ _vm->_system->copyRectToScreen(background.pixels, background.pitch, 0, 0, background.w, background.h);
} else
- _system->fillScreen(0);
+ _vm->_system->fillScreen(0);
- Graphics::Surface *surface = _system->lockScreen();
+ Graphics::Surface *surface = _vm->_system->lockScreen();
- bool got_any_animation = false;
+ bool gotAnyAnimation = false;
- if (ons != NULL && debug_features.feature[DebugFeatures::kShowOns]) {
- for (uint32 i = 0; i < ons_count; ++i) {
+ if (ons != NULL && debugFeatures.feature[DebugFeatures::kShowOns]) {
+ for (uint32 i = 0; i < onsCount; ++i) {
Surface *s = ons + i;
if (s != NULL)
s->render(surface);
}
}
- Common::List<Surface *> z_order;
+ Common::List<Surface *> zOrder;
for (byte i = 0; i < 4; ++i) {
- Animation *a = custom_animation + i;
- Surface *s = a->currentFrame(game_delta);
+ Animation *a = customAnimation + i;
+ Surface *s = a->currentFrame(gameDelta);
if (s != NULL) {
if (!a->ignore)
busy = true;
if (!a->paused && !a->loop)
- got_any_animation = true;
+ gotAnyAnimation = true;
} else {
a = animation + i;
- if (!custom_animation[i].empty()) {
- debug(0, "custom animation ended, restart animation in the same slot.");
- custom_animation[i].free();
+ if (!customAnimation[i].empty()) {
+ debugC(0, kDebugScene, "custom animation ended, restart animation in the same slot.");
+ customAnimation[i].free();
a->restart();
}
- s = a->currentFrame(game_delta);
+ s = a->currentFrame(gameDelta);
}
- if (current_event.type == SceneEvent::kWaitLanAnimationFrame && current_event.slot == i) {
+ if (currentEvent.type == SceneEvent::kWaitLanAnimationFrame && currentEvent.slot == i) {
if (s == NULL) {
restart |= nextEvent();
continue;
}
int index = a->currentIndex();
- if (index == current_event.animation) {
- debug(0, "kWaitLanAnimationFrame(%d, %d) complete", current_event.slot, current_event.animation);
+ if (index == currentEvent.animation) {
+ debugC(0, kDebugScene, "kWaitLanAnimationFrame(%d, %d) complete", currentEvent.slot, currentEvent.animation);
restart |= nextEvent();
}
}
@@ -705,8 +694,8 @@ bool Scene::render(bool tick_game, bool tick_mark, uint32 delta) {
if (s == NULL)
continue;
- if (debug_features.feature[DebugFeatures::kShowLan])
- z_order.push_back(s);
+ if (debugFeatures.feature[DebugFeatures::kShowLan])
+ zOrder.push_back(s);
if (a->id == 0)
continue;
@@ -722,38 +711,36 @@ bool Scene::render(bool tick_game, bool tick_mark, uint32 delta) {
}
}
- Common::sort(z_order.begin(), z_order.end(), ZOrderCmp());
- Common::List<Surface *>::iterator z_order_it;
+ Common::sort(zOrder.begin(), zOrder.end(), ZOrderCmp());
+ Common::List<Surface *>::iterator zOrderIter;
- Surface *mark = actor_animation.currentFrame(game_delta);
+ Surface *mark = actorAnimation.currentFrame(gameDelta);
int horizon = position.y;
- for (z_order_it = z_order.begin(); z_order_it != z_order.end(); ++z_order_it) {
- Surface *s = *z_order_it;
+ for (zOrderIter = zOrder.begin(); zOrderIter != zOrder.end(); ++zOrderIter) {
+ Surface *s = *zOrderIter;
if (s->y + s->h > horizon)
break;
s->render(surface);
}
if (mark != NULL) {
- actor_animation_position = mark->render(surface);
- if (!actor_animation.ignore)
+ actorAnimationPosition = mark->render(surface);
+ if (!actorAnimation.ignore)
busy = true;
else
busy = false;
- got_any_animation = true;
- } else if (!hide_actor) {
- actor_animation.free();
+ gotAnyAnimation = true;
+ } else if (!hideActor) {
+ actorAnimation.free();
uint zoom = lookupZoom(position.y);
- {
- byte fade = findFade();
- static byte old_fade = 0;
- if (fade != old_fade) {
- old_fade = fade;
- paletteEffect(fade);
- if (_fade_timer == 0)
- setPalette(4);
- }
+
+ byte fade = findFade();
+ if (fade != _fadeOld) {
+ _fadeOld = fade;
+ paletteEffect(fade);
+ if (_fadeTimer == 0)
+ setPalette(4);
}
if (!path.empty()) {
@@ -767,31 +754,31 @@ bool Scene::render(bool tick_game, bool tick_mark, uint32 delta) {
o = dp.y > 0 ? kActorDown : kActorUp;
}
- if (tick_mark) {
- int speed_x = zoom / 32; //8 * zoom / 256
- int speed_y = (o == kActorDown || o == kActorUp ? 2 : 1) * zoom / 256;
- if (speed_x == 0)
- speed_x = 1;
- if (speed_y == 0)
- speed_y = 1;
+ if (tickMark) {
+ int speedX = zoom / 32; // 8 * zoom / 256
+ int speedY = (o == kActorDown || o == kActorUp ? 2 : 1) * zoom / 256;
+ if (speedX == 0)
+ speedX = 1;
+ if (speedY == 0)
+ speedY = 1;
- position.y += (ABS(dp.y) < speed_y ? dp.y : SIGN(dp.y) * speed_y);
+ position.y += (ABS(dp.y) < speedY ? dp.y : SIGN(dp.y) * speedY);
position.x += (o == kActorDown || o == kActorUp) ?
- (ABS(dp.x) < speed_y ? dp.x : SIGN(dp.x) * speed_y) :
- (ABS(dp.x) < speed_x ? dp.x : SIGN(dp.x) * speed_x);
+ (ABS(dp.x) < speedY ? dp.x : SIGN(dp.x) * speedY) :
+ (ABS(dp.x) < speedX ? dp.x : SIGN(dp.x) * speedX);
}
- _idle_timer = 0;
- teenagent_idle.resetIndex();
- actor_animation_position = teenagent.render(surface, position, o, mark_delta, false, zoom);
+ _idleTimer = 0;
+ teenagentIdle.resetIndex();
+ actorAnimationPosition = teenagent.render(surface, position, o, markDelta, false, zoom);
- if (tick_mark && position == destination) {
+ if (tickMark && position == destination) {
path.pop_front();
if (path.empty()) {
if (orientation == 0)
- orientation = o; //save last orientation
+ orientation = o; // save last orientation
nextEvent();
- got_any_animation = true;
+ gotAnyAnimation = true;
restart = true;
}
busy = true;
@@ -799,65 +786,63 @@ bool Scene::render(bool tick_game, bool tick_mark, uint32 delta) {
busy = true;
} else {
teenagent.resetIndex();
- _idle_timer += mark_delta;
- if (_idle_timer < 50)
- actor_animation_position = teenagent.render(surface, position, orientation, 0, actor_talking, zoom);
+ _idleTimer += markDelta;
+ if (_idleTimer < 50)
+ actorAnimationPosition = teenagent.render(surface, position, orientation, 0, actorTalking, zoom);
else
- actor_animation_position = teenagent_idle.renderIdle(surface, position, orientation, mark_delta, zoom, _engine->_rnd);
+ actorAnimationPosition = teenagentIdle.renderIdle(surface, position, orientation, markDelta, zoom, _vm->_rnd);
}
}
if (restart) {
- _system->unlockScreen();
+ _vm->_system->unlockScreen();
continue;
}
- //removed mark == null. In final scene of chapter 2 mark rendered above table.
- //if it'd cause any bugs, add hack here. (_id != 23 && mark == NULL)
- if (on_enabled &&
- debug_features.feature[DebugFeatures::kShowOn]) {
- on.render(surface, actor_animation_position);
- }
+ // removed mark == null. In final scene of chapter 2 mark rendered above table.
+ // if it'd cause any bugs, add hack here. (_id != 23 && mark == NULL)
+ if (onEnabled && debugFeatures.feature[DebugFeatures::kShowOn])
+ on.render(surface, actorAnimationPosition);
- for (; z_order_it != z_order.end(); ++z_order_it) {
- Surface *s = *z_order_it;
+ for (; zOrderIter != zOrder.end(); ++zOrderIter) {
+ Surface *s = *zOrderIter;
s->render(surface);
}
if (!message.empty()) {
bool visible = true;
- if (message_first_frame != 0 && message_animation != NULL) {
- int index = message_animation->currentIndex() + 1;
- //debug(0, "message: %s first: %u index: %u", message.c_str(), message_first_frame, index);
- if (index < message_first_frame)
+ if (messageFirstFrame != 0 && messageAnimation != NULL) {
+ int index = messageAnimation->currentIndex() + 1;
+ debugC(0, kDebugScene, "message: %s first: %u index: %u", message.c_str(), messageFirstFrame, index);
+ if (index < messageFirstFrame)
visible = false;
- if (index > message_last_frame) {
+ if (index > messageLastFrame) {
clearMessage();
visible = false;
}
}
if (visible) {
- res->font7.render(surface, message_pos.x, message_pos.y, message, message_color);
+ _vm->res->font7.render(surface, messagePos.x, messagePos.y, message, messageColor);
busy = true;
}
}
- if (!busy && !restart && tick_game && callback_timer) {
- if (--callback_timer == 0) {
- if (_engine->inventory->active())
- _engine->inventory->activate(false);
- _engine->processCallback(callback);
+ if (!busy && !restart && tickGame && callbackTimer) {
+ if (--callbackTimer == 0) {
+ if (_vm->inventory->active())
+ _vm->inventory->activate(false);
+ _vm->processCallback(callback);
}
- //debug(0, "callback timer = %u", callback_timer);
+ debugC(0, kDebugScene, "callback timer = %u", callbackTimer);
}
//if (!current_event.empty())
// current_event.dump();
- if (!debug_features.feature[DebugFeatures::kHidePath]) {
- const Common::Array<Walkbox> & scene_walkboxes = walkboxes[_id - 1];
- for (uint i = 0; i < scene_walkboxes.size(); ++i) {
- scene_walkboxes[i].rect.render(surface, 0xd0 + i);
+ if (!debugFeatures.feature[DebugFeatures::kHidePath]) {
+ const Common::Array<Walkbox> & sceneWalkboxes = walkboxes[_id - 1];
+ for (uint i = 0; i < sceneWalkboxes.size(); ++i) {
+ sceneWalkboxes[i].rect.render(surface, 0xd0 + i);
}
Common::Point last_p = position;
@@ -872,39 +857,39 @@ bool Scene::render(bool tick_game, bool tick_mark, uint32 delta) {
}
}
- _system->unlockScreen();
+ _vm->_system->unlockScreen();
- if (current_event.type == SceneEvent::kWait) {
- if (current_event.timer > delta) {
+ if (currentEvent.type == SceneEvent::kWait) {
+ if (currentEvent.timer > messageDelta) {
busy = true;
- current_event.timer -= delta;
+ currentEvent.timer -= messageDelta;
}
- if (current_event.timer <= delta)
+ if (currentEvent.timer <= messageDelta)
restart |= nextEvent();
}
- if (!restart && current_event.type == SceneEvent::kWaitForAnimation && !got_any_animation) {
- debug(0, "no animations, nextevent");
+ if (!restart && currentEvent.type == SceneEvent::kWaitForAnimation && !gotAnyAnimation) {
+ debugC(0, kDebugScene, "no animations, nextevent");
nextEvent();
restart = true;
}
if (busy) {
- _idle_timer = 0;
- teenagent_idle.resetIndex();
+ _idleTimer = 0;
+ teenagentIdle.resetIndex();
}
} while (restart);
for (Sounds::iterator i = sounds.begin(); i != sounds.end();) {
Sound &sound = *i;
if (sound.delay == 0) {
- debug(1, "sound %u started", sound.id);
- _engine->playSoundNow(sound.id);
+ debugC(1, kDebugScene, "sound %u started", sound.id);
+ _vm->playSoundNow(sound.id);
i = sounds.erase(i);
} else {
- sound.delay -= game_delta;
+ sound.delay -= gameDelta;
++i;
}
}
@@ -913,363 +898,364 @@ bool Scene::render(bool tick_game, bool tick_mark, uint32 delta) {
}
bool Scene::processEventQueue() {
- while (!events.empty() && current_event.empty()) {
- //debug(0, "processing next event");
- current_event = events.front();
+ while (!events.empty() && currentEvent.empty()) {
+ debugC(0, kDebugScene, "processing next event");
+ currentEvent = events.front();
events.pop_front();
- switch (current_event.type) {
+ switch (currentEvent.type) {
case SceneEvent::kSetOn: {
- byte on_id = current_event.ons;
- if (on_id != 0) {
- --on_id;
- byte *ptr = getOns(current_event.scene == 0 ? _id : current_event.scene);
- debug(0, "on[%u] = %02x", on_id, current_event.color);
- ptr[on_id] = current_event.color;
+ byte onId = currentEvent.ons;
+ if (onId != 0) {
+ --onId;
+ byte *ptr = getOns(currentEvent.scene == 0 ? _id : currentEvent.scene);
+ debugC(0, kDebugScene, "on[%u] = %02x", onId, currentEvent.color);
+ ptr[onId] = currentEvent.color;
} else {
- on_enabled = current_event.color != 0;
- debug(0, "%s on rendering", on_enabled ? "enabling" : "disabling");
+ onEnabled = currentEvent.color != 0;
+ debugC(0, kDebugScene, "%s on rendering", onEnabled ? "enabling" : "disabling");
}
loadOns();
- current_event.clear();
+ currentEvent.clear();
}
break;
case SceneEvent::kSetLan: {
- if (current_event.lan != 0) {
- debug(0, "lan[%u] = %02x", current_event.lan - 1, current_event.color);
- byte *ptr = getLans(current_event.scene == 0 ? _id : current_event.scene);
- ptr[current_event.lan - 1] = current_event.color;
+ if (currentEvent.lan != 0) {
+ debugC(0, kDebugScene, "lan[%u] = %02x", currentEvent.lan - 1, currentEvent.color);
+ byte *ptr = getLans(currentEvent.scene == 0 ? _id : currentEvent.scene);
+ ptr[currentEvent.lan - 1] = currentEvent.color;
}
loadLans();
- current_event.clear();
+ currentEvent.clear();
}
break;
case SceneEvent::kLoadScene: {
- if (current_event.scene != 0) {
- init(current_event.scene, current_event.dst);
- if (current_event.orientation != 0)
- orientation = current_event.orientation;
+ if (currentEvent.scene != 0) {
+ init(currentEvent.scene, currentEvent.dst);
+ if (currentEvent.orientation != 0)
+ orientation = currentEvent.orientation;
} else {
- //special case, empty scene
+ // special case, empty scene
background.free();
on.free();
delete[] ons;
ons = NULL;
for (byte i = 0; i < 4; ++i) {
animation[i].free();
- custom_animation[i].free();
+ customAnimation[i].free();
}
}
- current_event.clear();
+ currentEvent.clear();
}
break;
case SceneEvent::kWalk: {
- Common::Point dst = current_event.dst;
- if ((current_event.color & 2) != 0) { //relative move
+ Common::Point dst = currentEvent.dst;
+ if ((currentEvent.color & 2) != 0) { // relative move
dst.x += position.x;
dst.y += position.y;
}
- if ((current_event.color & 1) != 0) {
- warp(dst, current_event.orientation);
- current_event.clear();
+ if ((currentEvent.color & 1) != 0) {
+ warp(dst, currentEvent.orientation);
+ currentEvent.clear();
} else
- moveTo(dst, current_event.orientation);
+ moveTo(dst, currentEvent.orientation);
}
break;
case SceneEvent::kCreditsMessage:
case SceneEvent::kMessage: {
- message = current_event.message;
- message_animation = NULL;
- if (current_event.first_frame) {
- message_timer = 0;
- message_first_frame = current_event.first_frame;
- message_last_frame = current_event.last_frame;
- if (current_event.slot > 0) {
- message_animation = custom_animation + (current_event.slot - 1);
- //else if (!animation[current_event.slot].empty())
- // message_animation = animation + current_event.slot;
+ message = currentEvent.message;
+ messageAnimation = NULL;
+ if (currentEvent.firstFrame) {
+ messageTimer = 0;
+ messageFirstFrame = currentEvent.firstFrame;
+ messageLastFrame = currentEvent.lastFrame;
+ if (currentEvent.slot > 0) {
+ messageAnimation = customAnimation + (currentEvent.slot - 1);
+ //else if (!animation[currentEvent.slot].empty())
+ // messageAnimation = animation + currentEvent.slot;
} else
- message_animation = &actor_animation;
- debug(0, "async message %d-%d (slot %u)", message_first_frame, message_last_frame, current_event.slot);
+ messageAnimation = &actorAnimation;
+ debugC(0, kDebugScene, "async message %d-%d (slot %u)", messageFirstFrame, messageLastFrame, currentEvent.slot);
} else {
- message_timer = current_event.timer ? current_event.timer * 110 : messageDuration(message);
- message_first_frame = message_last_frame = 0;
+ messageTimer = currentEvent.timer ? currentEvent.timer * 110 : messageDuration(message);
+ messageFirstFrame = messageLastFrame = 0;
}
Common::Point p;
- if (current_event.dst.x == 0 && current_event.dst.y == 0) {
- p = Common::Point((actor_animation_position.left + actor_animation_position.right) / 2,
- actor_animation_position.top);
+ if (currentEvent.dst.x == 0 && currentEvent.dst.y == 0) {
+ p = Common::Point((actorAnimationPosition.left + actorAnimationPosition.right) / 2,
+ actorAnimationPosition.top);
} else {
- p = current_event.dst;
+ p = currentEvent.dst;
}
- byte message_slot = current_event.slot;
- if (message_slot != 0) {
- --message_slot;
- assert(message_slot < 4);
- const Surface *s = custom_animation[message_slot].currentFrame(0);
+ byte messageSlot = currentEvent.slot;
+ if (messageSlot != 0) {
+ --messageSlot;
+ assert(messageSlot < 4);
+ const Surface *s = customAnimation[messageSlot].currentFrame(0);
if (s == NULL)
- s = animation[message_slot].currentFrame(0);
+ s = animation[messageSlot].currentFrame(0);
if (s != NULL) {
p.x = s->x + s->w / 2;
p.y = s->y;
} else
- warning("no animation in slot %u", message_slot);
+ warning("no animation in slot %u", messageSlot);
}
- message_pos = messagePosition(message, p);
- message_color = current_event.color;
+ messagePos = messagePosition(message, p);
+ messageColor = currentEvent.color;
- if (message_first_frame)
- current_event.clear(); //async message, clearing event
+ if (messageFirstFrame)
+ currentEvent.clear(); // async message, clearing event
}
break;
case SceneEvent::kPlayAnimation: {
- byte slot = current_event.slot & 7; //0 - mark's
- if (current_event.animation != 0) {
- debug(0, "playing animation %u in slot %u(%02x)", current_event.animation, slot, current_event.slot);
+ byte slot = currentEvent.slot & 7; // 0 - mark's
+ if (currentEvent.animation != 0) {
+ debugC(0, kDebugScene, "playing animation %u in slot %u(%02x)", currentEvent.animation, slot, currentEvent.slot);
if (slot != 0) {
--slot;
assert(slot < 4);
- playAnimation(slot, current_event.animation, (current_event.slot & 0x80) != 0, (current_event.slot & 0x40) != 0, (current_event.slot & 0x20) != 0);
+ playAnimation(slot, currentEvent.animation, (currentEvent.slot & 0x80) != 0, (currentEvent.slot & 0x40) != 0, (currentEvent.slot & 0x20) != 0);
} else
- actor_talking = true;
+ actorTalking = true;
} else {
if (slot != 0) {
--slot;
- debug(0, "cancelling animation in slot %u", slot);
+ debugC(0, kDebugScene, "cancelling animation in slot %u", slot);
assert(slot < 4);
- custom_animation[slot].free();
+ customAnimation[slot].free();
} else
- actor_talking = true;
+ actorTalking = true;
}
- current_event.clear();
+ currentEvent.clear();
}
break;
case SceneEvent::kPauseAnimation: {
- byte slot = current_event.slot & 7; //0 - mark's
+ byte slot = currentEvent.slot & 7; // 0 - mark's
if (slot != 0) {
--slot;
- debug(1, "pause animation in slot %u", slot);
- custom_animation[slot].paused = (current_event.slot & 0x80) != 0;
+ debugC(1, kDebugScene, "pause animation in slot %u", slot);
+ customAnimation[slot].paused = (currentEvent.slot & 0x80) != 0;
} else {
- actor_talking = false;
+ actorTalking = false;
}
- current_event.clear();
+ currentEvent.clear();
}
break;
case SceneEvent::kClearAnimations:
for (byte i = 0; i < 4; ++i)
- custom_animation[i].free();
- actor_talking = false;
- current_event.clear();
+ customAnimation[i].free();
+ actorTalking = false;
+ currentEvent.clear();
break;
case SceneEvent::kPlayActorAnimation:
- debug(0, "playing actor animation %u", current_event.animation);
- playActorAnimation(current_event.animation, (current_event.slot & 0x80) != 0, (current_event.slot & 0x20) != 0);
- current_event.clear();
+ debugC(0, kDebugScene, "playing actor animation %u", currentEvent.animation);
+ playActorAnimation(currentEvent.animation, (currentEvent.slot & 0x80) != 0, (currentEvent.slot & 0x20) != 0);
+ currentEvent.clear();
break;
case SceneEvent::kPlayMusic:
- debug(0, "setting music %u", current_event.music);
- _engine->setMusic(current_event.music);
- Resources::instance()->dseg.set_byte(0xDB90, current_event.music);
- current_event.clear();
+ debugC(0, kDebugScene, "setting music %u", currentEvent.music);
+ _vm->setMusic(currentEvent.music);
+ _vm->res->dseg.set_byte(dsAddr_currentMusic, currentEvent.music);
+ currentEvent.clear();
break;
case SceneEvent::kPlaySound:
- debug(0, "playing sound %u, delay: %u", current_event.sound, current_event.color);
- sounds.push_back(Sound(current_event.sound, current_event.color));
- current_event.clear();
+ debugC(0, kDebugScene, "playing sound %u, delay: %u", currentEvent.sound, currentEvent.color);
+ sounds.push_back(Sound(currentEvent.sound, currentEvent.color));
+ currentEvent.clear();
break;
case SceneEvent::kEnableObject: {
- debug(0, "%s object #%u", current_event.color ? "enabling" : "disabling", current_event.object - 1);
- Object *obj = getObject(current_event.object - 1, current_event.scene == 0 ? _id : current_event.scene);
- obj->enabled = current_event.color;
+ debugC(0, kDebugScene, "%s object #%u", currentEvent.color ? "enabling" : "disabling", currentEvent.object - 1);
+ Object *obj = getObject(currentEvent.object - 1, currentEvent.scene == 0 ? _id : currentEvent.scene);
+ obj->enabled = currentEvent.color;
obj->save();
- current_event.clear();
+ currentEvent.clear();
}
break;
case SceneEvent::kHideActor:
- hide_actor = current_event.color != 0;
- current_event.clear();
+ hideActor = currentEvent.color != 0;
+ currentEvent.clear();
break;
case SceneEvent::kWaitForAnimation:
- debug(0, "waiting for the animation");
+ debugC(0, kDebugScene, "waiting for the animation");
break;
case SceneEvent::kWaitLanAnimationFrame:
- debug(0, "waiting for the frame %d in slot %d", current_event.animation, current_event.slot);
+ debugC(0, kDebugScene, "waiting for the frame %d in slot %d", currentEvent.animation, currentEvent.slot);
break;
case SceneEvent::kTimer:
- callback = current_event.callback;
- callback_timer = current_event.timer;
- debug(0, "triggering callback %04x in %u frames", callback, callback_timer);
- current_event.clear();
+ callback = currentEvent.callback;
+ callbackTimer = currentEvent.timer;
+ debugC(0, kDebugScene, "triggering callback %04x in %u frames", callback, callbackTimer);
+ currentEvent.clear();
break;
case SceneEvent::kEffect:
- _system->delayMillis(80); //2 vsyncs
- _system->setShakePos(8);
- _system->updateScreen();
+ _vm->_system->delayMillis(80); // 2 vsyncs
+ _vm->_system->setShakePos(8);
+ _vm->_system->updateScreen();
- _system->delayMillis(80); //2 vsyncs
- _system->setShakePos(0);
- _system->updateScreen();
+ _vm->_system->delayMillis(80); // 2 vsyncs
+ _vm->_system->setShakePos(0);
+ _vm->_system->updateScreen();
- _system->delayMillis(80); //2 vsyncs
- _system->setShakePos(4);
- _system->updateScreen();
+ _vm->_system->delayMillis(80); // 2 vsyncs
+ _vm->_system->setShakePos(4);
+ _vm->_system->updateScreen();
- _system->delayMillis(80); //2 vsyncs
- _system->setShakePos(0);
- _system->updateScreen();
+ _vm->_system->delayMillis(80); // 2 vsyncs
+ _vm->_system->setShakePos(0);
+ _vm->_system->updateScreen();
- current_event.clear();
+ currentEvent.clear();
break;
case SceneEvent::kFade:
- _fade_timer = current_event.orientation != 0 ? 5 : -5;
- current_event.clear();
+ _fadeTimer = currentEvent.orientation != 0 ? 5 : -5;
+ currentEvent.clear();
break;
case SceneEvent::kWait:
- debug(0, "wait %u", current_event.timer);
+ debugC(0, kDebugScene, "wait %u", currentEvent.timer);
break;
case SceneEvent::kCredits:
- debug(0, "showing credits");
+ debugC(0, kDebugScene, "showing credits");
break;
case SceneEvent::kQuit:
- debug(0, "quit!");
- _engine->quitGame();
+ debugC(0, kDebugScene, "quit!");
+ _vm->quitGame();
break;
case SceneEvent::kSetFlag:
- debug(0, "async set_flag(%04x, %d)", current_event.callback, current_event.color);
- Resources::instance()->dseg.set_byte(current_event.callback, current_event.color);
- current_event.clear();
+ debugC(0, kDebugScene, "async set_flag(%04x, %d)", currentEvent.callback, currentEvent.color);
+ _vm->res->dseg.set_byte(currentEvent.callback, currentEvent.color);
+ currentEvent.clear();
break;
default:
- error("empty/unhandler event[%d]", (int)current_event.type);
+ error("empty/unhandler event[%d]", (int)currentEvent.type);
}
}
+
if (events.empty()) {
- message_color = 0xd1;
- hide_actor = false;
+ messageColor = textColorMark;
+ hideActor = false;
}
- return !current_event.empty();
+
+ return !currentEvent.empty();
}
void Scene::setPalette(unsigned mul) {
- //debug(0, "setPalette(%u)", mul);
+ debugC(0, kDebugScene, "setPalette(%u)", mul);
byte p[3 * 256];
for (int i = 0; i < 3 * 256; ++i) {
p[i] = (unsigned)palette[i] * mul;
}
- _system->getPaletteManager()->setPalette(p, 0, 256);
+ _vm->_system->getPaletteManager()->setPalette(p, 0, 256);
}
-Object *Scene::getObject(int id, int scene_id) {
+Object *Scene::getObject(int id, int sceneId) {
assert(id > 0);
- if (scene_id == 0)
- scene_id = _id;
+ if (sceneId == 0)
+ sceneId = _id;
- if (scene_id == 0)
+ if (sceneId == 0)
return NULL;
- Common::Array<Object> &scene_objects = objects[scene_id - 1];
+ Common::Array<Object> &sceneObjects = objects[sceneId - 1];
--id;
- if (id >= (int)scene_objects.size())
+ if (id >= (int)sceneObjects.size())
return NULL;
- return &scene_objects[id];
+ return &sceneObjects[id];
}
-Common::Point Scene::messagePosition(const Common::String &str, Common::Point message_position) {
- Resources *res = Resources::instance();
+Common::Point Scene::messagePosition(const Common::String &str, Common::Point pos) {
int lines = 1;
for (uint i = 0; i < str.size(); ++i)
if (str[i] == '\n')
++lines;
- uint w = res->font7.render(NULL, 0, 0, str, 0);
- uint h = res->font7.height * lines + 3;
+ uint w = _vm->res->font7.render(NULL, 0, 0, str, 0);
+ uint h = _vm->res->font7.getHeight() * lines + 3;
- message_position.x -= w / 2;
- message_position.y -= h;
+ pos.x -= w / 2;
+ pos.y -= h;
- if (message_position.x + w > 320)
- message_position.x = 320 - w;
- if (message_position.x < 0)
- message_position.x = 0;
- if (message_position.y + h > 320)
- message_position.y = 200 - h;
- if (message_position.y < 0)
- message_position.y = 0;
+ if (pos.x + w > kScreenWidth)
+ pos.x = kScreenWidth - w;
+ if (pos.x < 0)
+ pos.x = 0;
+ if (pos.y + h > kScreenHeight)
+ pos.y = kScreenHeight - h;
+ if (pos.y < 0)
+ pos.y = 0;
- return message_position;
+ return pos;
}
uint Scene::messageDuration(const Common::String &str) {
- //original game uses static delays: 100-slow, 50, 20 and 1 tick - crazy speed.
- //total delay = total message length * delay / 8 + 60.
- uint total_width = str.size();
+ // original game uses static delays: 100-slow, 50, 20 and 1 tick - crazy speed.
+ // total delay = total message length * delay / 8 + 60.
+ uint totalWidth = str.size();
- int speed = Common::ConfigManager::instance().getInt("talkspeed");
+ int speed = ConfMan.getInt("talkspeed");
if (speed < 0)
speed = 60;
- uint delay_delta = 1 + (255 - speed) * 99 / 255;
+ uint delayDelta = 1 + (255 - speed) * 99 / 255;
- uint delay = 60 + (total_width * delay_delta) / 8;
- //debug(0, "delay = %u, delta: %u", delay, delay_delta);
+ uint delay = 60 + (totalWidth * delayDelta) / 8;
+ debugC(0, kDebugScene, "delay = %u, delta: %u", delay, delayDelta);
return delay * 10;
}
void Scene::displayMessage(const Common::String &str, byte color, const Common::Point &pos) {
//assert(!str.empty());
- //debug(0, "displayMessage: %s", str.c_str());
+ debugC(0, kDebugScene, "displayMessage: %s", str.c_str());
message = str;
- message_pos = (pos.x | pos.y) ? pos : messagePosition(str, position);
- message_color = color;
- message_timer = messageDuration(message);
+ messagePos = (pos.x | pos.y) ? pos : messagePosition(str, position);
+ messageColor = color;
+ messageTimer = messageDuration(message);
}
void Scene::clear() {
clearMessage();
events.clear();
- current_event.clear();
+ currentEvent.clear();
for (int i = 0; i < 4; ++i) {
animation[i].free();
- custom_animation[i].free();
+ customAnimation[i].free();
}
callback = 0;
- callback_timer = 0;
+ callbackTimer = 0;
}
void Scene::clearMessage() {
message.clear();
- message_timer = 0;
- message_color = 0xd1;
- message_first_frame = 0;
- message_last_frame = 0;
- message_animation = NULL;
+ messageTimer = 0;
+ messageColor = textColorMark;
+ messageFirstFrame = 0;
+ messageLastFrame = 0;
+ messageAnimation = NULL;
}
} // End of namespace TeenAgent
diff --git a/engines/teenagent/scene.h b/engines/teenagent/scene.h
index 32e784bb60..14aefa0cca 100644
--- a/engines/teenagent/scene.h
+++ b/engines/teenagent/scene.h
@@ -27,8 +27,8 @@
#include "teenagent/objects.h"
#include "teenagent/surface.h"
#include "teenagent/surface_list.h"
+#include "teenagent/teenagent.h"
-#include "common/system.h"
#include "common/array.h"
#include "common/list.h"
@@ -39,7 +39,6 @@ struct Event;
namespace TeenAgent {
class TeenAgentEngine;
-class Dialog;
struct SceneEvent {
enum Type {
@@ -84,22 +83,22 @@ struct SceneEvent {
byte lan;
union {
byte music;
- byte first_frame;
+ byte firstFrame;
};
union {
byte sound;
- byte last_frame;
+ byte lastFrame;
};
byte object;
SceneEvent(Type type_) :
- type(type_), message(), color(0xd1), slot(0), animation(0), timer(0), orientation(0), dst(),
+ type(type_), message(), color(textColorMark), slot(0), animation(0), timer(0), orientation(0), dst(),
scene(0), ons(0), lan(0), music(0), sound(0), object(0) {}
void clear() {
type = kNone;
message.clear();
- color = 0xd1;
+ color = textColorMark;
slot = 0;
orientation = 0;
animation = 0;
@@ -118,7 +117,7 @@ struct SceneEvent {
}
void dump() const {
- debug(0, "event[%d]: \"%s\"[%02x], slot: %d, animation: %u, timer: %u, dst: (%d, %d) [%u], scene: %u, ons: %u, lan: %u, object: %u, music: %u, sound: %u",
+ debugC(0, kDebugScene, "event[%d]: \"%s\"[%02x], slot: %d, animation: %u, timer: %u, dst: (%d, %d) [%u], scene: %u, ons: %u, lan: %u, object: %u, music: %u, sound: %u",
(int)type, message.c_str(), color, slot, animation, timer, dst.x, dst.y, orientation, scene, ons, lan, object, music, sound
);
}
@@ -126,13 +125,13 @@ struct SceneEvent {
class Scene {
public:
- Scene(TeenAgentEngine *engine, OSystem *system);
+ Scene(TeenAgentEngine *engine);
~Scene();
bool intro;
void init(int id, const Common::Point &pos);
- bool render(bool tick_game, bool tick_mark, uint32 message_delta);
+ bool render(bool tickGame, bool tickMark, uint32 messageDelta);
int getId() const { return _id; }
void warp(const Common::Point &point, byte orientation = 0);
@@ -140,7 +139,7 @@ public:
void moveTo(const Common::Point &point, byte orientation = 0, bool validate = false);
Common::Point getPosition() const { return position; }
- void displayMessage(const Common::String &str, byte color = 0xd1, const Common::Point &pos = Common::Point());
+ void displayMessage(const Common::String &str, byte color = textColorMark, const Common::Point &pos = Common::Point());
void setOrientation(uint8 o) { orientation = o; }
void push(const SceneEvent &event);
byte peekFlagEvent(uint16 addr) const;
@@ -153,15 +152,15 @@ public:
byte *getOns(int id);
byte *getLans(int id);
- bool eventRunning() const { return !current_event.empty(); }
+ bool eventRunning() const { return !currentEvent.empty(); }
Walkbox *getWalkbox(byte id) { return &walkboxes[_id - 1][id]; }
- Object *getObject(int id, int scene_id = 0);
+ Object *getObject(int id, int sceneId = 0);
Object *findObject(const Common::Point &point);
void loadObjectData();
Animation *getAnimation(byte slot);
- inline Animation *getActorAnimation() { return &actor_animation; }
+ inline Animation *getActorAnimation() { return &actorAnimation; }
inline const Common::String &getMessage() const { return message; }
void setPalette(unsigned mul);
int lookupZoom(uint y) const;
@@ -173,39 +172,38 @@ private:
void playAnimation(byte idx, uint id, bool loop, bool paused, bool ignore);
void playActorAnimation(uint id, bool loop, bool ignore);
- byte palette[768];
+ byte palette[3 * 256];
void paletteEffect(byte step);
byte findFade() const;
- static Common::Point messagePosition(const Common::String &str, Common::Point position);
- static uint messageDuration(const Common::String &str);
+ Common::Point messagePosition(const Common::String &str, Common::Point pos);
+ uint messageDuration(const Common::String &str);
bool processEventQueue();
inline bool nextEvent() {
- current_event.clear();
+ currentEvent.clear();
return processEventQueue();
}
void clearMessage();
- TeenAgentEngine *_engine;
- OSystem *_system;
+ TeenAgentEngine *_vm;
int _id;
Graphics::Surface background;
SurfaceList on;
- bool on_enabled;
+ bool onEnabled;
Surface *ons;
- uint32 ons_count;
- Animation actor_animation, animation[4], custom_animation[4];
- Common::Rect actor_animation_position, animation_position[4];
+ uint32 onsCount;
+ Animation actorAnimation, animation[4], customAnimation[4];
+ Common::Rect actorAnimationPosition, animationPosition[4];
- Actor teenagent, teenagent_idle;
+ Actor teenagent, teenagentIdle;
Common::Point position;
typedef Common::List<Common::Point> Path;
Path path;
uint8 orientation;
- bool actor_talking;
+ bool actorTalking;
bool findPath(Path &p, const Common::Point &src, const Common::Point &dst) const;
@@ -214,22 +212,24 @@ private:
Common::Array<Common::Array<FadeType> > fades;
Common::String message;
- Common::Point message_pos;
- byte message_color;
- uint message_timer;
- byte message_first_frame;
- byte message_last_frame;
- Animation *message_animation;
+ Common::Point messagePos;
+ byte messageColor;
+ uint messageTimer;
+ byte messageFirstFrame;
+ byte messageLastFrame;
+ Animation *messageAnimation;
typedef Common::List<SceneEvent> EventList;
EventList events;
- SceneEvent current_event;
- bool hide_actor;
+ SceneEvent currentEvent;
+ bool hideActor;
- uint16 callback, callback_timer;
+ uint16 callback, callbackTimer;
- int _fade_timer;
- uint _idle_timer;
+ int _fadeTimer;
+ byte _fadeOld;
+
+ uint _idleTimer;
struct Sound {
byte id, delay;
@@ -254,7 +254,7 @@ private:
feature[i] = true;
}
}
- } debug_features;
+ } debugFeatures;
};
} // End of namespace TeenAgent
diff --git a/engines/teenagent/segment.h b/engines/teenagent/segment.h
index 303198b071..286337d120 100644
--- a/engines/teenagent/segment.h
+++ b/engines/teenagent/segment.h
@@ -41,26 +41,21 @@ public:
assert(offset < _size);
return _data[offset];
}
+
inline uint16 get_word(uint32 offset) const {
assert(offset + 1 < _size);
return READ_LE_UINT16(_data + offset);
}
- inline uint32 get_quad(uint32 offset) const {
- assert(offset + 3 < _size);
- return READ_LE_UINT32(_data + offset);
- }
+
inline void set_byte(uint32 offset, byte v) const {
assert(offset < _size);
_data[offset] = v;
}
+
inline void set_word(uint32 offset, uint16 v) const {
assert(offset + 1 < _size);
return WRITE_LE_UINT16(_data + offset, v);
}
- inline void set_quad(uint32 offset, uint32 v) const {
- assert(offset + 3 < _size);
- return WRITE_LE_UINT32(_data + offset, v);
- }
const byte *ptr(uint32 addr) const {
assert(addr < _size);
@@ -71,6 +66,7 @@ public:
assert(addr < _size);
return _data + addr;
}
+
uint size() const { return _size; }
};
diff --git a/engines/teenagent/surface.cpp b/engines/teenagent/surface.cpp
index 63312990ee..4db25bc749 100644
--- a/engines/teenagent/surface.cpp
+++ b/engines/teenagent/surface.cpp
@@ -21,6 +21,8 @@
#include "teenagent/surface.h"
#include "teenagent/pack.h"
+#include "teenagent/teenagent.h"
+
#include "common/stream.h"
#include "common/debug.h"
@@ -34,7 +36,7 @@ Surface::~Surface() {
}
void Surface::load(Common::SeekableReadStream &stream, Type type) {
- //debug(0, "load()");
+ debugC(0, kDebugSurface, "load()");
free();
x = y = 0;
@@ -44,71 +46,71 @@ void Surface::load(Common::SeekableReadStream &stream, Type type) {
if (type != kTypeLan) {
uint16 pos = stream.readUint16LE();
- x = pos % 320;
- y = pos / 320;
+ x = pos % kScreenWidth;
+ y = pos / kScreenWidth;
}
- //debug(0, "declared info: %ux%u (%04xx%04x) -> %u,%u", w_, h_, w_, h_, x, y);
+ debugC(0, kDebugSurface, "declared info: %ux%u (%04xx%04x) -> %u,%u", w_, h_, w_, h_, x, y);
if (stream.eos() || w_ == 0)
return;
if (w_ * h_ > stream.size()) {
- debug(0, "invalid surface %ux%u -> %u,%u", w_, h_, x, y);
+ debugC(0, kDebugSurface, "invalid surface %ux%u -> %u,%u", w_, h_, x, y);
return;
}
- //debug(0, "creating surface %ux%u -> %u,%u", w_, h_, x, y);
+ debugC(0, kDebugSurface, "creating surface %ux%u -> %u,%u", w_, h_, x, y);
create(w_, h_, Graphics::PixelFormat::createFormatCLUT8());
stream.read(pixels, w_ * h_);
}
-Common::Rect Surface::render(Graphics::Surface *surface, int dx, int dy, bool mirror, Common::Rect src_rect, uint zoom) const {
- if (src_rect.isEmpty()) {
- src_rect = Common::Rect(0, 0, w, h);
+Common::Rect Surface::render(Graphics::Surface *surface, int dx, int dy, bool mirror, Common::Rect srcRect, uint zoom) const {
+ if (srcRect.isEmpty()) {
+ srcRect = Common::Rect(0, 0, w, h);
}
- Common::Rect dst_rect(x + dx, y + dy, x + dx + zoom * src_rect.width() / 256, y + dy + zoom * src_rect.height() / 256);
- if (dst_rect.left < 0) {
- src_rect.left = -dst_rect.left;
- dst_rect.left = 0;
+ Common::Rect dstRect(x + dx, y + dy, x + dx + zoom * srcRect.width() / 256, y + dy + zoom * srcRect.height() / 256);
+ if (dstRect.left < 0) {
+ srcRect.left = -dstRect.left;
+ dstRect.left = 0;
}
- if (dst_rect.right > surface->w) {
- src_rect.right -= dst_rect.right - surface->w;
- dst_rect.right = surface->w;
+ if (dstRect.right > surface->w) {
+ srcRect.right -= dstRect.right - surface->w;
+ dstRect.right = surface->w;
}
- if (dst_rect.top < 0) {
- src_rect.top -= dst_rect.top;
- dst_rect.top = 0;
+ if (dstRect.top < 0) {
+ srcRect.top -= dstRect.top;
+ dstRect.top = 0;
}
- if (dst_rect.bottom > surface->h) {
- src_rect.bottom -= dst_rect.bottom - surface->h;
- dst_rect.bottom = surface->h;
+ if (dstRect.bottom > surface->h) {
+ srcRect.bottom -= dstRect.bottom - surface->h;
+ dstRect.bottom = surface->h;
}
- if (src_rect.isEmpty() || dst_rect.isEmpty())
+ if (srcRect.isEmpty() || dstRect.isEmpty())
return Common::Rect();
if (zoom == 256) {
- const byte *src = (const byte *)getBasePtr(0, src_rect.top);
- byte *dst_base = (byte *)surface->getBasePtr(dst_rect.left, dst_rect.top);
+ const byte *src = (const byte *)getBasePtr(0, srcRect.top);
+ byte *dstBase = (byte *)surface->getBasePtr(dstRect.left, dstRect.top);
- for (int i = src_rect.top; i < src_rect.bottom; ++i) {
- byte *dst = dst_base;
- for (int j = src_rect.left; j < src_rect.right; ++j) {
+ for (int i = srcRect.top; i < srcRect.bottom; ++i) {
+ byte *dst = dstBase;
+ for (int j = srcRect.left; j < srcRect.right; ++j) {
byte p = src[(mirror ? w - j - 1 : j)];
if (p != 0xff)
*dst++ = p;
else
++dst;
}
- dst_base += surface->pitch;
+ dstBase += surface->pitch;
src += pitch;
}
} else {
- byte *dst = (byte *)surface->getBasePtr(dst_rect.left, dst_rect.top);
- for (int i = 0; i < dst_rect.height(); ++i) {
- for (int j = 0; j < dst_rect.width(); ++j) {
+ byte *dst = (byte *)surface->getBasePtr(dstRect.left, dstRect.top);
+ for (int i = 0; i < dstRect.height(); ++i) {
+ for (int j = 0; j < dstRect.width(); ++j) {
int px = j * 256 / zoom;
- const byte *src = (const byte *)getBasePtr(src_rect.left + (mirror ? w - px - 1 : px), src_rect.top + i * 256 / zoom);
+ const byte *src = (const byte *)getBasePtr(srcRect.left + (mirror ? w - px - 1 : px), srcRect.top + i * 256 / zoom);
byte p = *src;
if (p != 0xff)
dst[j] = p;
@@ -116,7 +118,7 @@ Common::Rect Surface::render(Graphics::Surface *surface, int dx, int dy, bool mi
dst += surface->pitch;
}
}
- return dst_rect;
+ return dstRect;
}
} // End of namespace TeenAgent
diff --git a/engines/teenagent/surface.h b/engines/teenagent/surface.h
index 51368c6bee..3e591ed3e0 100644
--- a/engines/teenagent/surface.h
+++ b/engines/teenagent/surface.h
@@ -33,16 +33,17 @@ namespace TeenAgent {
class Surface : public Graphics::Surface {
public:
- enum Type {kTypeOns, kTypeLan};
-
- uint16 x, y;
-
Surface();
~Surface();
+
+ enum Type {kTypeOns, kTypeLan};
+
void load(Common::SeekableReadStream &, Type type);
- Common::Rect render(Graphics::Surface *surface, int dx = 0, int dy = 0, bool mirror = false, Common::Rect src_rect = Common::Rect(), uint zoom = 256) const;
+ Common::Rect render(Graphics::Surface *surface, int dx = 0, int dy = 0, bool mirror = false, Common::Rect srcRect = Common::Rect(), uint zoom = 256) const;
bool empty() const { return pixels == NULL; }
+
+ uint16 x, y;
};
} // End of namespace TeenAgent
diff --git a/engines/teenagent/surface_list.cpp b/engines/teenagent/surface_list.cpp
index 31387ac3cb..e293ce6470 100644
--- a/engines/teenagent/surface_list.cpp
+++ b/engines/teenagent/surface_list.cpp
@@ -19,34 +19,35 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "teenagent/surface.h"
#include "teenagent/surface_list.h"
-#include "objects.h"
+#include "teenagent/surface.h"
+#include "teenagent/objects.h"
+#include "teenagent/teenagent.h"
namespace TeenAgent {
-SurfaceList::SurfaceList() : surfaces(NULL), surfaces_n(0) {}
+SurfaceList::SurfaceList() : surfaces(NULL), surfacesCount(0) {}
SurfaceList::~SurfaceList() {
free();
}
-void SurfaceList::load(Common::SeekableReadStream &stream, Type type, int sub_hack) {
+void SurfaceList::load(Common::SeekableReadStream &stream, int subHack) {
free();
byte fn = stream.readByte();
if (stream.eos())
return;
- surfaces_n = fn - sub_hack;
- debug(0, "loading %u surfaces from list (skip %d)", surfaces_n, sub_hack);
+ surfacesCount = fn - subHack;
+ debugC(0, kDebugSurface, "loading %u surfaces from list (skip %d)", surfacesCount, subHack);
- if (surfaces_n == 0)
+ if (surfacesCount == 0)
return;
- surfaces = new Surface[surfaces_n];
+ surfaces = new Surface[surfacesCount];
- for (byte i = 0; i < surfaces_n; ++i) {
+ for (byte i = 0; i < surfacesCount; ++i) {
uint offset = stream.readUint16LE();
uint pos = stream.pos();
stream.seek(offset);
@@ -58,11 +59,11 @@ void SurfaceList::load(Common::SeekableReadStream &stream, Type type, int sub_ha
void SurfaceList::free() {
delete[] surfaces;
surfaces = NULL;
- surfaces_n = 0;
+ surfacesCount = 0;
}
void SurfaceList::render(Graphics::Surface *surface, const Common::Rect &clip) const {
- for (uint i = 0; i < surfaces_n; ++i) {
+ for (uint i = 0; i < surfacesCount; ++i) {
const Surface &s = surfaces[i];
Common::Rect r(s.x, s.y, s.x + s.w, s.y + s.h);
if (r.bottom < clip.bottom || !clip.intersects(r))
diff --git a/engines/teenagent/surface_list.h b/engines/teenagent/surface_list.h
index 2d7be0d52b..73a41fb5f8 100644
--- a/engines/teenagent/surface_list.h
+++ b/engines/teenagent/surface_list.h
@@ -23,23 +23,23 @@
#define TEENAGENT_SURFACE_LIST_H__
#include "common/stream.h"
+#include "graphics/surface.h"
namespace TeenAgent {
class Surface;
class SurfaceList {
public:
- enum Type { kTypeOn };
-
SurfaceList();
~SurfaceList();
- void load(Common::SeekableReadStream &, Type type, int sub_hack = 0);
+
+ void load(Common::SeekableReadStream &, int subHack = 0);
void free();
void render(Graphics::Surface *surface, const Common::Rect &clip) const;
protected:
Surface *surfaces;
- uint surfaces_n;
+ uint surfacesCount;
};
}
diff --git a/engines/teenagent/teenagent.cpp b/engines/teenagent/teenagent.cpp
index 57c069fe59..0b48a18b26 100644
--- a/engines/teenagent/teenagent.cpp
+++ b/engines/teenagent/teenagent.cpp
@@ -21,6 +21,7 @@
#include "common/config-manager.h"
#include "common/debug.h"
+#include "common/debug-channels.h"
#include "common/events.h"
#include "common/savefile.h"
#include "common/system.h"
@@ -39,26 +40,56 @@
#include "graphics/thumbnail.h"
#include "teenagent/console.h"
+#include "teenagent/dialog.h"
+#include "teenagent/inventory.h"
#include "teenagent/music.h"
#include "teenagent/objects.h"
#include "teenagent/pack.h"
+#include "teenagent/resources.h"
#include "teenagent/scene.h"
#include "teenagent/teenagent.h"
namespace TeenAgent {
TeenAgentEngine::TeenAgentEngine(OSystem *system, const ADGameDescription *gd)
- : Engine(system), action(kActionNone), _gameDescription(gd),
- _rnd("teenagent") {
- music = new MusicPlayer();
+ : Engine(system), _action(kActionNone), _gameDescription(gd), _rnd("teenagent") {
+ DebugMan.addDebugChannel(kDebugActor, "Actor", "Enable Actor Debug");
+ DebugMan.addDebugChannel(kDebugAnimation, "Animation", "Enable Animation Debug");
+ DebugMan.addDebugChannel(kDebugCallbacks, "Callbacks", "Enable Callbacks Debug");
+ DebugMan.addDebugChannel(kDebugDialog, "Dialog", "Enable Dialog Debug");
+ DebugMan.addDebugChannel(kDebugFont, "Font", "Enable Font Debug");
+ DebugMan.addDebugChannel(kDebugInventory, "Inventory", "Enable Inventory Debug");
+ DebugMan.addDebugChannel(kDebugMusic, "Music", "Enable Music Debug");
+ DebugMan.addDebugChannel(kDebugObject, "Object", "Enable Object Debug");
+ DebugMan.addDebugChannel(kDebugPack, "Pack", "Enable Pack Debug");
+ DebugMan.addDebugChannel(kDebugScene, "Scene", "Enable Scene Debug");
+ DebugMan.addDebugChannel(kDebugSurface, "Surface", "Enable Surface Debug");
+
+ music = new MusicPlayer(this);
+ dialog = new Dialog(this);
+ res = new Resources();
console = 0;
}
TeenAgentEngine::~TeenAgentEngine() {
+ delete dialog;
+ dialog = 0;
+ delete scene;
+ scene = 0;
+ delete inventory;
+ inventory = 0;
delete music;
+ music = 0;
+ _mixer->stopAll();
+ _useHotspots.clear();
+ delete res;
+ res = 0;
+
+ CursorMan.popCursor();
delete console;
+ DebugMan.clearAllDebugChannels();
}
bool TeenAgentEngine::trySelectedObject() {
@@ -66,66 +97,64 @@ bool TeenAgentEngine::trySelectedObject() {
if (inv == NULL)
return false;
- Resources *res = Resources::instance();
- debug(0, "checking active object %u on %u", inv->id, dst_object->id);
+ debugC(0, kDebugObject, "checking active object %u on %u", inv->id, _dstObject->id);
//mouse time challenge hack:
- if ((res->dseg.get_byte(0) == 1 && inv->id == 49 && dst_object->id == 5) ||
- (res->dseg.get_byte(0) == 2 && inv->id == 29 && dst_object->id == 5)) {
+ if ((res->dseg.get_byte(dsAddr_timedCallbackState) == 1 && inv->id == kInvItemRock && _dstObject->id == 5) ||
+ (res->dseg.get_byte(dsAddr_timedCallbackState) == 2 && inv->id == kInvItemSuperGlue && _dstObject->id == 5)) {
//putting rock into hole or superglue on rock
- processCallback(0x8d57);
+ fnPutRockInHole();
return true;
}
- const Common::Array<UseHotspot> &hotspots = use_hotspots[scene->getId() - 1];
+ const Common::Array<UseHotspot> &hotspots = _useHotspots[scene->getId() - 1];
for (uint i = 0; i < hotspots.size(); ++i) {
const UseHotspot &spot = hotspots[i];
- if (spot.inventory_id == inv->id && dst_object->id == spot.object_id) {
- debug(0, "use object on hotspot!");
+ if (spot.inventoryId == inv->id && _dstObject->id == spot.objectId) {
+ debugC(0, kDebugObject, "use object on hotspot!");
spot.dump();
- if (spot.actor_x != 0xffff && spot.actor_y != 0xffff)
- moveTo(spot.actor_x, spot.actor_y, spot.orientation);
+ if (spot.actorX != 0xffff && spot.actorY != 0xffff)
+ moveTo(spot.actorX, spot.actorY, spot.orientation);
if (!processCallback(spot.callback))
- debug(0, "fixme! display proper description");
+ debugC(0, kDebugObject, "FIXME: display proper description");
inventory->resetSelectedObject();
return true;
}
}
- //error
+ // error
inventory->resetSelectedObject();
- displayMessage(0x3457);
+ displayMessage(dsAddr_objErrorMsg); // "That's no good"
return true;
}
void TeenAgentEngine::processObject() {
- if (dst_object == NULL)
+ if (_dstObject == NULL)
return;
- Resources *res = Resources::instance();
- switch (action) {
+ switch (_action) {
case kActionExamine: {
if (trySelectedObject())
break;
- byte *dcall = res->dseg.ptr(0xb5ce);
+ byte *dcall = res->dseg.ptr(dsAddr_objExamineCallbackTablePtr);
dcall = res->dseg.ptr(READ_LE_UINT16(dcall + scene->getId() * 2 - 2));
- dcall += 2 * dst_object->id - 2;
+ dcall += 2 * _dstObject->id - 2;
uint16 callback = READ_LE_UINT16(dcall);
if (callback == 0 || !processCallback(callback))
- displayMessage(dst_object->description);
+ displayMessage(_dstObject->description);
}
break;
case kActionUse: {
if (trySelectedObject())
break;
- byte *dcall = res->dseg.ptr(0xb89c);
+ byte *dcall = res->dseg.ptr(dsAddr_objUseCallbackTablePtr);
dcall = res->dseg.ptr(READ_LE_UINT16(dcall + scene->getId() * 2 - 2));
- dcall += 2 * dst_object->id - 2;
+ dcall += 2 * _dstObject->id - 2;
uint16 callback = READ_LE_UINT16(dcall);
if (!processCallback(callback))
- displayMessage(dst_object->description);
+ displayMessage(_dstObject->description);
}
break;
@@ -134,20 +163,19 @@ void TeenAgentEngine::processObject() {
}
}
-
void TeenAgentEngine::use(Object *object) {
if (object == NULL || scene->eventRunning())
return;
- dst_object = object;
+ _dstObject = object;
object->rect.dump();
- object->actor_rect.dump();
+ object->actorRect.dump();
- action = kActionUse;
- if (object->actor_rect.valid())
- scene->moveTo(Common::Point(object->actor_rect.right, object->actor_rect.bottom), object->actor_orientation);
- else if (object->actor_orientation > 0)
- scene->setOrientation(object->actor_orientation);
+ _action = kActionUse;
+ if (object->actorRect.valid())
+ scene->moveTo(Common::Point(object->actorRect.right, object->actorRect.bottom), object->actorOrientation);
+ else if (object->actorOrientation > 0)
+ scene->setOrientation(object->actorOrientation);
}
void TeenAgentEngine::examine(const Common::Point &point, Object *object) {
@@ -155,53 +183,39 @@ void TeenAgentEngine::examine(const Common::Point &point, Object *object) {
return;
if (object != NULL) {
- Common::Point dst = object->actor_rect.center();
- debug(0, "click %d, %d, object %d, %d", point.x, point.y, dst.x, dst.y);
- action = kActionExamine;
- if (object->actor_rect.valid())
- scene->moveTo(dst, object->actor_orientation, true); //validate examine message. Original engine does not let you into walkboxes
- dst_object = object;
- } else if (!scene_busy) {
- //do not reset anything while scene is busy, but allow interrupts while walking.
- debug(0, "click %d, %d", point.x, point.y);
- action = kActionNone;
+ Common::Point dst = object->actorRect.center();
+ debugC(0, kDebugObject, "click %d, %d, object %d, %d", point.x, point.y, dst.x, dst.y);
+ _action = kActionExamine;
+ if (object->actorRect.valid())
+ scene->moveTo(dst, object->actorOrientation, true); // validate examine message. Original engine does not let you into walkboxes
+ _dstObject = object;
+ } else if (!_sceneBusy) {
+ // do not reset anything while scene is busy, but allow interrupts while walking.
+ debugC(0, kDebugObject, "click %d, %d", point.x, point.y);
+ _action = kActionNone;
scene->moveTo(point, 0, true);
- dst_object = NULL;
+ _dstObject = NULL;
}
}
void TeenAgentEngine::init() {
- _mark_delay = 80;
- _game_delay = 110;
+ _markDelay = 80;
+ _gameDelay = 110;
- Resources *res = Resources::instance();
- use_hotspots.resize(42);
- byte *scene_hotspots = res->dseg.ptr(0xbb87);
+ _useHotspots.resize(42);
+ byte *sceneHotspots = res->dseg.ptr(dsAddr_sceneHotspotsPtr);
for (byte i = 0; i < 42; ++i) {
- Common::Array<UseHotspot> & hotspots = use_hotspots[i];
- byte *hotspots_ptr = res->dseg.ptr(READ_LE_UINT16(scene_hotspots + i * 2));
- while (*hotspots_ptr) {
+ Common::Array<UseHotspot> & hotspots = _useHotspots[i];
+ byte *hotspotsPtr = res->dseg.ptr(READ_LE_UINT16(sceneHotspots + i * 2));
+ while (*hotspotsPtr) {
UseHotspot h;
- h.load(hotspots_ptr);
- hotspots_ptr += 9;
+ h.load(hotspotsPtr);
+ hotspotsPtr += 9;
hotspots.push_back(h);
}
}
}
-void TeenAgentEngine::deinit() {
- _mixer->stopAll();
- delete scene;
- scene = NULL;
- delete inventory;
- inventory = NULL;
- //delete music;
- //music = NULL;
- use_hotspots.clear();
- Resources::instance()->deinit();
- CursorMan.popCursor();
-}
-
Common::Error TeenAgentEngine::loadGameState(int slot) {
debug(0, "loading from slot %d", slot);
Common::ScopedPtr<Common::InSaveFile> in(_saveFileMan->openForLoading(Common::String::format("teenagent.%02d", slot)));
@@ -211,22 +225,19 @@ Common::Error TeenAgentEngine::loadGameState(int slot) {
if (!in)
return Common::kReadPermissionDenied;
- Resources *res = Resources::instance();
+ assert(res->dseg.size() >= dsAddr_saveState + saveStateSize);
- const uint dataSize = 0x777a;
- assert(res->dseg.size() >= 0x6478 + dataSize);
-
- char *data = (char *)malloc(dataSize);
+ char *data = (char *)malloc(saveStateSize);
if (!data)
error("[TeenAgentEngine::loadGameState] Cannot allocate buffer");
in->seek(0);
- if (in->read(data, dataSize) != dataSize) {
+ if (in->read(data, saveStateSize) != saveStateSize) {
free(data);
return Common::kReadingFailed;
}
- memcpy(res->dseg.ptr(0x6478), data, dataSize);
+ memcpy(res->dseg.ptr(dsAddr_saveState), data, saveStateSize);
free(data);
@@ -234,10 +245,10 @@ Common::Error TeenAgentEngine::loadGameState(int slot) {
inventory->activate(false);
inventory->reload();
- setMusic(Resources::instance()->dseg.get_byte(0xDB90));
+ setMusic(res->dseg.get_byte(dsAddr_currentMusic));
- int id = res->dseg.get_byte(0xB4F3);
- uint16 x = res->dseg.get_word(0x64AF), y = res->dseg.get_word(0x64B1);
+ int id = res->dseg.get_byte(dsAddr_currentScene);
+ uint16 x = res->dseg.get_word(dsAddr_egoX), y = res->dseg.get_word(dsAddr_egoY);
scene->loadObjectData();
scene->init(id, Common::Point(x, y));
scene->setPalette(4);
@@ -251,15 +262,15 @@ Common::Error TeenAgentEngine::saveGameState(int slot, const Common::String &des
if (!out)
return Common::kWritingFailed;
- Resources *res = Resources::instance();
- res->dseg.set_byte(0xB4F3, scene->getId());
+ res->dseg.set_byte(dsAddr_currentScene, scene->getId());
Common::Point pos = scene->getPosition();
- res->dseg.set_word(0x64AF, pos.x);
- res->dseg.set_word(0x64B1, pos.y);
+ res->dseg.set_word(dsAddr_egoX, pos.x);
+ res->dseg.set_word(dsAddr_egoY, pos.y);
- assert(res->dseg.size() >= 0x6478 + 0x777a);
- strncpy((char *)res->dseg.ptr(0x6478), desc.c_str(), 0x16);
- out->write(res->dseg.ptr(0x6478), 0x777a);
+ assert(res->dseg.size() >= dsAddr_saveState + saveStateSize);
+ // FIXME: Description string is 24 bytes and null based on detection.cpp code, not 22?
+ strncpy((char *)res->dseg.ptr(dsAddr_saveState), desc.c_str(), 22);
+ out->write(res->dseg.ptr(dsAddr_saveState), saveStateSize);
if (!Graphics::saveThumbnail(*out))
warning("saveThumbnail failed");
@@ -267,7 +278,6 @@ Common::Error TeenAgentEngine::saveGameState(int slot, const Common::String &des
return Common::kNoError;
}
-
int TeenAgentEngine::skipEvents() const {
Common::EventManager *_event = _system->getEventManager();
Common::Event event;
@@ -295,7 +305,7 @@ bool TeenAgentEngine::showCDLogo() {
if (!cdlogo.exists("cdlogo.res") || !cdlogo.open("cdlogo.res"))
return true;
- const uint bgSize = 0xfa00;
+ const uint bgSize = kScreenWidth * kScreenHeight;
const uint paletteSize = 3 * 256;
byte *bg = (byte *)malloc(bgSize);
@@ -314,8 +324,8 @@ bool TeenAgentEngine::showCDLogo() {
for (uint c = 0; c < paletteSize; ++c)
palette[c] *= 4;
- _system->getPaletteManager()->setPalette(palette, 0, 0x100);
- _system->copyRectToScreen(bg, 320, 0, 0, 320, 200);
+ _system->getPaletteManager()->setPalette(palette, 0, 256);
+ _system->copyRectToScreen(bg, kScreenWidth, 0, 0, kScreenWidth, kScreenHeight);
_system->updateScreen();
free(bg);
@@ -341,7 +351,7 @@ bool TeenAgentEngine::showLogo() {
if (!frame)
return true;
- const uint bgSize = 0xfa00;
+ const uint bgSize = kScreenWidth * kScreenHeight;
const uint paletteSize = 3 * 256;
byte *bg = (byte *)malloc(bgSize);
@@ -360,7 +370,7 @@ bool TeenAgentEngine::showLogo() {
for (uint c = 0; c < paletteSize; ++c)
palette[c] *= 4;
- _system->getPaletteManager()->setPalette(palette, 0, 0x100);
+ _system->getPaletteManager()->setPalette(palette, 0, 256);
free(palette);
@@ -374,7 +384,7 @@ bool TeenAgentEngine::showLogo() {
return r > 0 ? true : false;
}
}
- _system->copyRectToScreen(bg, 320, 0, 0, 320, 200);
+ _system->copyRectToScreen(bg, kScreenWidth, 0, 0, kScreenWidth, kScreenHeight);
frame.reset(logo.getStream(i));
if (!frame) {
@@ -419,23 +429,23 @@ bool TeenAgentEngine::showMetropolis() {
palette[c] *= 4;
}
- _system->getPaletteManager()->setPalette(palette, 0, 0x100);
+ _system->getPaletteManager()->setPalette(palette, 0, 256);
free(palette);
const uint varia6Size = 21760;
const uint varia9Size = 18302;
- byte *varia_6 = (byte *)malloc(varia6Size);
- byte *varia_9 = (byte *)malloc(varia9Size);
- if (!varia_6 || !varia_9) {
- free(varia_6);
- free(varia_9);
+ byte *varia6Data = (byte *)malloc(varia6Size);
+ byte *varia9Data = (byte *)malloc(varia9Size);
+ if (!varia6Data || !varia9Data) {
+ free(varia6Data);
+ free(varia9Data);
error("[TeenAgentEngine::showMetropolis] Cannot allocate buffer");
}
- varia.read(6, varia_6, varia6Size);
- varia.read(9, varia_9, varia9Size);
+ varia.read(6, varia6Data, varia6Size);
+ varia.read(9, varia9Data, varia9Size);
const uint colorsSize = 56 * 160 * 2;
byte *colors = (byte *)malloc(colorsSize);
@@ -449,8 +459,8 @@ bool TeenAgentEngine::showMetropolis() {
{
int r = skipEvents();
if (r != 0) {
- free(varia_6);
- free(varia_9);
+ free(varia6Data);
+ free(varia9Data);
free(colors);
return r > 0 ? true : false;
}
@@ -458,7 +468,7 @@ bool TeenAgentEngine::showMetropolis() {
Graphics::Surface *surface = _system->lockScreen();
if (logo_y > 0) {
- surface->fillRect(Common::Rect(0, 0, 320, logo_y), 0);
+ surface->fillRect(Common::Rect(0, 0, kScreenWidth, logo_y), 0);
}
{
@@ -485,7 +495,7 @@ bool TeenAgentEngine::showMetropolis() {
}
byte *dst = (byte *)surface->getBasePtr(0, 131);
- byte *src = varia_6;
+ byte *src = varia6Data;
for (uint y = 0; y < 68; ++y) {
for (uint x = 0; x < 320; ++x) {
if (*src++ == 1) {
@@ -497,7 +507,7 @@ bool TeenAgentEngine::showMetropolis() {
_system->unlockScreen();
_system->copyRectToScreen(
- varia_9 + (logo_y < 0 ? -logo_y * 320 : 0), 320,
+ varia9Data + (logo_y < 0 ? -logo_y * 320 : 0), 320,
0, logo_y >= 0 ? logo_y : 0,
320, logo_y >= 0 ? 57 : 57 + logo_y);
@@ -509,38 +519,37 @@ bool TeenAgentEngine::showMetropolis() {
_system->delayMillis(100);
}
- free(varia_6);
- free(varia_9);
+ free(varia6Data);
+ free(varia9Data);
free(colors);
return true;
}
Common::Error TeenAgentEngine::run() {
- Resources *res = Resources::instance();
if (!res->loadArchives(_gameDescription))
return Common::kUnknownError;
Common::EventManager *_event = _system->getEventManager();
- initGraphics(320, 200, false);
+ initGraphics(kScreenWidth, kScreenHeight, false);
console = new Console(this);
- scene = new Scene(this, _system);
+ scene = new Scene(this);
inventory = new Inventory(this);
init();
- CursorMan.pushCursor(res->dseg.ptr(0x00da), 8, 12, 0, 0, 1);
+ CursorMan.pushCursor(res->dseg.ptr(dsAddr_cursor), 8, 12, 0, 0, 1);
syncSoundSettings();
setMusic(1);
_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) {
- loadGameState(load_slot);
+ int loadSlot = ConfMan.getInt("save_slot");
+ if (loadSlot >= 0) {
+ loadGameState(loadSlot);
} else {
if (!showCDLogo())
return Common::kNoError;
@@ -549,32 +558,30 @@ Common::Error TeenAgentEngine::run() {
if (!showMetropolis())
return Common::kNoError;
scene->intro = true;
- scene_busy = true;
- processCallback(0x24c);
+ _sceneBusy = true;
+ fnIntro();
}
CursorMan.showMouse(true);
- uint32 game_timer = 0;
- uint32 mark_timer = 0;
+ uint32 gameTimer = 0;
+ uint32 markTimer = 0;
Common::Event event;
Common::Point mouse;
uint32 timer = _system->getMillis();
do {
- Object *current_object = scene->findObject(mouse);
+ Object *currentObject = scene->findObject(mouse);
while (_event->pollEvent(event)) {
- if (event.type == Common::EVENT_RTL) {
- deinit();
+ if (event.type == Common::EVENT_RTL)
return Common::kNoError;
- }
- if ((!scene_busy && inventory->processEvent(event)) || scene->processEvent(event))
+ if ((!_sceneBusy && inventory->processEvent(event)) || scene->processEvent(event))
continue;
- //debug(0, "event");
+ debug(5, "event");
switch (event.type) {
case Common::EVENT_KEYDOWN:
if ((event.kbd.hasFlags(Common::KBD_CTRL) && event.kbd.keycode == Common::KEYCODE_d) ||
@@ -583,33 +590,33 @@ Common::Error TeenAgentEngine::run() {
} else if (event.kbd.hasFlags(0) && event.kbd.keycode == Common::KEYCODE_F5) {
openMainMenuDialog();
} if (event.kbd.hasFlags(Common::KBD_CTRL) && event.kbd.keycode == Common::KEYCODE_f) {
- _mark_delay = _mark_delay == 80 ? 40 : 80;
- debug(0, "mark_delay = %u", _mark_delay);
+ _markDelay = _markDelay == 80 ? 40 : 80;
+ debug(5, "markDelay = %u", _markDelay);
}
break;
case Common::EVENT_LBUTTONDOWN:
if (scene->getId() < 0)
break;
- examine(event.mouse, current_object);
+ examine(event.mouse, currentObject);
break;
case Common::EVENT_RBUTTONDOWN:
- //if (current_object)
- // debug(0, "%d, %s", current_object->id, current_object->name.c_str());
+ if (currentObject)
+ debugC(0, kDebugObject, "%d, %s", currentObject->id, currentObject->name.c_str());
if (scene->getId() < 0)
break;
- if (current_object == NULL)
+ if (currentObject == NULL)
break;
- if (res->dseg.get_byte(0) == 3 && current_object->id == 1) {
- processCallback(0x5189); //boo!
+ if (res->dseg.get_byte(dsAddr_timedCallbackState) == 3 && currentObject->id == 1) {
+ fnGuardDrinking();
break;
}
- if (res->dseg.get_byte(0) == 4 && current_object->id == 5) {
- processCallback(0x99e0); //getting an anchor
+ if (res->dseg.get_byte(dsAddr_timedCallbackState) == 4 && currentObject->id == 5) {
+ fnGotAnchor();
break;
}
- use(current_object);
+ use(currentObject);
break;
case Common::EVENT_MOUSEMOVE:
mouse = event.mouse;
@@ -622,60 +629,60 @@ Common::Error TeenAgentEngine::run() {
//game delays: slow 16, normal 11, fast 5, crazy 1
//mark delays: 4 * (3 - hero_speed), normal == 1
//game delays in 1/100th of seconds
- uint32 new_timer = _system->getMillis();
- uint32 delta = new_timer - timer;
- timer = new_timer;
+ uint32 newTimer = _system->getMillis();
+ uint32 delta = newTimer - timer;
+ timer = newTimer;
- bool tick_game = game_timer <= delta;
- if (tick_game)
- game_timer = _game_delay - ((delta - game_timer) % _game_delay);
+ bool tickGame = gameTimer <= delta;
+ if (tickGame)
+ gameTimer = _gameDelay - ((delta - gameTimer) % _gameDelay);
else
- game_timer -= delta;
+ gameTimer -= delta;
- bool tick_mark = mark_timer <= delta;
- if (tick_mark)
- mark_timer = _mark_delay - ((delta - mark_timer) % _mark_delay);
+ bool tickMark = markTimer <= delta;
+ if (tickMark)
+ markTimer = _markDelay - ((delta - markTimer) % _markDelay);
else
- mark_timer -= delta;
+ markTimer -= delta;
- if (tick_game || tick_mark) {
- bool b = scene->render(tick_game, tick_mark, delta);
- if (!inventory->active() && !b && action != kActionNone) {
+ if (tickGame || tickMark) {
+ bool b = scene->render(tickGame, tickMark, delta);
+ if (!inventory->active() && !b && _action != kActionNone) {
processObject();
- action = kActionNone;
- dst_object = NULL;
+ _action = kActionNone;
+ _dstObject = NULL;
}
- scene_busy = b;
+ _sceneBusy = b;
}
- _system->showMouse(scene->getMessage().empty() && !scene_busy);
+ _system->showMouse(scene->getMessage().empty() && !_sceneBusy);
- bool busy = inventory->active() || scene_busy;
+ bool busy = inventory->active() || _sceneBusy;
Graphics::Surface *surface = _system->lockScreen();
if (!busy) {
- InventoryObject *selected_object = inventory->selectedObject();
- if (current_object || selected_object) {
+ InventoryObject *selectedObject = inventory->selectedObject();
+ if (currentObject || selectedObject) {
Common::String name;
- if (selected_object) {
- name += selected_object->name;
+ if (selectedObject) {
+ name += selectedObject->name;
name += " & ";
}
- if (current_object)
- name += current_object->name;
+ if (currentObject)
+ name += currentObject->name;
- uint w = res->font7.render(NULL, 0, 0, name, 0xd1);
- res->font7.render(surface, (320 - w) / 2, 180, name, 0xd1, true);
+ uint w = res->font7.render(NULL, 0, 0, name, textColorMark);
+ res->font7.render(surface, (kScreenWidth - w) / 2, 180, name, textColorMark, true);
#if 0
- if (current_object) {
- current_object->rect.render(surface, 0x80);
- current_object->actor_rect.render(surface, 0x81);
+ if (currentObject) {
+ currentObject->rect.render(surface, 0x80);
+ currentObject->actorRect.render(surface, 0x81);
}
#endif
}
}
- inventory->render(surface, tick_game ? 1 : 0);
+ inventory->render(surface, tickGame ? 1 : 0);
_system->unlockScreen();
@@ -683,20 +690,19 @@ Common::Error TeenAgentEngine::run() {
console->onFrame();
- uint32 next_tick = MIN(game_timer, mark_timer);
- if (next_tick > 0) {
- _system->delayMillis(next_tick > 40 ? 40 : next_tick);
+ uint32 nextTick = MIN(gameTimer, markTimer);
+ if (nextTick > 0) {
+ _system->delayMillis(nextTick > 40 ? 40 : nextTick);
}
} while (!shouldQuit());
- deinit();
return Common::kNoError;
}
Common::String TeenAgentEngine::parseMessage(uint16 addr) {
Common::String message;
for (
- const char *str = (const char *)Resources::instance()->dseg.ptr(addr);
+ const char *str = (const char *)res->dseg.ptr(addr);
str[0] != 0 || str[1] != 0;
++str) {
char c = str[0];
@@ -708,12 +714,12 @@ Common::String TeenAgentEngine::parseMessage(uint16 addr) {
return message;
}
-void TeenAgentEngine::displayMessage(const Common::String &str, byte color, uint16 position) {
+void TeenAgentEngine::displayMessage(const Common::String &str, byte color, uint16 x, uint16 y) {
if (str.empty()) {
return;
}
- if (color == 0xd1) { //mark's
+ if (color == textColorMark) { // mark's
SceneEvent e(SceneEvent::kPlayAnimation);
e.animation = 0;
e.slot = 0x80;
@@ -725,8 +731,8 @@ void TeenAgentEngine::displayMessage(const Common::String &str, byte color, uint
event.message = str;
event.color = color;
event.slot = 0;
- event.dst.x = position % 320;
- event.dst.y = position / 320;
+ event.dst.x = x;
+ event.dst.y = y;
scene->push(event);
}
@@ -738,46 +744,45 @@ void TeenAgentEngine::displayMessage(const Common::String &str, byte color, uint
}
}
-void TeenAgentEngine::displayMessage(uint16 addr, byte color, uint16 position) {
- displayMessage(parseMessage(addr), color, position);
+void TeenAgentEngine::displayMessage(uint16 addr, byte color, uint16 x, uint16 y) {
+ displayMessage(parseMessage(addr), color, x, y);
}
-void TeenAgentEngine::displayAsyncMessage(uint16 addr, uint16 position, uint16 first_frame, uint16 last_frame, byte color) {
+void TeenAgentEngine::displayAsyncMessage(uint16 addr, uint16 x, uint16 y, uint16 firstFrame, uint16 lastFrame, byte color) {
SceneEvent event(SceneEvent::kMessage);
event.message = parseMessage(addr);
event.slot = 0;
event.color = color;
- event.dst.x = position % 320;
- event.dst.y = position / 320;
- event.first_frame = first_frame;
- event.last_frame = last_frame;
+ event.dst.x = x;
+ event.dst.y = y;
+ event.firstFrame = firstFrame;
+ event.lastFrame = lastFrame;
scene->push(event);
}
-void TeenAgentEngine::displayAsyncMessageInSlot(uint16 addr, byte slot, uint16 first_frame, uint16 last_frame, byte color) {
+void TeenAgentEngine::displayAsyncMessageInSlot(uint16 addr, byte slot, uint16 firstFrame, uint16 lastFrame, byte color) {
SceneEvent event(SceneEvent::kMessage);
event.message = parseMessage(addr);
event.slot = slot + 1;
event.color = color;
- event.first_frame = first_frame;
- event.last_frame = last_frame;
+ event.firstFrame = firstFrame;
+ event.lastFrame = lastFrame;
scene->push(event);
}
-
void TeenAgentEngine::displayCredits(uint16 addr, uint16 timer) {
SceneEvent event(SceneEvent::kCreditsMessage);
- const byte *src = Resources::instance()->dseg.ptr(addr);
+ const byte *src = res->dseg.ptr(addr);
event.orientation = *src++;
event.color = *src++;
event.lan = 8;
event.dst.y = *src;
while (true) {
- ++src; //skip y position
+ ++src; // skip y position
Common::String line((const char *)src);
event.message += line;
src += line.size() + 1;
@@ -785,33 +790,33 @@ void TeenAgentEngine::displayCredits(uint16 addr, uint16 timer) {
break;
event.message += "\n";
}
- int w = Resources::instance()->font8.render(NULL, 0, 0, event.message, 0xd1);
- event.dst.x = (320 - w) / 2;
+ int w = res->font8.render(NULL, 0, 0, event.message, textColorCredits);
+ event.dst.x = (kScreenWidth - w) / 2;
event.timer = timer;
scene->push(event);
}
void TeenAgentEngine::displayCredits() {
SceneEvent event(SceneEvent::kCredits);
- event.message = parseMessage(0xe488);
- event.dst.y = 200;
+ event.message = parseMessage(dsAddr_finalCredits7);
+ event.dst.y = kScreenHeight;
int lines = 1;
for (uint i = 0; i < event.message.size(); ++i)
if (event.message[i] == '\n')
++lines;
- event.dst.x = (320 - Resources::instance()->font7.render(NULL, 0, 0, event.message, 0xd1)) / 2;
+ event.dst.x = (kScreenWidth - res->font7.render(NULL, 0, 0, event.message, textColorCredits)) / 2;
event.timer = 11 * lines - event.dst.y + 22;
- //debug(0, "credits = %s", event.message.c_str());
+ debug(2, "credits = %s", event.message.c_str());
scene->push(event);
}
-void TeenAgentEngine::displayCutsceneMessage(uint16 addr, uint16 position) {
+void TeenAgentEngine::displayCutsceneMessage(uint16 addr, uint16 x, uint16 y) {
SceneEvent event(SceneEvent::kCreditsMessage);
event.message = parseMessage(addr);
- event.dst.x = position % 320;
- event.dst.y = position / 320;
+ event.dst.x = x;
+ event.dst.y = y;
event.lan = 7;
scene->push(event);
@@ -822,7 +827,7 @@ void TeenAgentEngine::moveTo(const Common::Point &dst, byte o, bool warp) {
}
void TeenAgentEngine::moveTo(Object *obj) {
- moveTo(obj->actor_rect.right, obj->actor_rect.bottom, obj->actor_orientation);
+ moveTo(obj->actorRect.right, obj->actorRect.bottom, obj->actorOrientation);
}
void TeenAgentEngine::moveTo(uint16 x, uint16 y, byte o, bool warp) {
@@ -865,7 +870,6 @@ void TeenAgentEngine::playActorAnimation(uint16 id, bool async, bool ignore) {
waitAnimation();
}
-
void TeenAgentEngine::loadScene(byte id, const Common::Point &pos, byte o) {
loadScene(id, pos.x, pos.y, o);
}
@@ -890,21 +894,21 @@ void TeenAgentEngine::enableOn(bool enable) {
scene->push(event);
}
-void TeenAgentEngine::setOns(byte id, byte value, byte scene_id) {
+void TeenAgentEngine::setOns(byte id, byte value, byte sceneId) {
SceneEvent event(SceneEvent::kSetOn);
event.ons = id + 1;
event.color = value;
- event.scene = scene_id;
+ event.scene = sceneId;
scene->push(event);
}
-void TeenAgentEngine::setLan(byte id, byte value, byte scene_id) {
+void TeenAgentEngine::setLan(byte id, byte value, byte sceneId) {
if (id == 0)
error("setting lan 0 is invalid");
SceneEvent event(SceneEvent::kSetLan);
event.lan = id;
event.color = value;
- event.scene = scene_id;
+ event.scene = sceneId;
scene->push(event);
}
@@ -925,35 +929,34 @@ void TeenAgentEngine::reloadLan() {
scene->push(event);
}
-
void TeenAgentEngine::playMusic(byte id) {
SceneEvent event(SceneEvent::kPlayMusic);
event.music = id;
scene->push(event);
}
-void TeenAgentEngine::playSound(byte id, byte skip_frames) {
- if (skip_frames > 0)
- --skip_frames;
+void TeenAgentEngine::playSound(byte id, byte skipFrames) {
+ if (skipFrames > 0)
+ --skipFrames;
SceneEvent event(SceneEvent::kPlaySound);
event.sound = id;
- event.color = skip_frames;
+ event.color = skipFrames;
scene->push(event);
}
-void TeenAgentEngine::enableObject(byte id, byte scene_id) {
+void TeenAgentEngine::enableObject(byte id, byte sceneId) {
SceneEvent event(SceneEvent::kEnableObject);
event.object = id + 1;
event.color = 1;
- event.scene = scene_id;
+ event.scene = sceneId;
scene->push(event);
}
-void TeenAgentEngine::disableObject(byte id, byte scene_id) {
+void TeenAgentEngine::disableObject(byte id, byte sceneId) {
SceneEvent event(SceneEvent::kEnableObject);
event.object = id + 1;
event.color = 0;
- event.scene = scene_id;
+ event.scene = sceneId;
scene->push(event);
}
@@ -1015,7 +1018,6 @@ void TeenAgentEngine::wait(uint16 frames) {
}
void TeenAgentEngine::playSoundNow(byte id) {
- Resources *res = Resources::instance();
uint size = res->sam_sam.getSize(id);
if (size == 0) {
warning("skipping invalid sound %u", id);
@@ -1024,28 +1026,26 @@ void TeenAgentEngine::playSoundNow(byte id) {
byte *data = (byte *)malloc(size);
res->sam_sam.read(id, data, size);
- //debug(0, "playing %u samples...", size);
+ debug(3, "playing %u samples...", size);
Audio::AudioStream *stream = Audio::makeRawStream(data, size, 11025, 0);
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle, stream); //dispose is YES by default
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle, stream); // dispose is YES by default
}
-
void TeenAgentEngine::setMusic(byte id) {
- debug(0, "starting music %u", id);
- Resources *res = Resources::instance();
+ debugC(0, kDebugMusic, "starting music %u", id);
- if (id != 1) //intro music
- *res->dseg.ptr(0xDB90) = id;
+ if (id != 1) // intro music
+ res->dseg.set_byte(dsAddr_currentMusic, id);
if (_gameDescription->flags & ADGF_CD) {
byte track2cd[] = {7, 2, 0, 9, 3, 6, 8, 10, 4, 5, 11};
if (id == 0 || id > 11 || track2cd[id - 1] == 0) {
- debug(0, "no cd music for id %u", id);
+ debugC(0, kDebugMusic, "no cd music for id %u", id);
return;
}
byte track = track2cd[id - 1];
- debug(0, "playing cd track %u", track);
+ debugC(0, kDebugMusic, "playing cd track %u", track);
_system->getAudioCDManager()->play(track, -1, 0, 0);
} else if (music->load(id))
music->start();
diff --git a/engines/teenagent/teenagent.h b/engines/teenagent/teenagent.h
index 737f07ba85..d6a2c0d3c6 100644
--- a/engines/teenagent/teenagent.h
+++ b/engines/teenagent/teenagent.h
@@ -23,12 +23,15 @@
#define TEENAGENT_ENGINE_H
#include "engines/engine.h"
-#include "teenagent/pack.h"
-#include "teenagent/resources.h"
-#include "teenagent/inventory.h"
+
#include "audio/audiostream.h"
#include "audio/mixer.h"
+
#include "common/random.h"
+#include "common/rect.h"
+#include "common/array.h"
+
+#include "teenagent/dialog.h"
struct ADGameDescription;
@@ -43,14 +46,34 @@ struct ADGameDescription;
namespace TeenAgent {
struct Object;
+struct UseHotspot;
class Scene;
class MusicPlayer;
+class Dialog;
class Console;
+class Resources;
+class Inventory;
+
+// Engine Debug Flags
+enum {
+ kDebugActor = (1 << 0),
+ kDebugAnimation = (1 << 1),
+ kDebugCallbacks = (1 << 2),
+ kDebugDialog = (1 << 3),
+ kDebugFont = (1 << 4),
+ kDebugInventory = (1 << 5),
+ kDebugMusic = (1 << 6),
+ kDebugObject = (1 << 7),
+ kDebugPack = (1 << 8),
+ kDebugScene = (1 << 9),
+ kDebugSurface = (1 << 10)
+};
+
+const uint16 kScreenWidth = 320;
+const uint16 kScreenHeight = 200;
class TeenAgentEngine : public Engine {
public:
- enum Action { kActionNone, kActionExamine, kActionUse };
-
TeenAgentEngine(OSystem *system, const ADGameDescription *gd);
~TeenAgentEngine();
@@ -58,15 +81,16 @@ public:
virtual Common::Error loadGameState(int slot);
virtual Common::Error saveGameState(int slot, const Common::String &desc);
virtual bool canLoadGameStateCurrently() { return true; }
- virtual bool canSaveGameStateCurrently() { return !scene_busy; }
+ virtual bool canSaveGameStateCurrently() { return !_sceneBusy; }
virtual bool hasFeature(EngineFeature f) const;
void init();
- void deinit();
+
+ enum Action { kActionNone, kActionExamine, kActionUse };
void examine(const Common::Point &point, Object *object);
void use(Object *object);
- inline void cancel() { action = kActionNone; }
+ inline void cancel() { _action = kActionNone; }
bool processCallback(uint16 addr);
inline Scene *getScene() { return scene; }
@@ -76,15 +100,15 @@ public:
bool showMetropolis();
int skipEvents() const;
- static Common::String parseMessage(uint16 addr);
+ Common::String parseMessage(uint16 addr);
//event driven:
- void displayMessage(uint16 addr, byte color = 0xd1, uint16 position = 0);
- void displayMessage(const Common::String &str, byte color = 0xd1, uint16 position = 0);
- void displayAsyncMessage(uint16 addr, uint16 position, uint16 first_frame, uint16 last_frame, byte color = 0xd1);
- void displayAsyncMessageInSlot(uint16 addr, byte slot, uint16 first_frame, uint16 last_frame, byte color = 0xd1);
+ void displayMessage(uint16 addr, byte color = textColorMark, uint16 x = 0, uint16 y = 0);
+ void displayMessage(const Common::String &str, byte color = textColorMark, uint16 x = 0, uint16 y = 0);
+ void displayAsyncMessage(uint16 addr, uint16 x, uint16 y, uint16 firstFrame, uint16 lastFrame, byte color = textColorMark);
+ void displayAsyncMessageInSlot(uint16 addr, byte slot, uint16 firstFrame, uint16 lastFrame, byte color = textColorMark);
void displayCredits(uint16 addr, uint16 timer = 0);
- void displayCutsceneMessage(uint16 addr, uint16 position);
+ void displayCutsceneMessage(uint16 addr, uint16 x, uint16 y);
void moveTo(const Common::Point &dst, byte o, bool warp = false);
void moveTo(uint16 x, uint16 y, byte o, bool warp = false);
void moveTo(Object *obj);
@@ -94,18 +118,18 @@ public:
void loadScene(byte id, const Common::Point &pos, byte o = 0);
void loadScene(byte id, uint16 x, uint16 y, byte o = 0);
void enableOn(bool enable = true);
- void setOns(byte id, byte value, byte scene_id = 0);
- void setLan(byte id, byte value, byte scene_id = 0);
+ void setOns(byte id, byte value, byte sceneId = 0);
+ void setLan(byte id, byte value, byte sceneId = 0);
void setFlag(uint16 addr, byte value);
byte getFlag(uint16 addr);
void reloadLan();
void rejectMessage();
void playMusic(byte id); //schedules play
- void playSound(byte id, byte skip_frames);
+ void playSound(byte id, byte skipFrames);
void playSoundNow(byte id);
- void enableObject(byte id, byte scene_id = 0);
- void disableObject(byte id, byte scene_id = 0);
+ void enableObject(byte id, byte sceneId = 0);
+ void disableObject(byte id, byte sceneId = 0);
void hideActor();
void showActor();
void waitAnimation();
@@ -119,9 +143,11 @@ public:
Common::RandomSource _rnd;
+ Resources *res;
Scene *scene;
Inventory *inventory;
MusicPlayer *music;
+ Dialog *dialog;
Console *console;
void setMusic(byte id);
@@ -130,17 +156,47 @@ private:
void processObject();
bool trySelectedObject();
- bool scene_busy;
- Action action;
- Object *dst_object;
+ bool _sceneBusy;
+ Action _action;
+ Object *_dstObject;
Audio::AudioStream *_musicStream;
Audio::SoundHandle _musicHandle, _soundHandle;
const ADGameDescription *_gameDescription;
- uint _mark_delay, _game_delay;
-
- Common::Array<Common::Array<UseHotspot> > use_hotspots;
+ uint _markDelay, _gameDelay;
+
+ Common::Array<Common::Array<UseHotspot> > _useHotspots;
+
+ void fnIntro();
+ void fnPoleClimbFail();
+ void fnGotAnchor();
+ void fnGetOutOfLake();
+ void fnGuardDrinking();
+ void fnEgoDefaultPosition();
+ void fnEnterCave();
+ void fnEgoScaredBySpider();
+ void fnMoveToLadderAndLeaveCellar();
+ void fnLeaveCellar();
+ void fnPutRockInHole();
+ void fnEgoBottomRightTurn();
+ bool fnCheckingDrawers();
+ void fnDrawerOpenMessage();
+ bool fnRobotSafeAlreadyUnlockedCheck();
+ void fnRobotSafeUnlockCheck();
+ bool fnMansionIntrusionAttempt();
+ void fnSecondMansionIntrusion();
+ void fnThirdMansionIntrusion();
+ void fnFourthMansionIntrusion();
+ void fnFifthMansionIntrusion();
+ void fnSixthMansionIntrusion();
+ void fnTooDark();
+ bool fnIsCookGone();
+ void fnEgoSuspiciousPosition();
+ void fnGivingFlowerToOldLady();
+ void fnGiveAnotherFlowerToOldLady();
+ void fnGivingFlowerToAnne();
+ void fnGiveAnotherFlowerToAnne();
};
} // End of namespace TeenAgent
diff --git a/engines/tinsel/actors.cpp b/engines/tinsel/actors.cpp
index a784ff5788..0ba8b7cdba 100644
--- a/engines/tinsel/actors.cpp
+++ b/engines/tinsel/actors.cpp
@@ -319,8 +319,8 @@ static void ActorRestoredProcess(CORO_PARAM, const void *param) {
CORO_BEGIN_CODE(_ctx);
_ctx->pic = RestoreInterpretContext(r->pic);
-
- // The newly added check here specially sets the process to RES_NOT when loading a savegame.
+
+ // The newly added check here specially sets the process to RES_NOT when loading a savegame.
// This is needed particularly for the Psychiatrist scene in Discworld 1 - otherwise Rincewind
// can't go upstairs without leaving the building and returning. If this patch causes problems
// in other scenes, an added check for the hCode == 1174490602 could be added.
diff --git a/engines/tinsel/pcode.cpp b/engines/tinsel/pcode.cpp
index 6ea18c8268..04bc2856ca 100644
--- a/engines/tinsel/pcode.cpp
+++ b/engines/tinsel/pcode.cpp
@@ -152,7 +152,7 @@ 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,
+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)
};
@@ -222,7 +222,7 @@ const WorkaroundEntry workaroundList[] = {
// times would cause the game to crash
{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
+ // 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},
diff --git a/engines/tinsel/saveload.cpp b/engines/tinsel/saveload.cpp
index 518e27f02b..2ef92d853f 100644
--- a/engines/tinsel/saveload.cpp
+++ b/engines/tinsel/saveload.cpp
@@ -502,7 +502,7 @@ 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;
diff --git a/engines/toltecs/animation.cpp b/engines/toltecs/animation.cpp
index eef9cef9ed..084332cf83 100644
--- a/engines/toltecs/animation.cpp
+++ b/engines/toltecs/animation.cpp
@@ -53,7 +53,7 @@ void AnimationPlayer::start(uint resIndex) {
_vm->_arc->closeResource();
debug(1, "AnimationPlayer::start() width = %d; height = %d; frameCount = %d", _width, _height, _frameCount);
-
+
_vm->_sceneWidth = _width;
_vm->_sceneHeight = _height;
@@ -63,7 +63,7 @@ void AnimationPlayer::start(uint resIndex) {
_frameNumber = 0;
// TODO mov screenFlag01, 0FFFFh
// TODO mov animDrawFrameFlag, 0FFFFh
-
+
_firstNextFrameOffset = _nextFrameOffset;
_firstCurFrameSize = _curFrameSize;
_firstNextFrameSize = _nextFrameSize;
@@ -81,25 +81,25 @@ void AnimationPlayer::nextFrame() {
} else {
_frameNumber++;
}
-
+
debug(1, "AnimationPlayer::nextFrame() frameNumber = %d", _frameNumber);
if (_keepFrameCounter > 0) {
_keepFrameCounter--;
return;
}
-
+
_vm->_arc->openResource(_resIndex);
_vm->_arc->seek(_nextFrameOffset, SEEK_CUR);
_curFrameSize = _nextFrameSize;
-
+
if (_curFrameSize == 0)
_curFrameSize = 1;
-
+
_vm->_arc->read(_animBuffer, _curFrameSize);
_nextFrameSize = _vm->_arc->readUint32LE();
_nextFrameOffset += _curFrameSize + 4;
-
+
if (_curFrameSize > 1) {
unpackFrame();
// TODO mov animDrawFrameFlag, 0FFFFh
diff --git a/engines/toltecs/animation.h b/engines/toltecs/animation.h
index 22576d7535..54ec5d8afa 100644
--- a/engines/toltecs/animation.h
+++ b/engines/toltecs/animation.h
@@ -54,7 +54,7 @@ public:
uint16 _width, _height;
uint16 _frameNumber, _frameCount;
uint32 _keepFrameCounter;
-
+
uint32 _curFrameSize;
uint32 _nextFrameSize, _nextFrameOffset;
diff --git a/engines/toltecs/menu.cpp b/engines/toltecs/menu.cpp
index 415f19ca31..6e23ff988f 100644
--- a/engines/toltecs/menu.cpp
+++ b/engines/toltecs/menu.cpp
@@ -21,8 +21,11 @@
*
*/
+#include "audio/mixer.h"
#include "common/savefile.h"
+#include "common/config-manager.h"
+
#include "toltecs/toltecs.h"
#include "toltecs/menu.h"
#include "toltecs/palette.h"
@@ -37,7 +40,7 @@ MenuSystem::MenuSystem(ToltecsEngine *vm) : _vm(vm) {
MenuSystem::~MenuSystem() {
}
-int MenuSystem::run() {
+int MenuSystem::run(MenuID menuId) {
//debug("MenuSystem::run()");
@@ -50,18 +53,13 @@ int MenuSystem::run() {
memcpy(backgroundOrig.getBasePtr(0,0), _vm->_screen->_frontScreen, 640 * 400);
_currMenuID = kMenuIdNone;
- _newMenuID = kMenuIdMain;
+ _newMenuID = menuId;
_currItemID = kItemIdNone;
_editingDescription = false;
- _cfgText = true;
- _cfgVoices = true;
- _cfgMasterVolume = 10;
- _cfgVoicesVolume = 10;
- _cfgMusicVolume = 10;
- _cfgSoundFXVolume = 10;
- _cfgBackgroundVolume = 10;
- _running = true;
+
+ _running = true;
_top = 30 - _vm->_guiHeight / 2;
+
_needRedraw = false;
// TODO: buildColorTransTable2
@@ -78,7 +76,7 @@ int MenuSystem::run() {
update();
_vm->_system->updateScreen();
}
-
+
// Restore original background
memcpy(_vm->_screen->_frontScreen, backgroundOrig.getBasePtr(0,0), 640 * 400);
_vm->_system->copyRectToScreen(_vm->_screen->_frontScreen, 640, 0, 0, 640, 400);
@@ -89,7 +87,7 @@ int MenuSystem::run() {
_background->free();
delete _background;
- return 0;
+ return 0;
}
void MenuSystem::update() {
@@ -104,7 +102,7 @@ void MenuSystem::update() {
if (_needRedraw) {
//_vm->_system->copyRectToScreen(_vm->_screen->_frontScreen + 39 * 640 + 60, 640, 60, 39, 520, 247);
- _vm->_system->copyRectToScreen(_vm->_screen->_frontScreen, 640, 0, 0, 640, 400);
+ _vm->_system->copyRectToScreen(_vm->_screen->_frontScreen, 640, 0, _top, 640, 400 - _top);
//debug("redraw");
_needRedraw = false;
}
@@ -204,7 +202,7 @@ void MenuSystem::handleKeyDown(const Common::KeyState& kbd) {
ItemID MenuSystem::findItemAt(int x, int y) {
for (Common::Array<Item>::iterator iter = _items.begin(); iter != _items.end(); iter++) {
- if ((*iter).rect.contains(x, y))
+ if ((*iter).rect.contains(x, y - _top))
return (*iter).id;
}
return kItemIdNone;
@@ -241,8 +239,8 @@ void MenuSystem::initMenu(MenuID menuID) {
drawString(0, 74, 320, 1, 229, _vm->getSysString(kStrWhatCanIDoForYou));
addClickTextItem(kItemIdLoad, 0, 115, 320, 0, _vm->getSysString(kStrLoad), 229, 255);
addClickTextItem(kItemIdSave, 0, 135, 320, 0, _vm->getSysString(kStrSave), 229, 255);
- addClickTextItem(kItemIdToggleText, 0, 165, 320, 0, _vm->getSysString(kStrTextOn), 229, 255);
- addClickTextItem(kItemIdToggleVoices, 0, 185, 320, 0, _vm->getSysString(kStrVoicesOn), 229, 255);
+ addClickTextItem(kItemIdToggleText, 0, 165, 320, 0, _vm->getSysString(_vm->_cfgText ? kStrTextOn : kStrTextOff), 229, 255);
+ addClickTextItem(kItemIdToggleVoices, 0, 185, 320, 0, _vm->getSysString(_vm->_cfgVoices ? kStrVoicesOn : kStrVoicesOff), 229, 255);
addClickTextItem(kItemIdVolumesMenu, 0, 215, 320, 0, _vm->getSysString(kStrVolume), 229, 255);
addClickTextItem(kItemIdPlay, 0, 245, 320, 0, _vm->getSysString(kStrPlay), 229, 255);
addClickTextItem(kItemIdQuit, 0, 275, 320, 0, _vm->getSysString(kStrQuit), 229, 255);
@@ -326,13 +324,13 @@ void MenuSystem::clickItem(ItemID id) {
_newMenuID = kMenuIdLoad;
break;
case kItemIdToggleText:
- setCfgText(!_cfgText, true);
- if (!_cfgVoices && !_cfgText)
+ setCfgText(!_vm->_cfgText, true);
+ if (!_vm->_cfgVoices && !_vm->_cfgText)
setCfgVoices(true, false);
break;
case kItemIdToggleVoices:
- setCfgVoices(!_cfgVoices, true);
- if (!_cfgVoices && !_cfgText)
+ setCfgVoices(!_vm->_cfgVoices, true);
+ if (!_vm->_cfgVoices && !_vm->_cfgText)
setCfgText(true, false);
break;
case kItemIdVolumesMenu:
@@ -416,7 +414,7 @@ void MenuSystem::restoreRect(int x, int y, int w, int h) {
}
void MenuSystem::shadeRect(int x, int y, int w, int h, byte color1, byte color2) {
- byte *src = (byte *)_background->getBasePtr(x, y);
+ byte *src = (byte *)_vm->_screen->_frontScreen + x + y * 640;
for (int xc = 0; xc < w; xc++) {
src[xc] = color2;
src[xc + h * 640] = color1;
@@ -518,49 +516,51 @@ void MenuSystem::clickSavegameItem(ItemID id) {
}
void MenuSystem::setCfgText(bool value, bool active) {
- if (_cfgText != value) {
+ if (_vm->_cfgText != value) {
Item *item = getItem(kItemIdToggleText);
- _cfgText = value;
+ _vm->_cfgText = value;
restoreRect(item->rect.left, item->rect.top, item->rect.width() + 1, item->rect.height() - 2);
- setItemCaption(item, _vm->getSysString(_cfgText ? kStrTextOn : kStrTextOff));
+ setItemCaption(item, _vm->getSysString(_vm->_cfgText ? kStrTextOn : kStrTextOff));
drawItem(kItemIdToggleText, true);
+ ConfMan.setBool("subtitles", value);
}
}
void MenuSystem::setCfgVoices(bool value, bool active) {
- if (_cfgVoices != value) {
+ if (_vm->_cfgVoices != value) {
Item *item = getItem(kItemIdToggleVoices);
- _cfgVoices = value;
+ _vm->_cfgVoices = value;
restoreRect(item->rect.left, item->rect.top, item->rect.width() + 1, item->rect.height() - 2);
- setItemCaption(item, _vm->getSysString(_cfgVoices ? kStrVoicesOn : kStrVoicesOff));
+ setItemCaption(item, _vm->getSysString(_vm->_cfgVoices ? kStrVoicesOn : kStrVoicesOff));
drawItem(kItemIdToggleVoices, true);
+ ConfMan.setBool("speech_mute", !value);
}
}
void MenuSystem::drawVolumeBar(ItemID itemID) {
int w = 440, y, volume;
char text[21];
-
+
switch (itemID) {
- case kItemIdMaster:
+ case kItemIdMaster: // unused in ScummVM, always 20
y = 130 + 25 * 0;
- volume = _cfgMasterVolume;
+ volume = 20;
break;
case kItemIdVoices:
y = 130 + 25 * 1;
- volume = _cfgVoicesVolume;
+ volume = _vm->_cfgVoicesVolume;
break;
case kItemIdMusic:
y = 130 + 25 * 2;
- volume = _cfgMusicVolume;
+ volume = _vm->_cfgMusicVolume;
break;
case kItemIdSoundFX:
y = 130 + 25 * 3;
- volume = _cfgSoundFXVolume;
+ volume = _vm->_cfgSoundFXVolume;
break;
- case kItemIdBackground:
+ case kItemIdBackground: // unused in ScummVM, always 20
y = 130 + 25 * 4;
- volume = _cfgBackgroundVolume;
+ volume = 20;
break;
default:
return;
@@ -568,46 +568,48 @@ void MenuSystem::drawVolumeBar(ItemID itemID) {
Font font(_vm->_res->load(_vm->_screen->getFontResIndex(1))->data);
restoreRect(390, y - font.getHeight(), 100, 25);
-
+
for (int i = 0; i < volume; i++)
text[i] = '|';
text[volume] = 0;
-
+
drawString(0, y, w, 0, 246, text);
-
+
}
void MenuSystem::changeVolumeBar(ItemID itemID, int delta) {
-
- int *volume, newVolume;
+ byte newVolume;
switch (itemID) {
- case kItemIdMaster:
- volume = &_cfgMasterVolume;
- break;
case kItemIdVoices:
- volume = &_cfgVoicesVolume;
+ _vm->_cfgVoicesVolume = CLIP(_vm->_cfgVoicesVolume + delta, 0, 20);
+ // Always round volume up instead of down.
+ newVolume = (_vm->_cfgVoicesVolume * Audio::Mixer::kMaxChannelVolume + 19) / 20;
+ _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, newVolume);
+ ConfMan.setInt("speech_volume", newVolume);
break;
case kItemIdMusic:
- volume = &_cfgMusicVolume;
+ _vm->_cfgMusicVolume = CLIP(_vm->_cfgMusicVolume + delta, 0, 20);
+ newVolume = (_vm->_cfgMusicVolume * Audio::Mixer::kMaxChannelVolume + 19) / 20;
+ _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, newVolume);
+ ConfMan.setInt("music_volume", newVolume);
break;
case kItemIdSoundFX:
- volume = &_cfgSoundFXVolume;
+ _vm->_cfgSoundFXVolume = CLIP(_vm->_cfgSoundFXVolume + delta, 0, 20);
+ newVolume = (_vm->_cfgSoundFXVolume * Audio::Mixer::kMaxChannelVolume + 19) / 20;
+ _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, newVolume);
+ ConfMan.setInt("sfx_volume", newVolume);
break;
+ case kItemIdMaster:
case kItemIdBackground:
- volume = &_cfgBackgroundVolume;
+ // unused in ScummVM
break;
default:
return;
}
- newVolume = CLIP(*volume + delta, 0, 20);
-
- if (newVolume != *volume) {
- *volume = newVolume;
- drawVolumeBar(itemID);
- }
-
+ _vm->syncSoundSettings();
+ drawVolumeBar(itemID);
}
} // End of namespace Toltecs
diff --git a/engines/toltecs/menu.h b/engines/toltecs/menu.h
index 3e2c2da8d9..a72205c2e5 100644
--- a/engines/toltecs/menu.h
+++ b/engines/toltecs/menu.h
@@ -29,14 +29,6 @@
namespace Toltecs {
-enum MenuID {
- kMenuIdNone,
- kMenuIdMain,
- kMenuIdSave,
- kMenuIdLoad,
- kMenuIdVolumes
-};
-
enum ItemID {
kItemIdNone,
// Main menu
@@ -85,10 +77,10 @@ public:
MenuSystem(ToltecsEngine *vm);
~MenuSystem();
- int run();
+ int run(MenuID menuId);
void update();
void handleEvents();
-
+
protected:
struct Item {
@@ -99,7 +91,7 @@ protected:
int x, y, w;
uint fontNum;
};
-
+
struct SavegameItem {
int _slotNum;
Common::String _description;
@@ -124,9 +116,6 @@ protected:
Common::Array<Item> _items;
Common::Array<SavegameItem> _savegames;
-
- bool _cfgText, _cfgVoices;
- int _cfgMasterVolume, _cfgVoicesVolume, _cfgMusicVolume, _cfgSoundFXVolume, _cfgBackgroundVolume;
void addClickTextItem(ItemID id, int x, int y, int w, uint fontNum, const char *caption, byte defaultColor, byte activeColor);
@@ -134,13 +123,13 @@ protected:
void handleMouseMove(int x, int y);
void handleMouseClick(int x, int y);
void handleKeyDown(const Common::KeyState& kbd);
-
+
ItemID findItemAt(int x, int y);
Item *getItem(ItemID id);
void setItemCaption(Item *item, const char *caption);
void initMenu(MenuID menuID);
-
+
void enterItem(ItemID id);
void leaveItem(ItemID id);
void clickItem(ItemID id);
diff --git a/engines/toltecs/microtiles.cpp b/engines/toltecs/microtiles.cpp
index 0b61ac38a5..60e65bdaf3 100644
--- a/engines/toltecs/microtiles.cpp
+++ b/engines/toltecs/microtiles.cpp
@@ -138,7 +138,7 @@ Common::Rect * MicroTileArray::getRectangles(int *num_rects, int min_x, int min_
x0 = CLIP (x0, min_x, max_x);
y0 = CLIP (y0, min_y, max_y);
y1 = CLIP (y1, min_y, max_y);
-
+
// FIXME: Why is the following code in an #if block?
#if 1
start = i;
diff --git a/engines/toltecs/movie.cpp b/engines/toltecs/movie.cpp
index 76d42ebf0a..35accb5d93 100644
--- a/engines/toltecs/movie.cpp
+++ b/engines/toltecs/movie.cpp
@@ -61,7 +61,7 @@ void MoviePlayer::playMovie(uint resIndex) {
int16 savedCameraY = _vm->_cameraY;
int16 savedGuiHeight = _vm->_guiHeight;
byte moviePalette[768];
-
+
_vm->_isSaveAllowed = false;
memset(moviePalette, 0, sizeof(moviePalette));
@@ -78,7 +78,7 @@ void MoviePlayer::playMovie(uint resIndex) {
_vm->_arc->readUint32LE();
_vm->_arc->readUint32LE();
_framesPerSoundChunk = _vm->_arc->readUint32LE();
- _vm->_arc->readUint32LE();
+ int rate = _vm->_arc->readUint32LE();
_vm->_sceneWidth = 640;
_vm->_sceneHeight = 400;
@@ -87,7 +87,7 @@ void MoviePlayer::playMovie(uint resIndex) {
_vm->_cameraY = 0;
_vm->_guiHeight = 0;
- _audioStream = Audio::makeQueuingAudioStream(22050, false);
+ _audioStream = Audio::makeQueuingAudioStream(rate, false);
_vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_audioStreamHandle, _audioStream);
@@ -96,49 +96,52 @@ void MoviePlayer::playMovie(uint resIndex) {
fetchAudioChunks();
- uint32 lastTime = _vm->_mixer->getSoundElapsedTime(_audioStreamHandle);
+ byte *chunkBuffer = NULL;
+ uint32 chunkBufferSize = 0;
+ uint32 frame = 0;
while (_chunkCount--) {
-
byte chunkType = _vm->_arc->readByte();
uint32 chunkSize = _vm->_arc->readUint32LE();
- byte *chunkBuffer = NULL;
- uint32 movieOffset;
debug(0, "chunkType = %d; chunkSize = %d", chunkType, chunkSize);
-
+
// Skip audio chunks - we've already queued them in
// fetchAudioChunks() above
if (chunkType == kChunkAudio) {
_vm->_arc->skip(chunkSize);
} else {
- chunkBuffer = new byte[chunkSize];
+ // Only reallocate the chunk buffer if the new chunk is bigger
+ if (chunkSize > chunkBufferSize) {
+ delete[] chunkBuffer;
+ chunkBuffer = new byte[chunkSize];
+ chunkBufferSize = chunkSize;
+ }
+
_vm->_arc->read(chunkBuffer, chunkSize);
}
- movieOffset = _vm->_arc->pos();
-
switch (chunkType) {
case kChunkFirstImage:
case kChunkSubsequentImages:
unpackRle(chunkBuffer, _vm->_screen->_backScreen);
- // TODO: Rework this
- _vm->_screen->updateShakeScreen();
_vm->_screen->_fullRefresh = true;
- _vm->updateInput();
- _vm->drawScreen();
_soundChunkFramesLeft--;
if (_soundChunkFramesLeft <= _framesPerSoundChunk) {
fetchAudioChunks();
}
- while (_vm->_mixer->getSoundElapsedTime(_audioStreamHandle) < lastTime + 111) {
- g_system->delayMillis(10);
+ while (_vm->_mixer->getSoundElapsedTime(_audioStreamHandle) < (1000 * frame) / 9) {
+ if (_vm->_screen->_shakeActive && _vm->_screen->updateShakeScreen()) {
+ _vm->_screen->_fullRefresh = true;
+ }
+ _vm->updateInput();
+ _vm->drawScreen();
+ // Note: drawScreen() calls delayMillis()
}
- lastTime = _vm->_mixer->getSoundElapsedTime(_audioStreamHandle);
-
+ frame++;
break;
case kChunkPalette:
unpackPalette(chunkBuffer, moviePalette, 256, 3);
@@ -150,10 +153,10 @@ void MoviePlayer::playMovie(uint resIndex) {
// Already processed
break;
case kChunkShowSubtitle:
- // TODO: Check if the text is a subtitle (last character == 0xFE).
- // If so, don't show it if text display is disabled.
- memcpy(_vm->_script->getSlotData(subtitleSlot), chunkBuffer, chunkSize);
- _vm->_screen->updateTalkText(subtitleSlot, 0);
+ if (_vm->_cfgText) {
+ memcpy(_vm->_script->getSlotData(subtitleSlot), chunkBuffer, chunkSize);
+ _vm->_screen->updateTalkText(subtitleSlot, 0);
+ }
break;
case kChunkShakeScreen: // start/stop shakescreen effect
if (chunkBuffer[0] == 0xFF)
@@ -176,20 +179,17 @@ void MoviePlayer::playMovie(uint resIndex) {
error("MoviePlayer::playMovie(%04X) Unknown chunk type %d at %08X", resIndex, chunkType, _vm->_arc->pos() - 5 - chunkSize);
}
- delete[] chunkBuffer;
-
- _vm->_arc->seek(movieOffset, SEEK_SET);
-
if (!handleInput())
break;
-
}
+ delete[] chunkBuffer;
+
_audioStream->finish();
_vm->_mixer->stopHandle(_audioStreamHandle);
_vm->_arc->closeResource();
-
+
debug(0, "playMovie() done");
_vm->_sceneWidth = savedSceneWidth;
diff --git a/engines/toltecs/movie.h b/engines/toltecs/movie.h
index aecfac240f..8fa48975d7 100644
--- a/engines/toltecs/movie.h
+++ b/engines/toltecs/movie.h
@@ -36,7 +36,7 @@ public:
~MoviePlayer();
void playMovie(uint resIndex);
-
+
protected:
ToltecsEngine *_vm;
Audio::QueuingAudioStream *_audioStream;
@@ -47,11 +47,11 @@ protected:
void unpackPalette(byte *source, byte *dest, int elemCount, int elemSize);
void unpackRle(byte *source, byte *dest);
-
+
void fetchAudioChunks();
-
+
bool handleInput();
-
+
};
} // End of namespace Toltecs
diff --git a/engines/toltecs/music.cpp b/engines/toltecs/music.cpp
index c322961077..830e4a97da 100644
--- a/engines/toltecs/music.cpp
+++ b/engines/toltecs/music.cpp
@@ -20,15 +20,13 @@
*
*/
-// FIXME: This code is taken from SAGA and needs more work (e.g. setVolume).
+#include "audio/midiparser.h"
+#include "common/textconsole.h"
#include "toltecs/toltecs.h"
#include "toltecs/music.h"
#include "toltecs/resource.h"
-#include "audio/midiparser.h"
-#include "common/textconsole.h"
-
namespace Toltecs {
MusicPlayer::MusicPlayer(bool isGM) : _isGM(isGM), _buffer(NULL) {
@@ -62,7 +60,7 @@ void MusicPlayer::playMIDI(const byte *data, uint32 size, bool loop) {
memcpy(_buffer, data, size);
MidiParser *parser;
-
+
if (!memcmp(data, "FORM", 4))
parser = MidiParser::createParser_XMIDI(NULL);
else
@@ -77,7 +75,7 @@ void MusicPlayer::playMIDI(const byte *data, uint32 size, bool loop) {
_parser = parser;
- setVolume(127);
+ syncVolume();
_isLooping = loop;
_isPlaying = true;
@@ -86,16 +84,6 @@ void MusicPlayer::playMIDI(const byte *data, uint32 size, bool loop) {
}
}
-void MusicPlayer::pause() {
- setVolume(-1);
- _isPlaying = false;
-}
-
-void MusicPlayer::resume() {
- setVolume(127);
- _isPlaying = true;
-}
-
void MusicPlayer::stopAndClear() {
Common::StackLock lock(_mutex);
stop();
diff --git a/engines/toltecs/music.h b/engines/toltecs/music.h
index 79df1ea2f5..8d364dbb9f 100644
--- a/engines/toltecs/music.h
+++ b/engines/toltecs/music.h
@@ -37,8 +37,6 @@ public:
MusicPlayer(bool isGM = true);
void playMIDI(const byte *data, uint32 size, bool loop = false);
- void pause();
- void resume();
void stopAndClear();
// MidiDriver_BASE interface implementation
diff --git a/engines/toltecs/palette.cpp b/engines/toltecs/palette.cpp
index 706218e0ba..74683c6d7a 100644
--- a/engines/toltecs/palette.cpp
+++ b/engines/toltecs/palette.cpp
@@ -31,7 +31,7 @@ namespace Toltecs {
Palette::Palette(ToltecsEngine *vm) : _vm(vm) {
clearFragments();
-
+
memset(_colorTransTable, 0, sizeof(_colorTransTable));
}
@@ -81,7 +81,7 @@ void Palette::setDeltaPalette(byte *palette, byte mask, int8 deltaValue, int16 c
if (mask & 4) colors[index * 3 + 2] = CLIP<int>(rgb + deltaValue, 0, 63) << 2;
index++;
}
-
+
debug(0, "startIndex = %d; colorCount = %d", startIndex, colorCount);
_vm->_system->getPaletteManager()->setPalette((const byte *)colors, 0, 256);
@@ -101,9 +101,9 @@ void Palette::addFragment(uint resIndex, int16 id) {
Resource *fragmentResource = _vm->_res->load(resIndex);
byte count = fragmentResource->size / 3;
-
+
memcpy(&_mainPalette[_fragmentIndex * 3], fragmentResource->data, count * 3);
-
+
PaletteFragment fragment;
fragment.id = id;
fragment.index = _fragmentIndex;
@@ -126,7 +126,7 @@ uint16 Palette::findFragment(int16 id) {
break;
}
}
-
+
debug(0, "Palette::findFragment() result = %04X", result);
return result;
@@ -140,9 +140,9 @@ void Palette::clearFragments() {
void Palette::buildColorTransTable(byte limit, int8 deltaValue, byte mask) {
byte r = 0, g = 0, b = 0;
-
+
mask &= 7;
-
+
for (int i = 0; i < 256; i++) {
if (deltaValue < 0) {
@@ -161,7 +161,7 @@ void Palette::buildColorTransTable(byte limit, int8 deltaValue, byte mask) {
b -= deltaValue;
}
}
-
+
int bestIndex = 0;
uint16 bestMatch = 0xFFFF;
@@ -174,7 +174,7 @@ void Palette::buildColorTransTable(byte limit, int8 deltaValue, byte mask) {
bestIndex = j;
}
}
-
+
_colorTransTable[i] = bestIndex;
}
diff --git a/engines/toltecs/palette.h b/engines/toltecs/palette.h
index 7bcf06e027..570f51777e 100644
--- a/engines/toltecs/palette.h
+++ b/engines/toltecs/palette.h
@@ -66,7 +66,7 @@ protected:
int16 id;
byte index, count;
};
-
+
typedef Common::Array<PaletteFragment> PaletteFragmentArray;
ToltecsEngine *_vm;
diff --git a/engines/toltecs/render.cpp b/engines/toltecs/render.cpp
index 3f5356493e..4c41e6ce00 100644
--- a/engines/toltecs/render.cpp
+++ b/engines/toltecs/render.cpp
@@ -114,7 +114,7 @@ void RenderQueue::addMask(SegmapMaskRect &mask) {
void RenderQueue::update() {
bool doFullRefresh = _vm->_screen->_fullRefresh;
-
+
_updateUta->clear();
if (!doFullRefresh) {
@@ -166,7 +166,7 @@ void RenderQueue::update() {
for (RenderQueueArray::iterator iter = _currQueue->begin(); iter != _currQueue->end(); iter++) {
const RenderQueueItem *item = &(*iter);
-
+
if (item->flags == kRefresh || doFullRefresh) {
switch (item->type) {
@@ -200,7 +200,7 @@ void RenderQueue::update() {
SWAP(_currQueue, _prevQueue);
_currQueue->clear();
-
+
}
void RenderQueue::clear() {
@@ -249,16 +249,16 @@ bool RenderQueue::hasItemChanged(const RenderQueueItem &item1, const RenderQueue
if (item1.type != item2.type)
return true;
-
+
if (item1.rect.left != item2.rect.left ||
item1.rect.top != item2.rect.top ||
item1.rect.right != item2.rect.right ||
item1.rect.bottom != item2.rect.bottom)
return true;
-
+
if (item1.type == kText && item1.text.color != item2.text.color)
return true;
-
+
return false;
}
@@ -268,7 +268,7 @@ void RenderQueue::invalidateItemsByRect(const Common::Rect &rect, const RenderQu
if (item != subItem &&
subItem->flags == kUnchanged &&
rect.intersects(subItem->rect)) {
-
+
subItem->flags = kRefresh;
invalidateItemsByRect(subItem->rect, subItem);
}
diff --git a/engines/toltecs/render.h b/engines/toltecs/render.h
index bb9ec29959..59d7a3ddb9 100644
--- a/engines/toltecs/render.h
+++ b/engines/toltecs/render.h
@@ -75,7 +75,7 @@ public:
void addMask(SegmapMaskRect &mask);
void update();
void clear();
-
+
protected:
typedef Common::List<RenderQueueItem> RenderQueueArray;
@@ -87,7 +87,7 @@ protected:
RenderQueueItem *findItemInQueue(RenderQueueArray *queue, const RenderQueueItem &item);
bool hasItemChanged(const RenderQueueItem &item1, const RenderQueueItem &item2);
void invalidateItemsByRect(const Common::Rect &rect, const RenderQueueItem *item);
-
+
void addDirtyRect(const Common::Rect &rect);
void restoreDirtyBackground();
void updateDirtyRects();
diff --git a/engines/toltecs/resource.cpp b/engines/toltecs/resource.cpp
index b95e0444b1..0b9f7c8fcd 100644
--- a/engines/toltecs/resource.cpp
+++ b/engines/toltecs/resource.cpp
@@ -66,7 +66,7 @@ void ArchiveReader::dump(uint resIndex, const char *prefix) {
byte *data = new byte[resourceSize];
Common::String fn;
-
+
if (prefix)
fn = Common::String::format("%s_%04X.0", prefix, resIndex);
else
@@ -117,11 +117,11 @@ Resource *ResourceCache::load(uint resIndex) {
resItem->data = new byte[resItem->size];
_vm->_arc->read(resItem->data, resItem->size);
_vm->_arc->closeResource();
-
+
_cache[resIndex] = resItem;
-
+
return resItem;
-
+
}
}
diff --git a/engines/toltecs/saveload.cpp b/engines/toltecs/saveload.cpp
index c24d2149b0..6c195a34c2 100644
--- a/engines/toltecs/saveload.cpp
+++ b/engines/toltecs/saveload.cpp
@@ -36,12 +36,11 @@
namespace Toltecs {
/* TODO:
- - Save with F7; Load with F9
- Saving during an animation (AnimationPlayer) is not working correctly yet
- Maybe switch to SCUMM/Tinsel serialization approach?
*/
-#define TOLTECS_SAVEGAME_VERSION 3
+#define TOLTECS_SAVEGAME_VERSION 4
ToltecsEngine::kReadSaveHeaderError ToltecsEngine::readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header) {
@@ -93,7 +92,7 @@ void ToltecsEngine::savegame(const char *filename, const char *description) {
byte descriptionLen = strlen(description);
out->writeByte(descriptionLen);
out->write(description, descriptionLen);
-
+
Graphics::saveThumbnail(*out);
// Not used yet, reserved for future usage
@@ -141,8 +140,8 @@ void ToltecsEngine::savegame(const char *filename, const char *description) {
}
void ToltecsEngine::loadgame(const char *filename) {
- Common::InSaveFile *in;
- if (!(in = g_system->getSavefileManager()->openForLoading(filename))) {
+ Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(filename);
+ if (!in) {
warning("Can't open file '%s', game not loaded", filename);
return;
}
@@ -150,13 +149,13 @@ void ToltecsEngine::loadgame(const char *filename) {
SaveHeader header;
kReadSaveHeaderError errorCode = readSaveHeader(in, false, header);
-
+
if (errorCode != kRSHENoError) {
warning("Error loading savegame '%s'", filename);
delete in;
return;
}
-
+
_sound->stopAll();
_music->stopSequence();
g_engine->setTotalPlayTime(header.playTime * 1000);
@@ -182,7 +181,7 @@ void ToltecsEngine::loadgame(const char *filename) {
_mouseX = in->readUint16LE();
_mouseY = in->readUint16LE();
_mouseDisabled = in->readUint16LE();
-
+
_system->warpMouse(_mouseX, _mouseY);
_system->showMouse(_mouseDisabled == 0);
@@ -191,7 +190,7 @@ void ToltecsEngine::loadgame(const char *filename) {
_anim->loadState(in);
_screen->loadState(in);
if (header.version >= 2)
- _sound->loadState(in);
+ _sound->loadState(in, header.version);
if (header.version >= 3)
_music->loadState(in);
diff --git a/engines/toltecs/screen.cpp b/engines/toltecs/screen.cpp
index 634917a7b1..c8d6740b02 100644
--- a/engines/toltecs/screen.cpp
+++ b/engines/toltecs/screen.cpp
@@ -43,9 +43,11 @@ Screen::Screen(ToltecsEngine *vm) : _vm(vm) {
// Screen shaking
_shakeActive = false;
+ _shakeTime = 0;
_shakeCounterInit = 0;
_shakeCounter = 0;
_shakePos = 0;
+ _shakeTime = 0;
// Verb line
_verbLineNum = 0;
@@ -73,7 +75,7 @@ Screen::~Screen() {
delete[] _frontScreen;
delete[] _backScreen;
-
+
delete _renderQueue;
}
@@ -129,7 +131,7 @@ void Screen::drawGuiImage(int16 x, int16 y, uint resIndex) {
byte *dest = _frontScreen + x + (y + _vm->_cameraHeight) * 640;
//debug(0, "Screen::drawGuiImage() x = %d; y = %d; w = %d; h = %d; resIndex = %d", x, y, width, height, resIndex);
-
+
while (workHeight > 0) {
int count = 1;
byte pixel = *imageData++;
@@ -156,6 +158,7 @@ void Screen::drawGuiImage(int16 x, int16 y, uint resIndex) {
void Screen::startShakeScreen(int16 shakeCounter) {
_shakeActive = true;
+ _shakeTime = 0;
_shakeCounterInit = shakeCounter;
_shakeCounter = shakeCounter;
_shakePos = 0;
@@ -166,15 +169,19 @@ void Screen::stopShakeScreen() {
_vm->_system->setShakePos(0);
}
-void Screen::updateShakeScreen() {
- if (_shakeActive) {
+bool Screen::updateShakeScreen() {
+ // Assume shaking happens no more often than 50 times per second
+ if (_shakeActive && _vm->_system->getMillis() - _shakeTime >= 20) {
+ _shakeTime = _vm->_system->getMillis();
_shakeCounter--;
if (_shakeCounter == 0) {
_shakeCounter = _shakeCounterInit;
_shakePos ^= 8;
_vm->_system->setShakePos(_shakePos);
+ return true;
}
}
+ return false;
}
void Screen::addStaticSprite(byte *spriteItem) {
@@ -247,7 +254,7 @@ void Screen::addAnimatedSprite(int16 x, int16 y, int16 fragmentId, byte *data, i
} else {
loopNum |= 0x8000;
}
-
+
WRITE_LE_UINT16(spriteItem + 0, loopNum);
WRITE_LE_UINT16(spriteItem + 4, frameNum);
@@ -308,9 +315,9 @@ void Screen::updateVerbLine(int16 slotIndex, int16 slotOffset) {
wrapState.len2 = 0;
y = _verbLineY;
-
+
memset(wrapState.textBuffer, 0, sizeof(wrapState.textBuffer));
-
+
for (int16 i = 0; i <= _verbLineNum; i++) {
wrapState.sourceString = _vm->_script->getSlotData(_verbLineItems[i].slotIndex) + _verbLineItems[i].slotOffset;
len = wrapGuiText(_fontResIndexArray[0], _verbLineWidth, wrapState);
@@ -331,19 +338,19 @@ void Screen::updateVerbLine(int16 slotIndex, int16 slotOffset) {
wrapState.sourceString++;
wrapState.len1 -= len;
wrapState.len2 = len + 1;
-
+
drawGuiText(_verbLineX - 1 - (wrapState.width / 2), y, 0xF9, 0xFF, _fontResIndexArray[0], wrapState);
wrapState.destString = wrapState.textBuffer;
wrapState.width = 0;
len = wrapGuiText(_fontResIndexArray[0], _verbLineWidth, wrapState);
wrapState.len1 += len;
-
+
y += 9;
}
y += 9;
}
-
+
wrapState.len1 -= len;
wrapState.len2 = len;
@@ -463,13 +470,12 @@ void Screen::addTalkTextRect(Font &font, int16 x, int16 &y, int16 length, int16
textRect->x = CLIP<int16>(x - width / 2, 0, 640);
item->lineCount++;
}
-
+
y += font.getHeight() - 1;
}
void Screen::addTalkTextItemsToRenderQueue() {
-
for (int16 i = 0; i <= _talkTextItemNum; i++) {
TalkTextItem *item = &_talkTextItems[i];
byte *text = _vm->_script->getSlotData(item->slotIndex) + item->slotOffset;
@@ -482,14 +488,15 @@ void Screen::addTalkTextItemsToRenderQueue() {
if (item->duration < 0)
item->duration = 0;
+ if (!_vm->_cfgText)
+ return;
+
for (byte j = 0; j < item->lineCount; j++) {
- _renderQueue->addText(item->lines[j].x, item->lines[j].y, item->color, _fontResIndexArray[item->fontNum],
- text, item->lines[j].length);
+ _renderQueue->addText(item->lines[j].x, item->lines[j].y, item->color,
+ _fontResIndexArray[item->fontNum], text, item->lines[j].length);
text += item->lines[j].length;
}
-
}
-
}
int16 Screen::getTalkTextDuration() {
@@ -559,7 +566,7 @@ int16 Screen::wrapGuiText(uint fontResIndex, int maxWidth, GuiTextWrapState &wra
Font font(_vm->_res->load(fontResIndex)->data);
int16 len = 0;
-
+
while (*wrapState.sourceString >= 0x20 && *wrapState.sourceString < 0xF0) {
byte ch = *wrapState.sourceString;
byte charWidth;
@@ -573,9 +580,9 @@ int16 Screen::wrapGuiText(uint fontResIndex, int maxWidth, GuiTextWrapState &wra
wrapState.width += charWidth;
*wrapState.destString++ = *wrapState.sourceString++;
}
-
+
return len;
-
+
}
void Screen::drawGuiText(int16 x, int16 y, byte fontColor1, byte fontColor2, uint fontResIndex, GuiTextWrapState &wrapState) {
@@ -765,7 +772,7 @@ void Screen::loadState(Common::ReadStream *in) {
_verbLineItems[i].slotIndex = in->readUint16LE();
_verbLineItems[i].slotOffset = in->readUint16LE();
}
-
+
// Load talk text items
_talkTextX = in->readUint16LE();
_talkTextY = in->readUint16LE();
@@ -786,7 +793,7 @@ void Screen::loadState(Common::ReadStream *in) {
_talkTextItems[i].lines[j].length = in->readUint16LE();
}
}
-
+
// Load GUI bitmap
{
byte *gui = _frontScreen + _vm->_cameraHeight * 640;
diff --git a/engines/toltecs/screen.h b/engines/toltecs/screen.h
index 988f59c840..788cde50c6 100644
--- a/engines/toltecs/screen.h
+++ b/engines/toltecs/screen.h
@@ -154,15 +154,15 @@ public:
~Screen();
void unpackRle(byte *source, byte *dest, uint16 width, uint16 height);
-
+
void loadMouseCursor(uint resIndex);
-
+
void drawGuiImage(int16 x, int16 y, uint resIndex);
-
+
void startShakeScreen(int16 shakeCounter);
void stopShakeScreen();
- void updateShakeScreen();
-
+ bool updateShakeScreen();
+
// Sprite list
void addStaticSprite(byte *spriteItem);
void addAnimatedSprite(int16 x, int16 y, int16 fragmentId, byte *data, int16 *spriteArray, bool loop, int mode);
@@ -175,7 +175,7 @@ public:
// Verb line
void updateVerbLine(int16 slotIndex, int16 slotOffset);
-
+
// Talk text
void updateTalkText(int16 slotIndex, int16 slotOffset);
void addTalkTextRect(Font &font, int16 x, int16 &y, int16 length, int16 width, TalkTextItem *item);
@@ -207,7 +207,7 @@ public:
int16 slotIndex;
int16 slotOffset;
};
-
+
struct Rect {
int16 x, y, width, height;
};
@@ -215,12 +215,13 @@ public:
ToltecsEngine *_vm;
byte *_frontScreen, *_backScreen;
-
+
uint _fontResIndexArray[10];
byte _fontColor1, _fontColor2;
// Screen shaking
bool _shakeActive;
+ uint32 _shakeTime;
int16 _shakeCounterInit, _shakeCounter;
int _shakePos;
@@ -229,7 +230,7 @@ public:
VerbLineItem _verbLineItems[8];
int16 _verbLineX, _verbLineY, _verbLineWidth;
int16 _verbLineCount;
-
+
// Talk text
int16 _talkTextX, _talkTextY;
int16 _talkTextMaxWidth;
diff --git a/engines/toltecs/script.cpp b/engines/toltecs/script.cpp
index 9683831980..5e8617bc43 100644
--- a/engines/toltecs/script.cpp
+++ b/engines/toltecs/script.cpp
@@ -183,10 +183,7 @@ void ScriptInterpreter::setMainScript(uint slotIndex) {
}
void ScriptInterpreter::runScript() {
- uint32 lastScreenUpdate = 0;
-
while (!_vm->shouldQuit()) {
-
if (_vm->_movieSceneFlag)
_vm->_mouseButton = 0;
@@ -197,7 +194,7 @@ void ScriptInterpreter::runScript() {
_vm->saveGameState(_vm->_saveLoadSlot, _vm->_saveLoadDescription);
_vm->_saveLoadRequested = 0;
}
-
+
if (_switchLocalDataNear) {
_switchLocalDataNear = false;
_localData = getSlotData(_regs.reg4);
@@ -214,20 +211,10 @@ void ScriptInterpreter::runScript() {
_localData = _stack + 2;
_switchLocalDataNear = true;
}
-
+
byte opcode = readByte();
execOpcode(opcode);
-
- // Update the screen at semi-regular intervals, else the mouse
- // cursor will be jerky.
- uint32 now = _vm->_system->getMillis();
- if (now < lastScreenUpdate || now - lastScreenUpdate > 10) {
- _vm->_system->updateScreen();
- lastScreenUpdate = _vm->_system->getMillis();
- }
-
}
-
}
byte ScriptInterpreter::readByte() {
@@ -547,7 +534,7 @@ const char *getVarName(uint variable) {
int16 ScriptInterpreter::getGameVar(uint variable) {
debug(0, "ScriptInterpreter::getGameVar(%d{%s})", variable, getVarName(variable));
-
+
switch (variable) {
case 0: return _vm->_mouseDisabled;
case 1: return _vm->_mouseY;
@@ -579,7 +566,7 @@ int16 ScriptInterpreter::getGameVar(uint variable) {
void ScriptInterpreter::setGameVar(uint variable, int16 value) {
debug(0, "ScriptInterpreter::setGameVar(%d{%s}, %d)", variable, getVarName(variable), value);
-
+
switch (variable) {
case 0:
_vm->_mouseDisabled = value;
@@ -718,7 +705,7 @@ void ScriptInterpreter::saveState(Common::WriteStream *out) {
// Save stack
out->write(_stack, kScriptStackSize);
out->writeUint16LE(_savedSp);
-
+
// Save IP
out->writeUint16LE((int16)(_code - getSlotData(_regs.reg4)));
@@ -1046,29 +1033,21 @@ void ScriptInterpreter::sfHandleInput() {
Only scancodes known to be used (so far) are converted
*/
switch (_vm->_keyState.keycode) {
- case Common::KEYCODE_ESCAPE:
+ case Common::KEYCODE_ESCAPE:
keyCode = 1;
break;
case Common::KEYCODE_F10:
keyCode = 68;
break;
default:
- break;
+ break;
}
}
localWrite16(varOfs, keyCode);
}
void ScriptInterpreter::sfRunOptionsScreen() {
- _vm->_screen->loadMouseCursor(12);
- _vm->_palette->loadAddPalette(9, 224);
- _vm->_palette->setDeltaPalette(_vm->_palette->getMainPalette(), 7, 0, 31, 224);
- _vm->_screen->finishTalkTextItems();
- _vm->_screen->clearSprites();
- CursorMan.showMouse(true);
- _vm->_menuSystem->run();
- _vm->_keyState.reset();
- _switchLocalDataNear = true;
+ _vm->showMenu(kMenuIdMain);
}
/* NOTE: The opcodes sfPrecacheSprites, sfPrecacheSounds1, sfPrecacheSounds2 and
@@ -1076,7 +1055,7 @@ void ScriptInterpreter::sfRunOptionsScreen() {
of data so the game doesn't stall while playing (due to the slow speed of
CD-Drives back then). This is not needed in ScummVM since all supported
systems are fast enough to load data in-game. */
-
+
void ScriptInterpreter::sfPrecacheSprites() {
// See note above
}
@@ -1102,7 +1081,9 @@ void ScriptInterpreter::sfSaveStackPtr() {
}
void ScriptInterpreter::sfPlayMovie() {
+ CursorMan.showMouse(false);
_vm->_moviePlayer->playMovie(arg16(3));
+ CursorMan.showMouse(true);
}
} // End of namespace Toltecs
diff --git a/engines/toltecs/script.h b/engines/toltecs/script.h
index 0c1898c525..89dca4598f 100644
--- a/engines/toltecs/script.h
+++ b/engines/toltecs/script.h
@@ -56,6 +56,8 @@ public:
void saveState(Common::WriteStream *out);
void loadState(Common::ReadStream *in);
+ void setSwitchLocalDataNear(bool newValue) { _switchLocalDataNear = newValue; }
+
protected:
struct ScriptRegs {
@@ -88,13 +90,13 @@ protected:
bool _cmpBitTest;
ScriptSlot _slots[kMaxScriptSlots];
-
+
ScriptRegs _regs;
int16 _savedSp;
byte readByte();
int16 readInt16();
-
+
void execOpcode(byte opcode);
void setupScriptFunctions();
diff --git a/engines/toltecs/segmap.cpp b/engines/toltecs/segmap.cpp
index f7d806c67b..b06c0af675 100644
--- a/engines/toltecs/segmap.cpp
+++ b/engines/toltecs/segmap.cpp
@@ -48,7 +48,7 @@ void SegmentMap::load(byte *source) {
uint16 maskRectCount = READ_LE_UINT16(source);
source += 2;
uint16 maskRectDataSize = maskRectCount * 12 + 2;
-
+
debug(0, "SegmentMap::load() maskRectCount = %d", maskRectCount);
for (uint16 i = 0; i < maskRectCount; i++) {
@@ -74,25 +74,25 @@ void SegmentMap::load(byte *source) {
// Load path rects
source += 2; // skip rects array size
-
+
uint16 pathRectCount = READ_LE_UINT16(source);
source += 2;
-
+
debug(0, "SegmentMap::load() pathRectCount = %d", pathRectCount);
-
+
for (uint16 i = 0; i < pathRectCount; i++) {
SegmapPathRect pathRect;
pathRect.y1 = READ_LE_UINT16(source);
pathRect.x1 = READ_LE_UINT16(source + 2);
pathRect.y2 = pathRect.y1 + READ_LE_UINT16(source + 4);
pathRect.x2 = pathRect.x1 + READ_LE_UINT16(source + 6);
-
+
debug(0, "SegmentMap::load() (%d, %d, %d, %d)", pathRect.x1, pathRect.y1, pathRect.x2, pathRect.y2);
source += 8;
_pathRects.push_back(pathRect);
}
-
+
// Load info rects
source += 2; // skip rects array size
@@ -141,7 +141,7 @@ void SegmentMap::adjustPathPoint(int16 &x, int16 &y) {
uint32 minDistance = 0xFFFFFFFF, distance;
int16 adjustedX = 0, adjustedY = 0, x2, y2;
-
+
for (int16 rectIndex = 0; rectIndex < (int16)_pathRects.size(); rectIndex++) {
if (x >= _pathRects[rectIndex].x1 && x < _pathRects[rectIndex].x2) {
@@ -174,7 +174,7 @@ void SegmentMap::adjustPathPoint(int16 &x, int16 &y) {
}
}
-
+
x = adjustedX;
y = adjustedY;
@@ -318,7 +318,7 @@ void SegmentMap::findPath(int16 *pointsArray, int16 destX, int16 destY, int16 so
pointsArray[0] = 0;
pointsArray[1] = TO_LE_16(_pathNodesCount + 1);
}
-
+
debug(0, "SegmentMap::findPath() count = %d", FROM_LE_16(pointsArray[1]));
#if 0 // DEBUG: Draw the path we found
@@ -335,7 +335,7 @@ void SegmentMap::findPath(int16 *pointsArray, int16 destX, int16 destY, int16 so
sy = y;
}
#endif
-
+
}
int8 SegmentMap::getScalingAtPoint(int16 x, int16 y) {
diff --git a/engines/toltecs/segmap.h b/engines/toltecs/segmap.h
index 30182a6b71..dda0edeb88 100644
--- a/engines/toltecs/segmap.h
+++ b/engines/toltecs/segmap.h
@@ -61,14 +61,14 @@ public:
void getRgbModifiertAtPoint(int16 x, int16 y, int16 id, byte &r, byte &g, byte &b);
void addMasksToRenderQueue();
-
+
//protected:
public: // for debugging purposes
struct SegmapPathRect {
int16 x1, y1, x2, y2;
};
-
+
struct SegmapInfoRect {
int16 y, x;
int16 height, width;
@@ -78,11 +78,11 @@ public: // for debugging purposes
return py >= y && py <= y + height && px >= x && px <= x + width;
}
};
-
+
struct PathPoint {
int16 y, x;
};
-
+
typedef Common::Array<SegmapMaskRect> SegmapMaskRectArray;
typedef Common::Array<SegmapPathRect> SegmapPathRectArray;
typedef Common::Array<SegmapInfoRect> SegmapInfoRectArray;
diff --git a/engines/toltecs/sound.cpp b/engines/toltecs/sound.cpp
index c9ef00e31b..4b281392e5 100644
--- a/engines/toltecs/sound.cpp
+++ b/engines/toltecs/sound.cpp
@@ -34,48 +34,38 @@ namespace Toltecs {
Sound::Sound(ToltecsEngine *vm) : _vm(vm) {
for (int i = 0; i < kMaxChannels; i++) {
- channels[i].type = kChannelTypeEmpty;
- channels[i].resIndex = -1;
+ clearChannel(i);
}
}
Sound::~Sound() {
}
+void Sound::clearChannel(int channel) {
+ channels[channel].type = kChannelTypeEmpty;
+ channels[channel].resIndex = -1;
+ channels[channel].volume = 0;
+ channels[channel].panning = 0;
+}
+
void Sound::playSpeech(int16 resIndex) {
debug(0, "playSpeech(%d)", resIndex);
- internalPlaySound(resIndex, kChannelTypeSpeech, 50 /*TODO*/, 0);
+
+ if (_vm->_cfgVoices)
+ internalPlaySound(resIndex, kChannelTypeSpeech, 50 /*TODO*/, 0);
}
void Sound::playSound(int16 resIndex, int16 type, int16 volume) {
-
- // TODO: Use the right volumes
-
debug(0, "playSound(%d, %d, %d)", resIndex, type, volume);
-
- if (volume == -1 || type == -2) {
- if (type == kChannelTypeBackground) {
- internalPlaySound(resIndex, type, 50 /*TODO*/, 0);
- } else {
- internalPlaySound(resIndex, type, 100 /*TODO*/, 0);
- }
- } else {
- internalPlaySound(resIndex, type, 100 /*TODO*/, 0);
- }
+ internalPlaySound(resIndex, type, volume, 0);
}
void Sound::playSoundAtPos(int16 resIndex, int16 x, int16 y) {
-
debug(0, "playSoundAtPos(%d, %d, %d)", resIndex, x, y);
- int16 volume, panning = 0, deltaX = 0;
- int8 scaling = _vm->_segmap->getScalingAtPoint(x, y);
-
- if (scaling >= 0)
- volume = 50 + ABS(scaling) / 2;
- else
- volume = 50 - ABS(scaling) / 2;
+ int16 volume = 50 + ABS(_vm->_segmap->getScalingAtPoint(x, y)) / 2;
+ int16 panning = 0, deltaX = 0;
if (_vm->_cameraX > x)
deltaX = _vm->_cameraX - x;
@@ -85,32 +75,31 @@ void Sound::playSoundAtPos(int16 resIndex, int16 x, int16 y) {
deltaX = 600;
volume = ((100 - deltaX / 6) * volume) / 100;
-
+
if (_vm->_cameraX + 320 != x) {
panning = CLIP(x - (_vm->_cameraX + 320), -381, 381) / 3;
}
internalPlaySound(resIndex, 1, volume, panning);
-
}
void Sound::internalPlaySound(int16 resIndex, int16 type, int16 volume, int16 panning) {
+ // Change the game's sound volume (0 - 100) to Scummvm's scale (0 - 255)
+ volume = (volume == -1) ? 255 : volume * 255 / 100;
if (resIndex == -1) {
// Stop all sounds
_vm->_mixer->stopAll();
_vm->_screen->keepTalkTextItemsAlive();
for (int i = 0; i < kMaxChannels; i++) {
- channels[i].type = kChannelTypeEmpty;
- channels[i].resIndex = -1;
+ clearChannel(i);
}
} else if (type == -2) {
// Stop sounds with specified resIndex
for (int i = 0; i < kMaxChannels; i++) {
if (channels[i].resIndex == resIndex) {
_vm->_mixer->stopHandle(channels[i].handle);
- channels[i].type = kChannelTypeEmpty;
- channels[i].resIndex = -1;
+ clearChannel(i);
}
}
} else {
@@ -119,7 +108,7 @@ void Sound::internalPlaySound(int16 resIndex, int16 type, int16 volume, int16 pa
// Stop speech and play new sound
stopSpeech();
}
-
+
// Play new sound in empty channel
int freeChannel = -1;
for (int i = 0; i < kMaxChannels; i++) {
@@ -128,7 +117,7 @@ void Sound::internalPlaySound(int16 resIndex, int16 type, int16 volume, int16 pa
break;
}
}
-
+
// If all channels are in use no new sound will be played
if (freeChannel >= 0) {
Resource *soundResource = _vm->_res->load(resIndex);
@@ -141,19 +130,17 @@ void Sound::internalPlaySound(int16 resIndex, int16 type, int16 volume, int16 pa
channels[freeChannel].type = type;
channels[freeChannel].resIndex = resIndex;
+ channels[freeChannel].volume = volume;
+ channels[freeChannel].panning = panning;
- Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType;
- /*
- switch (type) {
- }
- */
+ Audio::Mixer::SoundType soundType = getScummVMSoundType((SoundChannelType)type);
_vm->_mixer->playStream(soundType, &channels[freeChannel].handle,
- stream, -1, volume, panning);
+ stream, -1, volume, panning);
}
}
-
+
}
void Sound::updateSpeech() {
@@ -170,8 +157,7 @@ void Sound::stopSpeech() {
if (channels[i].type == kChannelTypeSpeech) {
_vm->_mixer->stopHandle(channels[i].handle);
_vm->_screen->keepTalkTextItemsAlive();
- channels[i].type = kChannelTypeEmpty;
- channels[i].resIndex = -1;
+ clearChannel(i);
}
}
}
@@ -180,8 +166,7 @@ void Sound::stopAll() {
for (int i = 0; i < kMaxChannels; i++) {
_vm->_mixer->stopHandle(channels[i].handle);
_vm->_screen->keepTalkTextItemsAlive();
- channels[i].type = kChannelTypeEmpty;
- channels[i].resIndex = -1;
+ clearChannel(i);
}
}
@@ -189,13 +174,22 @@ void Sound::saveState(Common::WriteStream *out) {
for (int i = 0; i < kMaxChannels; i++) {
out->writeSint16LE(channels[i].type);
out->writeSint16LE(channels[i].resIndex);
+ out->writeSint16LE(channels[i].volume);
+ out->writeSint16LE(channels[i].panning);
}
}
-void Sound::loadState(Common::ReadStream *in) {
+void Sound::loadState(Common::ReadStream *in, int version) {
for (int i = 0; i < kMaxChannels; i++) {
channels[i].type = in->readSint16LE();
channels[i].resIndex = in->readSint16LE();
+ if (version < 4) {
+ channels[i].volume = (channels[i].type == kChannelTypeBackground) ? 50 : 100;
+ channels[i].panning = 0;
+ } else {
+ channels[i].volume = in->readSint16LE();
+ channels[i].panning = in->readSint16LE();
+ }
if (channels[i].type != kChannelTypeEmpty) {
Resource *soundResource = _vm->_res->load(channels[i].resIndex);
@@ -206,19 +200,26 @@ void Sound::loadState(Common::ReadStream *in) {
DisposeAfterUse::NO),
channels[i].type == kChannelTypeBackground ? 0 : 1);
- Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType;
- /*
- switch (type) {
- }
- */
-
- // TODO: Volume and panning
- int16 volume = (channels[i].type == kChannelTypeBackground) ? 50 : 100;
+ Audio::Mixer::SoundType soundType = getScummVMSoundType((SoundChannelType)channels[i].type);
_vm->_mixer->playStream(soundType, &channels[i].handle,
- stream, -1, volume, /*panning*/0);
+ stream, -1, channels[i].volume, channels[i].panning);
}
}
}
+Audio::Mixer::SoundType Sound::getScummVMSoundType(SoundChannelType type) const {
+ switch (type) {
+ case kChannelTypeBackground:
+ case kChannelTypeSfx:
+ return Audio::Mixer::kSFXSoundType;
+ case kChannelTypeSpeech:
+ return Audio::Mixer::kSpeechSoundType;
+ break;
+ default:
+ return Audio::Mixer::kSFXSoundType;
+ break;
+ }
+}
+
} // End of namespace Toltecs
diff --git a/engines/toltecs/sound.h b/engines/toltecs/sound.h
index e292d22c0f..48a6cd1318 100644
--- a/engines/toltecs/sound.h
+++ b/engines/toltecs/sound.h
@@ -42,6 +42,8 @@ enum SoundChannelType {
struct SoundChannel {
int16 resIndex;
int16 type;
+ int16 volume;
+ int16 panning;
Audio::SoundHandle handle;
};
@@ -60,15 +62,16 @@ public:
void stopAll();
void saveState(Common::WriteStream *out);
- void loadState(Common::ReadStream *in);
+ void loadState(Common::ReadStream *in, int version);
protected:
ToltecsEngine *_vm;
SoundChannel channels[kMaxChannels];
+ void clearChannel(int channel);
void internalPlaySound(int16 resIndex, int16 type, int16 volume, int16 panning);
-
+ Audio::Mixer::SoundType getScummVMSoundType(SoundChannelType type) const;
};
diff --git a/engines/toltecs/sprite.cpp b/engines/toltecs/sprite.cpp
index 7a02663793..6101eb7d85 100644
--- a/engines/toltecs/sprite.cpp
+++ b/engines/toltecs/sprite.cpp
@@ -199,7 +199,7 @@ bool Screen::createSpriteDrawItem(const DrawRequest &drawRequest, SpriteDrawItem
sprite.frameNum = frameNum;
spriteData = _vm->_res->load(drawRequest.resIndex)->data;
-
+
if (drawRequest.flags & 0x1000) {
sprite.flags |= 4;
}
@@ -207,7 +207,7 @@ bool Screen::createSpriteDrawItem(const DrawRequest &drawRequest, SpriteDrawItem
if (drawRequest.flags & 0x2000) {
sprite.flags |= 0x10;
}
-
+
if (drawRequest.flags & 0x4000) {
sprite.flags |= 0x40;
}
@@ -218,7 +218,7 @@ bool Screen::createSpriteDrawItem(const DrawRequest &drawRequest, SpriteDrawItem
if (spriteFrameEntry.w == 0 || spriteFrameEntry.h == 0)
return false;
-
+
sprite.offset = spriteFrameEntry.offset;
sprite.width = spriteFrameEntry.w;
@@ -263,12 +263,12 @@ bool Screen::createSpriteDrawItem(const DrawRequest &drawRequest, SpriteDrawItem
xoffs -= (xoffs * scaleValue) / 100;
yoffs -= (yoffs * scaleValue) / 100;
}
-
+
}
-
+
sprite.x -= xoffs;
sprite.y -= yoffs;
-
+
sprite.yerror = sprite.ydelta;
// Now we check if the sprite needs to be clipped
@@ -283,7 +283,7 @@ bool Screen::createSpriteDrawItem(const DrawRequest &drawRequest, SpriteDrawItem
sprite.height -= clipHeight;
if (sprite.height <= 0)
return false;
-
+
sprite.y = _vm->_cameraY;
// If the sprite is scaled
@@ -311,7 +311,7 @@ bool Screen::createSpriteDrawItem(const DrawRequest &drawRequest, SpriteDrawItem
}
sprite.yerror = chopHeight;
}
-
+
spriteFrameData = spriteData + sprite.offset;
// Now the sprite's offset is adjusted to point to the starting line
if ((sprite.flags & 0x10) == 0) {
@@ -439,7 +439,7 @@ void Screen::drawSpriteCore(byte *dest, SpriteFilter &reader, const SpriteDrawIt
SpriteReaderStatus status;
PixelPacket packet;
-
+
byte *destp = dest;
int16 skipX = sprite.skipX;
@@ -459,7 +459,7 @@ void Screen::drawSpriteCore(byte *dest, SpriteFilter &reader, const SpriteDrawIt
status = reader.readPacket(packet);
}
}
-
+
if (w - packet.count < 0)
packet.count = w;
diff --git a/engines/toltecs/toltecs.cpp b/engines/toltecs/toltecs.cpp
index 6d6c37dffd..9f3a10a03b 100644
--- a/engines/toltecs/toltecs.cpp
+++ b/engines/toltecs/toltecs.cpp
@@ -62,11 +62,6 @@ struct GameSettings {
};
ToltecsEngine::ToltecsEngine(OSystem *syst, const ToltecsGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) {
-
- // Setup mixer
- _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
- _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
-
_rnd = new Common::RandomSource("toltecs");
}
@@ -85,7 +80,7 @@ Common::Error ToltecsEngine::run() {
_flag01 = 0;
_saveLoadRequested = 0;
-
+
_cameraX = 0;
_cameraY = 0;
_newCameraX = 0;
@@ -96,7 +91,7 @@ Common::Error ToltecsEngine::run() {
_sceneWidth = 0;
_sceneHeight = 0;
-
+
_doSpeech = true;
_doText = true;
@@ -126,17 +121,27 @@ Common::Error ToltecsEngine::run() {
_moviePlayer = new MoviePlayer(this);
_music = new Music(_arc);
_menuSystem = new MenuSystem(this);
-
+
_sound = new Sound(this);
+ _cfgText = ConfMan.getBool("subtitles");
+ _cfgVoices = !ConfMan.getBool("speech_mute");
+
+ bool mute = false;
+ if (ConfMan.hasKey("mute"))
+ mute = ConfMan.getBool("mute");
+
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, mute ? 0 : ConfMan.getInt("speech_volume"));
+ _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, mute ? 0 : ConfMan.getInt("music_volume"));
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, mute ? 0 : ConfMan.getInt("sfx_volume"));
syncSoundSettings();
CursorMan.showMouse(true);
setupSysStrings();
-//#define TEST_MENU
-#ifdef TEST_MENU
+#if 0
+ // Menu test
_screen->registerFont(0, 0x0D);
_screen->registerFont(1, 0x0E);
_screen->loadMouseCursor(12);
@@ -181,7 +186,7 @@ Common::Error ToltecsEngine::run() {
delete _music;
delete _moviePlayer;
delete _menuSystem;
-
+
delete _sound;
return Common::kNoError;
@@ -245,7 +250,7 @@ void ToltecsEngine::loadScene(uint resIndex) {
_screen->_fullRefresh = true;
_screen->_renderQueue->clear();
-
+
}
void ToltecsEngine::updateScreen() {
@@ -306,6 +311,7 @@ void ToltecsEngine::drawScreen() {
}
_system->updateScreen();
+ _system->delayMillis(10);
updateCamera();
}
@@ -321,15 +327,14 @@ void ToltecsEngine::updateInput() {
//debug("key: flags = %02X; keycode = %d", _keyState.flags, _keyState.keycode);
- // FIXME: This is just for debugging
switch (event.kbd.keycode) {
- case Common::KEYCODE_F7:
- savegame("toltecs.001", "Quicksave");
+ case Common::KEYCODE_F5:
+ showMenu(kMenuIdSave);
break;
- case Common::KEYCODE_F9:
- loadgame("toltecs.001");
+ case Common::KEYCODE_F7:
+ showMenu(kMenuIdLoad);
break;
- case Common::KEYCODE_ESCAPE:
+ case Common::KEYCODE_SPACE:
// Skip current dialog line, if a dialog is active
if (_screen->getTalkTextDuration() > 0) {
_sound->stopSpeech();
@@ -422,7 +427,7 @@ void ToltecsEngine::setCamera(int16 x, int16 y) {
_screen->finishTalkTextItems();
_screen->clearSprites();
-
+
_cameraX = x;
_newCameraX = x;
@@ -491,9 +496,9 @@ void ToltecsEngine::updateCamera() {
}
void ToltecsEngine::talk(int16 slotIndex, int16 slotOffset) {
-
+
byte *scanData = _script->getSlotData(slotIndex) + slotOffset;
-
+
while (*scanData < 0xF0) {
if (*scanData == 0x19) {
scanData++;
@@ -506,7 +511,7 @@ void ToltecsEngine::talk(int16 slotIndex, int16 slotOffset) {
}
scanData++;
}
-
+
if (*scanData == 0xFE) {
if (_doSpeech) {
int16 resIndex = READ_LE_UINT16(scanData + 1);
@@ -540,7 +545,7 @@ void ToltecsEngine::walk(byte *walkData) {
walkInfo.xerror = READ_LE_UINT16(walkData + 14);
walkInfo.mulValue = READ_LE_UINT16(walkData + 16);
walkInfo.scaling = READ_LE_UINT16(walkData + 18);
-
+
walkInfo.scaling = -_segmap->getScalingAtPoint(walkInfo.x, walkInfo.y);
if (walkInfo.y1 < walkInfo.y2)
@@ -548,7 +553,7 @@ void ToltecsEngine::walk(byte *walkData) {
else
ystep = 1;
ydelta = ABS(walkInfo.y1 - walkInfo.y2) * _walkSpeedY;
-
+
if (walkInfo.x1 < walkInfo.x2)
xstep = -1;
else
@@ -611,11 +616,11 @@ void ToltecsEngine::walk(byte *walkData) {
}
-int16 ToltecsEngine::findRectAtPoint(byte *rectData, int16 x, int16 y, int16 index, int16 itemSize,
+int16 ToltecsEngine::findRectAtPoint(byte *rectData, int16 x, int16 y, int16 index, int16 itemSize,
byte *rectDataEnd) {
rectData += index * itemSize;
-
+
while (rectData < rectDataEnd) {
int16 rectY = READ_LE_UINT16(rectData);
if (rectY == -10)
@@ -633,9 +638,32 @@ int16 ToltecsEngine::findRectAtPoint(byte *rectData, int16 x, int16 y, int16 ind
index++;
rectData += itemSize;
}
-
+
return -1;
+}
+
+void ToltecsEngine::showMenu(MenuID menuId) {
+ _screen->loadMouseCursor(12);
+ _palette->loadAddPalette(9, 224);
+ _palette->setDeltaPalette(_palette->getMainPalette(), 7, 0, 31, 224);
+ _screen->finishTalkTextItems();
+ _screen->clearSprites();
+ CursorMan.showMouse(true);
+ _menuSystem->run(menuId);
+ _keyState.reset();
+ _script->setSwitchLocalDataNear(true);
+}
+
+void ToltecsEngine::syncSoundSettings() {
+ Engine::syncSoundSettings();
+
+ bool mute = false;
+ if (ConfMan.hasKey("mute"))
+ mute = ConfMan.getBool("mute");
+ _cfgVoicesVolume = (mute ? 0 : ConfMan.getInt("speech_volume")) * 20 / Audio::Mixer::kMaxChannelVolume;
+ _cfgMusicVolume = (mute ? 0 : ConfMan.getInt("music_volume")) * 20 / Audio::Mixer::kMaxChannelVolume;
+ _cfgSoundFXVolume = (mute ? 0 : ConfMan.getInt("sfx_volume")) * 20 / Audio::Mixer::kMaxChannelVolume;
}
} // End of namespace Toltecs
diff --git a/engines/toltecs/toltecs.h b/engines/toltecs/toltecs.h
index efa1f9d13a..b95a4f77cb 100644
--- a/engines/toltecs/toltecs.h
+++ b/engines/toltecs/toltecs.h
@@ -81,6 +81,14 @@ enum SysString {
kSysStrCount
};
+enum MenuID {
+ kMenuIdNone,
+ kMenuIdMain,
+ kMenuIdSave,
+ kMenuIdLoad,
+ kMenuIdVolumes
+};
+
class ToltecsEngine : public ::Engine {
Common::KeyState _keyPressed;
@@ -99,6 +107,7 @@ public:
uint32 getFeatures() const;
Common::Language getLanguage() const;
const Common::String& getTargetName() const { return _targetName; }
+ void syncSoundSettings();
void setupSysStrings();
void requestSavegame(int slotNum, Common::String &description);
@@ -119,14 +128,18 @@ public:
void scrollCameraLeft(int16 delta);
void scrollCameraRight(int16 delta);
void updateCamera();
-
+
+ void showMenu(MenuID menuId);
+
void talk(int16 slotIndex, int16 slotOffset);
void walk(byte *walkData);
-
- int16 findRectAtPoint(byte *rectData, int16 x, int16 y, int16 index, int16 itemSize,
+
+ int16 findRectAtPoint(byte *rectData, int16 x, int16 y, int16 index, int16 itemSize,
byte *rectDataEnd);
+ int _cfgVoicesVolume, _cfgMusicVolume, _cfgSoundFXVolume;
+ bool _cfgText, _cfgVoices;
public:
AnimationPlayer *_anim;
@@ -150,7 +163,7 @@ public:
uint _sceneResIndex;
int16 _sceneWidth, _sceneHeight;
-
+
int _counter01, _counter02;
bool _movieSceneFlag;
byte _flag01;
@@ -161,7 +174,7 @@ public:
int16 _guiHeight;
bool _doSpeech, _doText;
-
+
int16 _walkSpeedY, _walkSpeedX;
Common::KeyState _keyState;
diff --git a/engines/tony/custom.cpp b/engines/tony/custom.cpp
index f0a9197c6d..23c655e35a 100644
--- a/engines/tony/custom.cpp
+++ b/engines/tony/custom.cpp
@@ -41,7 +41,7 @@
namespace Tony {
-const char *ambianceFile[] = {
+static const char *const kAmbianceFile[] = {
"None",
"1.ADP", // Grilli.WAV
"2.ADP", // Grilli-Ovattati.WAV
@@ -52,66 +52,38 @@ const char *ambianceFile[] = {
"6.ADP" // Mare1.WAV half volume
};
-struct MusicFileEntry {
- const char *name;
- int sync;
-};
-
-const MusicFileEntry musicFiles[] = {
- {"00.ADP", 0}, {"01.ADP", 0},
- {"02.ADP", 0}, {"03.ADP", 0},
- {"04.ADP", 0}, {"05.ADP", 0},
- {"06.ADP", 0}, {"07.ADP", 0},
- {"08.ADP", 2450}, {"09.ADP", 0},
- {"10.ADP", 0}, {"11.ADP", 0},
- {"12.ADP", 0}, {"13.ADP", 0},
- {"14.ADP", 0}, {"15.ADP", 0},
- {"16.ADP", 0}, {"17.ADP", 0},
- {"18.ADP", 0}, {"19.ADP", 0},
- {"20.ADP", 0}, {"21.ADP", 0},
- {"22.ADP", 0}, {"23.ADP", 0},
- {"24.ADP", 0}, {"25.ADP", 0},
- {"26.ADP", 0}, {"27.ADP", 0},
- {"28.ADP", 1670}, {"29.ADP", 0},
- {"30.ADP", 0}, {"31.ADP", 0},
- {"32.ADP", 2900}, {"33.ADP", 0},
- {"34.ADP", 0}, {"35.ADP", 0},
- {"36.ADP", 0}, {"37.ADP", 0},
- {"38.ADP", 0}, {"39.ADP", 0},
- {"40.ADP", 0}, {"41.ADP", 1920},
- {"42.ADP", 1560}, {"43.ADP", 1920},
- {"44.ADP", 1920}, {"45.ADP", 1920},
- {"46.ADP", 1920}, {"47.ADP", 1920},
- {"48.ADP", 1920}, {"49.ADP", 1920},
- {"50.ADP", 1920}, {"51.ADP", 1920},
- {"52.ADP", 1920}, {"53.ADP", 0},
- {"54.ADP", 0}, {"55.ADP", 0},
- {"56.ADP", 0}, {"57.ADP", 0},
- {"58.ADP", 0}, {"59.ADP", 0}
+static const MusicFileEntry kMusicFiles[] = {
+ {"00.ADP", 0}, {"01.ADP", 0}, {"02.ADP", 0}, {"03.ADP", 0},
+ {"04.ADP", 0}, {"05.ADP", 0}, {"06.ADP", 0}, {"07.ADP", 0},
+ {"08.ADP", 2450}, {"09.ADP", 0}, {"10.ADP", 0}, {"11.ADP", 0},
+ {"12.ADP", 0}, {"13.ADP", 0}, {"14.ADP", 0}, {"15.ADP", 0},
+ {"16.ADP", 0}, {"17.ADP", 0}, {"18.ADP", 0}, {"19.ADP", 0},
+ {"20.ADP", 0}, {"21.ADP", 0}, {"22.ADP", 0}, {"23.ADP", 0},
+ {"24.ADP", 0}, {"25.ADP", 0}, {"26.ADP", 0}, {"27.ADP", 0},
+ {"28.ADP", 1670}, {"29.ADP", 0}, {"30.ADP", 0}, {"31.ADP", 0},
+ {"32.ADP", 2900}, {"33.ADP", 0}, {"34.ADP", 0}, {"35.ADP", 0},
+ {"36.ADP", 0}, {"37.ADP", 0}, {"38.ADP", 0}, {"39.ADP", 0},
+ {"40.ADP", 0}, {"41.ADP", 1920}, {"42.ADP", 1560}, {"43.ADP", 1920},
+ {"44.ADP", 1920}, {"45.ADP", 1920}, {"46.ADP", 1920}, {"47.ADP", 1920},
+ {"48.ADP", 1920}, {"49.ADP", 1920}, {"50.ADP", 1920}, {"51.ADP", 1920},
+ {"52.ADP", 1920}, {"53.ADP", 0}, {"54.ADP", 0}, {"55.ADP", 0},
+ {"56.ADP", 0}, {"57.ADP", 0}, {"58.ADP", 0}, {"59.ADP", 0}
};
-const char *jingleFileNames[] = {
- "S00.ADP", "S01.ADP",
- "S02.ADP", "S03.ADP",
- "S04.ADP", "S05.ADP",
- "S06.ADP", "S07.ADP",
- "S08.ADP", "S09.ADP",
- "S10.ADP", "S11.ADP",
- "S12.ADP", "S13.ADP",
- "S14.ADP", "S15.ADP",
- "S16.ADP", "S17.ADP",
- "S18.ADP"
+static const char *const kJingleFileNames[] = {
+ "S00.ADP", "S01.ADP", "S02.ADP", "S03.ADP", "S04.ADP",
+ "S05.ADP", "S06.ADP", "S07.ADP", "S08.ADP", "S09.ADP",
+ "S10.ADP", "S11.ADP", "S12.ADP", "S13.ADP", "S14.ADP",
+ "S15.ADP", "S16.ADP", "S17.ADP", "S18.ADP"
};
-
-void ReapplyChangedHotspot() {
- int i;
- for (i = 0; i < GLOBALS._curChangedHotspot; i++)
+void reapplyChangedHotspot() {
+ for (int i = 0; i < GLOBALS._curChangedHotspot; i++)
GLOBALS._loc->getItemFromCode(GLOBALS._changedHotspot[i]._dwCode)->changeHotspot(RMPoint(GLOBALS._changedHotspot[i]._nX, GLOBALS._changedHotspot[i]._nY));
}
-void SaveChangedHotspot(Common::OutSaveFile *f) {
+void saveChangedHotspot(Common::OutSaveFile *f) {
f->writeByte(GLOBALS._curChangedHotspot);
if (GLOBALS._curChangedHotspot > 0) {
for (int i = 0; i < GLOBALS._curChangedHotspot; ++i)
@@ -119,7 +91,7 @@ void SaveChangedHotspot(Common::OutSaveFile *f) {
}
}
-void LoadChangedHotspot(Common::InSaveFile *f) {
+void loadChangedHotspot(Common::InSaveFile *f) {
GLOBALS._curChangedHotspot = f->readByte();
if (GLOBALS._curChangedHotspot > 0) {
@@ -128,7 +100,6 @@ void LoadChangedHotspot(Common::InSaveFile *f) {
}
}
-
/**
* Classes required for custom functions
*
@@ -139,14 +110,14 @@ void LoadChangedHotspot(Common::InSaveFile *f) {
* AddInventory -> theEngine.AddInventory()
*/
-void MCharResetCodes() {
+void mCharResetCodes() {
for (int i = 0; i < 10; i++)
GLOBALS._mCharacter[i]._item = GLOBALS._loc->getItemFromCode(GLOBALS._mCharacter[i]._code);
for (int i = 0; i < 10; i++)
GLOBALS._character[i]._item = GLOBALS._loc->getItemFromCode(GLOBALS._character[i]._code);
}
-void CharsSaveAll(Common::OutSaveFile *f) {
+void charsSaveAll(Common::OutSaveFile *f) {
for (int i = 0; i < 10; i++) {
f->writeByte(GLOBALS._isMChar[i]);
if (GLOBALS._isMChar[i]) {
@@ -157,7 +128,7 @@ void CharsSaveAll(Common::OutSaveFile *f) {
}
}
-void CharsLoadAll(Common::InSaveFile *f) {
+void charsLoadAll(Common::InSaveFile *f) {
for (int i = 0; i < 10; i++) {
GLOBALS._isMChar[i] = f->readByte();
if (GLOBALS._isMChar[i])
@@ -167,28 +138,28 @@ void CharsLoadAll(Common::InSaveFile *f) {
}
}
-DECLARE_CUSTOM_FUNCTION(FaceToMe)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void faceToMe(CORO_PARAM, uint32, uint32, uint32, uint32) {
GLOBALS._tony->setPattern(GLOBALS._tony->PAT_STANDDOWN);
}
-DECLARE_CUSTOM_FUNCTION(BackToMe)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void backToMe(CORO_PARAM, uint32, uint32, uint32, uint32) {
GLOBALS._tony->setPattern(GLOBALS._tony->PAT_STANDUP);
}
-DECLARE_CUSTOM_FUNCTION(LeftToMe)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void leftToMe(CORO_PARAM, uint32, uint32, uint32, uint32) {
GLOBALS._tony->setPattern(GLOBALS._tony->PAT_STANDLEFT);
}
-DECLARE_CUSTOM_FUNCTION(RightToMe)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void rightToMe(CORO_PARAM, uint32, uint32, uint32, uint32) {
GLOBALS._tony->setPattern(GLOBALS._tony->PAT_STANDRIGHT);
}
-DECLARE_CUSTOM_FUNCTION(TonySetPerorate)(CORO_PARAM, uint32 bStatus, uint32, uint32, uint32) {
+void tonySetPerorate(CORO_PARAM, uint32 bStatus, uint32, uint32, uint32) {
g_vm->getEngine()->setPerorate(bStatus);
}
-DECLARE_CUSTOM_FUNCTION(MySleep)(CORO_PARAM, uint32 dwTime, uint32, uint32, uint32) {
+void mySleep(CORO_PARAM, uint32 dwTime, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
int i;
CORO_END_CONTEXT(_ctx);
@@ -201,12 +172,12 @@ DECLARE_CUSTOM_FUNCTION(MySleep)(CORO_PARAM, uint32 dwTime, uint32, uint32, uint
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(SetAlwaysDisplay)(CORO_PARAM, uint32 val, uint32, uint32, uint32) {
+void setAlwaysDisplay(CORO_PARAM, uint32 val, uint32, uint32, uint32) {
GLOBALS._bAlwaysDisplay = (val != 0);
}
-DECLARE_CUSTOM_FUNCTION(SetPointer)(CORO_PARAM, uint32 dwPointer, uint32, uint32, uint32) {
+void setPointer(CORO_PARAM, uint32 dwPointer, uint32, uint32, uint32) {
switch (dwPointer) {
case 1:
GLOBALS._pointer->setSpecialPointer(GLOBALS._pointer->PTR_ARROWUP);
@@ -230,7 +201,7 @@ DECLARE_CUSTOM_FUNCTION(SetPointer)(CORO_PARAM, uint32 dwPointer, uint32, uint32
}
}
-VoiceHeader *SearchVoiceHeader(uint32 codehi, uint32 codelo) {
+VoiceHeader *searchVoiceHeader(uint32 codehi, uint32 codelo) {
int code = (codehi << 16) | codelo;
if (g_vm->_voices.size() == 0)
@@ -245,7 +216,7 @@ VoiceHeader *SearchVoiceHeader(uint32 codehi, uint32 codelo) {
}
-DECLARE_CUSTOM_FUNCTION(SendTonyMessage)(CORO_PARAM, uint32 dwMessage, uint32 nX, uint32 nY, uint32) {
+void sendTonyMessage(CORO_PARAM, uint32 dwMessage, uint32 nX, uint32 nY, uint32) {
CORO_BEGIN_CONTEXT;
RMMessage msg;
int i;
@@ -266,7 +237,7 @@ DECLARE_CUSTOM_FUNCTION(SendTonyMessage)(CORO_PARAM, uint32 dwMessage, uint32 nX
if (!_ctx->msg.isValid())
return;
- _ctx->curVoc = SearchVoiceHeader(0, dwMessage);
+ _ctx->curVoc = searchVoiceHeader(0, dwMessage);
_ctx->voice = NULL;
if (_ctx->curVoc) {
// Is positioned within the database of entries beginning at the first
@@ -362,12 +333,12 @@ DECLARE_CUSTOM_FUNCTION(SendTonyMessage)(CORO_PARAM, uint32 dwMessage, uint32 nX
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(ChangeBoxStatus)(CORO_PARAM, uint32 nLoc, uint32 nBox, uint32 nStatus, uint32) {
+void changeBoxStatus(CORO_PARAM, uint32 nLoc, uint32 nBox, uint32 nStatus, uint32) {
GLOBALS._boxes->changeBoxStatus(nLoc, nBox, nStatus);
}
-DECLARE_CUSTOM_FUNCTION(CustLoadLocation)(CORO_PARAM, uint32 nLoc, uint32 tX, uint32 tY, uint32 bUseStartPos) {
+void custLoadLocation(CORO_PARAM, uint32 nLoc, uint32 tX, uint32 tY, uint32 bUseStartPos) {
CORO_BEGIN_CONTEXT;
uint32 h;
CORO_END_CONTEXT(_ctx);
@@ -390,7 +361,7 @@ DECLARE_CUSTOM_FUNCTION(CustLoadLocation)(CORO_PARAM, uint32 nLoc, uint32 tX, ui
}
-DECLARE_CUSTOM_FUNCTION(SendFullscreenMsgStart)(CORO_PARAM, uint32 nMsg, uint32 nFont, uint32, uint32) {
+void sendFullscreenMsgStart(CORO_PARAM, uint32 nMsg, uint32 nFont, uint32, uint32) {
CORO_BEGIN_CONTEXT;
RMMessage *msg;
RMGfxClearTask clear;
@@ -449,7 +420,7 @@ DECLARE_CUSTOM_FUNCTION(SendFullscreenMsgStart)(CORO_PARAM, uint32 nMsg, uint32
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(ClearScreen)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void clearScreen(CORO_PARAM, uint32, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
char buf[256];
RMGfxClearTask clear;
@@ -469,33 +440,33 @@ DECLARE_CUSTOM_FUNCTION(ClearScreen)(CORO_PARAM, uint32, uint32, uint32, uint32)
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(SendFullscreenMsgEnd)(CORO_PARAM, uint32 bNotEnableTony, uint32, uint32, uint32) {
+void sendFullscreenMsgEnd(CORO_PARAM, uint32 bNotEnableTony, uint32, uint32, uint32) {
g_vm->getEngine()->loadLocation(GLOBALS._fullScreenMessageLoc, RMPoint(GLOBALS._fullScreenMessagePt._x, GLOBALS._fullScreenMessagePt._y), RMPoint(-1, -1));
if (!bNotEnableTony)
GLOBALS._tony->show();
- MCharResetCodes();
- ReapplyChangedHotspot();
+ mCharResetCodes();
+ reapplyChangedHotspot();
}
-DECLARE_CUSTOM_FUNCTION(SendFullscreenMessage)(CORO_PARAM, uint32 nMsg, uint32 nFont, uint32, uint32) {
+void sendFullscreenMessage(CORO_PARAM, uint32 nMsg, uint32 nFont, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
CORO_BEGIN_CODE(_ctx);
- CORO_INVOKE_4(SendFullscreenMsgStart, nMsg, nFont, 0, 0);
- CORO_INVOKE_4(SendFullscreenMsgEnd, 0, 0, 0, 0);
+ CORO_INVOKE_4(sendFullscreenMsgStart, nMsg, nFont, 0, 0);
+ CORO_INVOKE_4(sendFullscreenMsgEnd, 0, 0, 0, 0);
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(NoBullsEye)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void noBullsEye(CORO_PARAM, uint32, uint32, uint32, uint32) {
GLOBALS._bNoBullsEye = true;
}
-DECLARE_CUSTOM_FUNCTION(CloseLocation)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void closeLocation(CORO_PARAM, uint32, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -515,7 +486,7 @@ DECLARE_CUSTOM_FUNCTION(CloseLocation)(CORO_PARAM, uint32, uint32, uint32, uint3
}
-DECLARE_CUSTOM_FUNCTION(ChangeLocation)(CORO_PARAM, uint32 nLoc, uint32 tX, uint32 tY, uint32 bUseStartPos) {
+void changeLocation(CORO_PARAM, uint32 nLoc, uint32 tX, uint32 tY, uint32 bUseStartPos) {
CORO_BEGIN_CONTEXT;
uint32 h;
CORO_END_CONTEXT(_ctx);
@@ -543,7 +514,7 @@ DECLARE_CUSTOM_FUNCTION(ChangeLocation)(CORO_PARAM, uint32 nLoc, uint32 tX, uint
if (GLOBALS._lastTappeto != GLOBALS._ambiance[nLoc]) {
GLOBALS._lastTappeto = GLOBALS._ambiance[nLoc];
if (GLOBALS._lastTappeto != 0)
- g_vm->playMusic(4, ambianceFile[GLOBALS._lastTappeto], 0, true, 2000);
+ g_vm->playMusic(4, kAmbianceFile[GLOBALS._lastTappeto], 0, true, 2000);
}
if (!GLOBALS._bNoBullsEye) {
@@ -566,51 +537,49 @@ DECLARE_CUSTOM_FUNCTION(ChangeLocation)(CORO_PARAM, uint32 nLoc, uint32 tX, uint
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(SetLocStartPosition)(CORO_PARAM, uint32 nLoc, uint32 lX, uint32 lY, uint32) {
+void setLocStartPosition(CORO_PARAM, uint32 nLoc, uint32 lX, uint32 lY, uint32) {
GLOBALS._startLocPos[nLoc].set(lX, lY);
}
-DECLARE_CUSTOM_FUNCTION(SaveTonyPosition)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void saveTonyPosition(CORO_PARAM, uint32, uint32, uint32, uint32) {
GLOBALS._saveTonyPos = GLOBALS._tony->position();
GLOBALS._saveTonyLoc = GLOBALS._loc->TEMPGetNumLoc();
}
-DECLARE_CUSTOM_FUNCTION(RestoreTonyPosition)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void restoreTonyPosition(CORO_PARAM, uint32, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
CORO_BEGIN_CODE(_ctx);
- CORO_INVOKE_4(ChangeLocation, GLOBALS._saveTonyLoc, GLOBALS._saveTonyPos._x, GLOBALS._saveTonyPos._y, 0);
+ CORO_INVOKE_4(changeLocation, GLOBALS._saveTonyLoc, GLOBALS._saveTonyPos._x, GLOBALS._saveTonyPos._y, 0);
- MCharResetCodes();
+ mCharResetCodes();
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(DisableInput)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void disableInput(CORO_PARAM, uint32, uint32, uint32, uint32) {
g_vm->getEngine()->disableInput();
}
-DECLARE_CUSTOM_FUNCTION(EnableInput)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void enableInput(CORO_PARAM, uint32, uint32, uint32, uint32) {
g_vm->getEngine()->enableInput();
}
-DECLARE_CUSTOM_FUNCTION(StopTony)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void stopTony(CORO_PARAM, uint32, uint32, uint32, uint32) {
GLOBALS._tony->stopNoAction(coroParam);
}
-DECLARE_CUSTOM_FUNCTION(CustEnableGUI)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void custEnableGUI(CORO_PARAM, uint32, uint32, uint32, uint32) {
GLOBALS.EnableGUI();
}
-DECLARE_CUSTOM_FUNCTION(CustDisableGUI)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void custDisableGUI(CORO_PARAM, uint32, uint32, uint32, uint32) {
GLOBALS.DisableGUI();
}
-
-
-void TonyGenericTake1(CORO_PARAM, uint32 nDirection) {
+void tonyGenericTake1(CORO_PARAM, uint32 nDirection) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -624,7 +593,7 @@ void TonyGenericTake1(CORO_PARAM, uint32 nDirection) {
CORO_END_CODE;
}
-void TonyGenericTake2(CORO_PARAM, uint32 nDirection) {
+void tonyGenericTake2(CORO_PARAM, uint32 nDirection) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -640,7 +609,7 @@ void TonyGenericTake2(CORO_PARAM, uint32 nDirection) {
CORO_END_CODE;
}
-void TonyGenericPut1(CORO_PARAM, uint32 nDirection) {
+void tonyGenericPut1(CORO_PARAM, uint32 nDirection) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -654,7 +623,7 @@ void TonyGenericPut1(CORO_PARAM, uint32 nDirection) {
CORO_END_CODE;
}
-void TonyGenericPut2(CORO_PARAM, uint32 nDirection) {
+void tonyGenericPut2(CORO_PARAM, uint32 nDirection) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -671,71 +640,65 @@ void TonyGenericPut2(CORO_PARAM, uint32 nDirection) {
}
-DECLARE_CUSTOM_FUNCTION(TonyTakeUp1)(CORO_PARAM, uint32, uint32, uint32, uint32) {
- TonyGenericTake1(coroParam, 0);
+void tonyTakeUp1(CORO_PARAM, uint32, uint32, uint32, uint32) {
+ tonyGenericTake1(coroParam, 0);
}
-DECLARE_CUSTOM_FUNCTION(TonyTakeMid1)(CORO_PARAM, uint32, uint32, uint32, uint32) {
- TonyGenericTake1(coroParam, 1);
+void tonyTakeMid1(CORO_PARAM, uint32, uint32, uint32, uint32) {
+ tonyGenericTake1(coroParam, 1);
}
-DECLARE_CUSTOM_FUNCTION(TonyTakeDown1)(CORO_PARAM, uint32, uint32, uint32, uint32) {
- TonyGenericTake1(coroParam, 2);
+void tonyTakeDown1(CORO_PARAM, uint32, uint32, uint32, uint32) {
+ tonyGenericTake1(coroParam, 2);
}
-
-
-DECLARE_CUSTOM_FUNCTION(TonyTakeUp2)(CORO_PARAM, uint32, uint32, uint32, uint32) {
- TonyGenericTake2(coroParam, 0);
+void tonyTakeUp2(CORO_PARAM, uint32, uint32, uint32, uint32) {
+ tonyGenericTake2(coroParam, 0);
}
-DECLARE_CUSTOM_FUNCTION(TonyTakeMid2)(CORO_PARAM, uint32, uint32, uint32, uint32) {
- TonyGenericTake2(coroParam, 1);
+void tonyTakeMid2(CORO_PARAM, uint32, uint32, uint32, uint32) {
+ tonyGenericTake2(coroParam, 1);
}
-DECLARE_CUSTOM_FUNCTION(TonyTakeDown2)(CORO_PARAM, uint32, uint32, uint32, uint32) {
- TonyGenericTake2(coroParam, 2);
+void tonyTakeDown2(CORO_PARAM, uint32, uint32, uint32, uint32) {
+ tonyGenericTake2(coroParam, 2);
}
-
-
-DECLARE_CUSTOM_FUNCTION(TonyPutUp1)(CORO_PARAM, uint32, uint32, uint32, uint32) {
- TonyGenericPut1(coroParam, 0);
+void tonyPutUp1(CORO_PARAM, uint32, uint32, uint32, uint32) {
+ tonyGenericPut1(coroParam, 0);
}
-
-DECLARE_CUSTOM_FUNCTION(TonyPutMid1)(CORO_PARAM, uint32, uint32, uint32, uint32) {
- TonyGenericPut1(coroParam, 1);
+void tonyPutMid1(CORO_PARAM, uint32, uint32, uint32, uint32) {
+ tonyGenericPut1(coroParam, 1);
}
-DECLARE_CUSTOM_FUNCTION(TonyPutDown1)(CORO_PARAM, uint32, uint32, uint32, uint32) {
- TonyGenericPut1(coroParam, 2);
+void tonyPutDown1(CORO_PARAM, uint32, uint32, uint32, uint32) {
+ tonyGenericPut1(coroParam, 2);
}
-DECLARE_CUSTOM_FUNCTION(TonyPutUp2)(CORO_PARAM, uint32, uint32, uint32, uint32) {
- TonyGenericPut2(coroParam, 0);
+void tonyPutUp2(CORO_PARAM, uint32, uint32, uint32, uint32) {
+ tonyGenericPut2(coroParam, 0);
}
-
-DECLARE_CUSTOM_FUNCTION(TonyPutMid2)(CORO_PARAM, uint32, uint32, uint32, uint32) {
- TonyGenericPut2(coroParam, 1);
+void tonyPutMid2(CORO_PARAM, uint32, uint32, uint32, uint32) {
+ tonyGenericPut2(coroParam, 1);
}
-DECLARE_CUSTOM_FUNCTION(TonyPutDown2)(CORO_PARAM, uint32, uint32, uint32, uint32) {
- TonyGenericPut2(coroParam, 2);
+void tonyPutDown2(CORO_PARAM, uint32, uint32, uint32, uint32) {
+ tonyGenericPut2(coroParam, 2);
}
-DECLARE_CUSTOM_FUNCTION(TonyOnTheFloor)(CORO_PARAM, uint32 dwParte, uint32, uint32, uint32) {
+void tonyOnTheFloor(CORO_PARAM, uint32 dwParte, uint32, uint32, uint32) {
if (dwParte == 0)
GLOBALS._tony->setPattern(GLOBALS._tony->PAT_ONTHEFLOORLEFT);
else
GLOBALS._tony->setPattern(GLOBALS._tony->PAT_ONTHEFLOORRIGHT);
}
-DECLARE_CUSTOM_FUNCTION(TonyGetUp)(CORO_PARAM, uint32 dwParte, uint32, uint32, uint32) {
+void tonyGetUp(CORO_PARAM, uint32 dwParte, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -752,11 +715,11 @@ DECLARE_CUSTOM_FUNCTION(TonyGetUp)(CORO_PARAM, uint32 dwParte, uint32, uint32, u
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(TonyShepherdess)(CORO_PARAM, uint32 bIsPast, uint32, uint32, uint32) {
+void tonyShepherdess(CORO_PARAM, uint32 bIsPast, uint32, uint32, uint32) {
GLOBALS._tony->setShepherdess(bIsPast);
}
-DECLARE_CUSTOM_FUNCTION(TonyWhistle)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void tonyWhistle(CORO_PARAM, uint32, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -771,98 +734,97 @@ DECLARE_CUSTOM_FUNCTION(TonyWhistle)(CORO_PARAM, uint32, uint32, uint32, uint32)
CORO_END_CODE;
}
-
-void TonySetNumTexts(uint32 dwText) {
+void tonySetNumTexts(uint32 dwText) {
GLOBALS._dwTonyNumTexts = dwText;
GLOBALS._bTonyInTexts = false;
}
-DECLARE_CUSTOM_FUNCTION(TonyLaugh)(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
- TonySetNumTexts(dwText);
+void tonyLaugh(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
+ tonySetNumTexts(dwText);
GLOBALS._nTonyNextTalkType = GLOBALS._tony->TALK_LAUGH;
}
-DECLARE_CUSTOM_FUNCTION(TonyGiggle)(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
- TonySetNumTexts(dwText);
+void tonyGiggle(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
+ tonySetNumTexts(dwText);
GLOBALS._nTonyNextTalkType = GLOBALS._tony->TALK_LAUGH2;
}
-DECLARE_CUSTOM_FUNCTION(TonyHips)(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
- TonySetNumTexts(dwText);
+void tonyHips(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
+ tonySetNumTexts(dwText);
GLOBALS._nTonyNextTalkType = GLOBALS._tony->TALK_HIPS;
}
-DECLARE_CUSTOM_FUNCTION(TonySing)(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
- TonySetNumTexts(dwText);
+void tonySing(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
+ tonySetNumTexts(dwText);
GLOBALS._nTonyNextTalkType = GLOBALS._tony->TALK_SING;
}
-DECLARE_CUSTOM_FUNCTION(TonyIndicate)(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
- TonySetNumTexts(dwText);
+void tonyIndicate(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
+ tonySetNumTexts(dwText);
GLOBALS._nTonyNextTalkType = GLOBALS._tony->TALK_INDICATE;
}
-DECLARE_CUSTOM_FUNCTION(TonyScaredWithHands)(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
- TonySetNumTexts(dwText);
+void tonyScaredWithHands(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
+ tonySetNumTexts(dwText);
GLOBALS._nTonyNextTalkType = GLOBALS._tony->TALK_SCARED;
}
-DECLARE_CUSTOM_FUNCTION(TonyScaredWithoutHands)(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
- TonySetNumTexts(dwText);
+void tonyScaredWithoutHands(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
+ tonySetNumTexts(dwText);
GLOBALS._nTonyNextTalkType = GLOBALS._tony->TALK_SCARED2;
}
-DECLARE_CUSTOM_FUNCTION(TonyWithHammer)(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
- TonySetNumTexts(dwText);
+void tonyWithHammer(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
+ tonySetNumTexts(dwText);
GLOBALS._nTonyNextTalkType = GLOBALS._tony->TALK_WITHHAMMER;
GLOBALS._tony->setPattern(GLOBALS._tony->PAT_WITHHAMMER);
}
-DECLARE_CUSTOM_FUNCTION(TonyWithGlasses)(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
- TonySetNumTexts(dwText);
+void tonyWithGlasses(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
+ tonySetNumTexts(dwText);
GLOBALS._nTonyNextTalkType = GLOBALS._tony->TALK_WITHGLASSES;
GLOBALS._tony->setPattern(GLOBALS._tony->PAT_WITHGLASSES);
}
-DECLARE_CUSTOM_FUNCTION(TonyWithWorm)(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
- TonySetNumTexts(dwText);
+void tonyWithWorm(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
+ tonySetNumTexts(dwText);
GLOBALS._nTonyNextTalkType = GLOBALS._tony->TALK_WITHWORM;
GLOBALS._tony->setPattern(GLOBALS._tony->PAT_WITHWORM);
}
-DECLARE_CUSTOM_FUNCTION(TonyWithRope)(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
- TonySetNumTexts(dwText);
+void tonyWithRope(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
+ tonySetNumTexts(dwText);
GLOBALS._nTonyNextTalkType = GLOBALS._tony->TALK_WITHROPE;
GLOBALS._tony->setPattern(GLOBALS._tony->PAT_WITHROPE);
}
-DECLARE_CUSTOM_FUNCTION(TonyWithSecretary)(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
- TonySetNumTexts(dwText);
+void tonyWithSecretary(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
+ tonySetNumTexts(dwText);
GLOBALS._nTonyNextTalkType = GLOBALS._tony->TALK_WITHSECRETARY;
GLOBALS._tony->setPattern(GLOBALS._tony->PAT_WITHSECRETARY);
}
-DECLARE_CUSTOM_FUNCTION(TonyWithRabbitANIM)(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
- TonySetNumTexts(dwText);
+void tonyWithRabbitANIM(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
+ tonySetNumTexts(dwText);
GLOBALS._nTonyNextTalkType = GLOBALS._tony->TALK_WITHRABBIT;
}
-DECLARE_CUSTOM_FUNCTION(TonyWithRecipeANIM)(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
- TonySetNumTexts(dwText);
+void tonyWithRecipeANIM(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
+ tonySetNumTexts(dwText);
GLOBALS._nTonyNextTalkType = GLOBALS._tony->TALK_WITHRECIPE;
}
-DECLARE_CUSTOM_FUNCTION(TonyWithCardsANIM)(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
- TonySetNumTexts(dwText);
+void tonyWithCardsANIM(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
+ tonySetNumTexts(dwText);
GLOBALS._nTonyNextTalkType = GLOBALS._tony->TALK_WITHCARDS;
}
-DECLARE_CUSTOM_FUNCTION(TonyWithSnowmanANIM)(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
- TonySetNumTexts(dwText);
+void tonyWithSnowmanANIM(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
+ tonySetNumTexts(dwText);
GLOBALS._nTonyNextTalkType = GLOBALS._tony->TALK_WITHSNOWMAN;
}
-DECLARE_CUSTOM_FUNCTION(TonyWithSnowmanStart)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void tonyWithSnowmanStart(CORO_PARAM, uint32, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -875,7 +837,7 @@ DECLARE_CUSTOM_FUNCTION(TonyWithSnowmanStart)(CORO_PARAM, uint32, uint32, uint32
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(TonyWithSnowmanEnd)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void tonyWithSnowmanEnd(CORO_PARAM, uint32, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -888,7 +850,7 @@ DECLARE_CUSTOM_FUNCTION(TonyWithSnowmanEnd)(CORO_PARAM, uint32, uint32, uint32,
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(TonyWithRabbitStart)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void tonyWithRabbitStart(CORO_PARAM, uint32, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -901,7 +863,7 @@ DECLARE_CUSTOM_FUNCTION(TonyWithRabbitStart)(CORO_PARAM, uint32, uint32, uint32,
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(TonyWithRabbitEnd)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void tonyWithRabbitEnd(CORO_PARAM, uint32, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -914,7 +876,7 @@ DECLARE_CUSTOM_FUNCTION(TonyWithRabbitEnd)(CORO_PARAM, uint32, uint32, uint32, u
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(TonyWithRecipeStart)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void tonyWithRecipeStart(CORO_PARAM, uint32, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -927,7 +889,7 @@ DECLARE_CUSTOM_FUNCTION(TonyWithRecipeStart)(CORO_PARAM, uint32, uint32, uint32,
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(TonyWithRecipeEnd)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void tonyWithRecipeEnd(CORO_PARAM, uint32, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -940,7 +902,7 @@ DECLARE_CUSTOM_FUNCTION(TonyWithRecipeEnd)(CORO_PARAM, uint32, uint32, uint32, u
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(TonyWithCardsStart)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void tonyWithCardsStart(CORO_PARAM, uint32, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -953,7 +915,7 @@ DECLARE_CUSTOM_FUNCTION(TonyWithCardsStart)(CORO_PARAM, uint32, uint32, uint32,
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(TonyWithCardsEnd)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void tonyWithCardsEnd(CORO_PARAM, uint32, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -966,7 +928,7 @@ DECLARE_CUSTOM_FUNCTION(TonyWithCardsEnd)(CORO_PARAM, uint32, uint32, uint32, ui
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(TonyWithNotebookStart)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void tonyWithNotebookStart(CORO_PARAM, uint32, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -979,7 +941,7 @@ DECLARE_CUSTOM_FUNCTION(TonyWithNotebookStart)(CORO_PARAM, uint32, uint32, uint3
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(TonyWithNotebookEnd)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void tonyWithNotebookEnd(CORO_PARAM, uint32, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -992,7 +954,7 @@ DECLARE_CUSTOM_FUNCTION(TonyWithNotebookEnd)(CORO_PARAM, uint32, uint32, uint32,
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(TonyWithMegaphoneStart)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void tonyWithMegaphoneStart(CORO_PARAM, uint32, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -1005,7 +967,7 @@ DECLARE_CUSTOM_FUNCTION(TonyWithMegaphoneStart)(CORO_PARAM, uint32, uint32, uint
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(TonyWithMegaphoneEnd)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void tonyWithMegaphoneEnd(CORO_PARAM, uint32, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -1018,7 +980,7 @@ DECLARE_CUSTOM_FUNCTION(TonyWithMegaphoneEnd)(CORO_PARAM, uint32, uint32, uint32
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(TonyWithBeardStart)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void tonyWithBeardStart(CORO_PARAM, uint32, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -1031,7 +993,7 @@ DECLARE_CUSTOM_FUNCTION(TonyWithBeardStart)(CORO_PARAM, uint32, uint32, uint32,
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(TonyWithBeardEnd)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void tonyWithBeardEnd(CORO_PARAM, uint32, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -1044,7 +1006,7 @@ DECLARE_CUSTOM_FUNCTION(TonyWithBeardEnd)(CORO_PARAM, uint32, uint32, uint32, ui
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(TonyScaredStart)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void tonyScaredStart(CORO_PARAM, uint32, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -1057,7 +1019,7 @@ DECLARE_CUSTOM_FUNCTION(TonyScaredStart)(CORO_PARAM, uint32, uint32, uint32, uin
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(TonyScaredEnd)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void tonyScaredEnd(CORO_PARAM, uint32, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -1071,12 +1033,12 @@ DECLARE_CUSTOM_FUNCTION(TonyScaredEnd)(CORO_PARAM, uint32, uint32, uint32, uint3
}
-DECLARE_CUSTOM_FUNCTION(TonyDisgusted)(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
- TonySetNumTexts(dwText);
+void tonyDisgusted(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
+ tonySetNumTexts(dwText);
GLOBALS._nTonyNextTalkType = GLOBALS._tony->TALK_DISGUSTED;
}
-DECLARE_CUSTOM_FUNCTION(TonySniffLeft)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void tonySniffLeft(CORO_PARAM, uint32, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -1084,12 +1046,12 @@ DECLARE_CUSTOM_FUNCTION(TonySniffLeft)(CORO_PARAM, uint32, uint32, uint32, uint3
GLOBALS._tony->setPattern(GLOBALS._tony->PAT_SNIFF_LEFT);
CORO_INVOKE_0(GLOBALS._tony->waitForEndPattern);
- CORO_INVOKE_4(LeftToMe, 0, 0, 0, 0);
+ CORO_INVOKE_4(leftToMe, 0, 0, 0, 0);
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(TonySniffRight)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void tonySniffRight(CORO_PARAM, uint32, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -1097,17 +1059,17 @@ DECLARE_CUSTOM_FUNCTION(TonySniffRight)(CORO_PARAM, uint32, uint32, uint32, uint
GLOBALS._tony->setPattern(GLOBALS._tony->PAT_SNIFF_RIGHT);
CORO_INVOKE_0(GLOBALS._tony->waitForEndPattern);
- CORO_INVOKE_4(RightToMe, 0, 0, 0, 0);
+ CORO_INVOKE_4(rightToMe, 0, 0, 0, 0);
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(TonySarcastic)(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
- TonySetNumTexts(dwText);
+void tonySarcastic(CORO_PARAM, uint32 dwText, uint32, uint32, uint32) {
+ tonySetNumTexts(dwText);
GLOBALS._nTonyNextTalkType = GLOBALS._tony->TALK_SARCASTIC;
}
-DECLARE_CUSTOM_FUNCTION(TonyMacbeth)(CORO_PARAM, uint32 nPos, uint32, uint32, uint32) {
+void tonyMacbeth(CORO_PARAM, uint32 nPos, uint32, uint32, uint32) {
switch (nPos) {
case 1:
GLOBALS._nTonyNextTalkType = GLOBALS._tony->TALK_MACBETH1;
@@ -1140,15 +1102,15 @@ DECLARE_CUSTOM_FUNCTION(TonyMacbeth)(CORO_PARAM, uint32 nPos, uint32, uint32, ui
}
-DECLARE_CUSTOM_FUNCTION(EnableTony)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void enableTony(CORO_PARAM, uint32, uint32, uint32, uint32) {
GLOBALS._tony->show();
}
-DECLARE_CUSTOM_FUNCTION(DisableTony)(CORO_PARAM, uint32 bShowShadow, uint32, uint32, uint32) {
+void disableTony(CORO_PARAM, uint32 bShowShadow, uint32, uint32, uint32) {
GLOBALS._tony->hide(bShowShadow);
}
-DECLARE_CUSTOM_FUNCTION(WaitForPatternEnd)(CORO_PARAM, uint32 nItem, uint32, uint32, uint32) {
+void waitForPatternEnd(CORO_PARAM, uint32 nItem, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
RMItem *item;
CORO_END_CONTEXT(_ctx);
@@ -1164,11 +1126,11 @@ DECLARE_CUSTOM_FUNCTION(WaitForPatternEnd)(CORO_PARAM, uint32 nItem, uint32, uin
}
-DECLARE_CUSTOM_FUNCTION(SetTonyPosition)(CORO_PARAM, uint32 nX, uint32 nY, uint32 nLoc, uint32) {
+void setTonyPosition(CORO_PARAM, uint32 nX, uint32 nY, uint32 nLoc, uint32) {
GLOBALS._tony->setPosition(RMPoint(nX, nY), nLoc);
}
-DECLARE_CUSTOM_FUNCTION(MoveTonyAndWait)(CORO_PARAM, uint32 nX, uint32 nY, uint32, uint32) {
+void moveTonyAndWait(CORO_PARAM, uint32 nX, uint32 nY, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -1187,11 +1149,11 @@ DECLARE_CUSTOM_FUNCTION(MoveTonyAndWait)(CORO_PARAM, uint32 nX, uint32 nY, uint3
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(MoveTony)(CORO_PARAM, uint32 nX, uint32 nY, uint32, uint32) {
+void moveTony(CORO_PARAM, uint32 nX, uint32 nY, uint32, uint32) {
GLOBALS._tony->move(coroParam, RMPoint(nX, nY));
}
-DECLARE_CUSTOM_FUNCTION(ScrollLocation)(CORO_PARAM, uint32 nX, uint32 nY, uint32 sX, uint32 sY) {
+void scrollLocation(CORO_PARAM, uint32 nX, uint32 nY, uint32 sX, uint32 sY) {
CORO_BEGIN_CONTEXT;
int lx, ly;
RMPoint pt;
@@ -1239,7 +1201,7 @@ DECLARE_CUSTOM_FUNCTION(ScrollLocation)(CORO_PARAM, uint32 nX, uint32 nY, uint32
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(SyncScrollLocation)(CORO_PARAM, uint32 nX, uint32 nY, uint32 sX, uint32 sY) {
+void syncScrollLocation(CORO_PARAM, uint32 nX, uint32 nY, uint32 sX, uint32 sY) {
CORO_BEGIN_CONTEXT;
int lx, ly;
RMPoint pt, startpt;
@@ -1321,7 +1283,7 @@ DECLARE_CUSTOM_FUNCTION(SyncScrollLocation)(CORO_PARAM, uint32 nX, uint32 nY, ui
}
-DECLARE_CUSTOM_FUNCTION(ChangeHotspot)(CORO_PARAM, uint32 dwCode, uint32 nX, uint32 nY, uint32) {
+void changeHotspot(CORO_PARAM, uint32 dwCode, uint32 nX, uint32 nY, uint32) {
int i;
for (i = 0; i < GLOBALS._curChangedHotspot; i++) {
@@ -1343,15 +1305,15 @@ DECLARE_CUSTOM_FUNCTION(ChangeHotspot)(CORO_PARAM, uint32 dwCode, uint32 nX, uin
}
-DECLARE_CUSTOM_FUNCTION(AutoSave)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void autoSave(CORO_PARAM, uint32, uint32, uint32, uint32) {
g_vm->autoSave(coroParam);
}
-DECLARE_CUSTOM_FUNCTION(AbortGame)(CORO_PARAM, uint32, uint32, uint32, uint32) {
- g_vm->abortGame();
+void abortGame(CORO_PARAM, uint32, uint32, uint32, uint32) {
+ error("script called abortGame");
}
-DECLARE_CUSTOM_FUNCTION(ShakeScreen)(CORO_PARAM, uint32 nScosse, uint32, uint32, uint32) {
+void shakeScreen(CORO_PARAM, uint32 nScosse, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
uint32 i;
uint32 curTime;
@@ -1389,7 +1351,7 @@ DECLARE_CUSTOM_FUNCTION(ShakeScreen)(CORO_PARAM, uint32 nScosse, uint32, uint32,
* Characters
*/
-DECLARE_CUSTOM_FUNCTION(CharSetCode)(CORO_PARAM, uint32 nChar, uint32 nCode, uint32, uint32) {
+void charSetCode(CORO_PARAM, uint32 nChar, uint32 nCode, uint32, uint32) {
assert(nChar < 16);
GLOBALS._character[nChar]._code = nCode;
GLOBALS._character[nChar]._item = GLOBALS._loc->getItemFromCode(nCode);
@@ -1404,26 +1366,26 @@ DECLARE_CUSTOM_FUNCTION(CharSetCode)(CORO_PARAM, uint32 nChar, uint32 nCode, uin
GLOBALS._isMChar[nChar] = false;
}
-DECLARE_CUSTOM_FUNCTION(CharSetColor)(CORO_PARAM, uint32 nChar, uint32 r, uint32 g, uint32 b) {
+void charSetColor(CORO_PARAM, uint32 nChar, uint32 r, uint32 g, uint32 b) {
assert(nChar < 16);
GLOBALS._character[nChar]._r = r;
GLOBALS._character[nChar]._g = g;
GLOBALS._character[nChar]._b = b;
}
-DECLARE_CUSTOM_FUNCTION(CharSetTalkPattern)(CORO_PARAM, uint32 nChar, uint32 tp, uint32 sp, uint32) {
+void charSetTalkPattern(CORO_PARAM, uint32 nChar, uint32 tp, uint32 sp, uint32) {
assert(nChar < 16);
GLOBALS._character[nChar]._talkPattern = tp;
GLOBALS._character[nChar]._standPattern = sp;
}
-DECLARE_CUSTOM_FUNCTION(CharSetStartEndTalkPattern)(CORO_PARAM, uint32 nChar, uint32 sp, uint32 ep, uint32) {
+void charSetStartEndTalkPattern(CORO_PARAM, uint32 nChar, uint32 sp, uint32 ep, uint32) {
assert(nChar < 16);
GLOBALS._character[nChar]._startTalkPattern = sp;
GLOBALS._character[nChar]._endTalkPattern = ep;
}
-DECLARE_CUSTOM_FUNCTION(CharSendMessage)(CORO_PARAM, uint32 nChar, uint32 dwMessage, uint32 bIsBack, uint32) {
+void charSendMessage(CORO_PARAM, uint32 nChar, uint32 dwMessage, uint32 bIsBack, uint32) {
CORO_BEGIN_CONTEXT;
RMMessage *msg;
int i;
@@ -1450,7 +1412,7 @@ DECLARE_CUSTOM_FUNCTION(CharSendMessage)(CORO_PARAM, uint32 nChar, uint32 dwMess
GLOBALS._character[nChar]._item->setPattern(GLOBALS._character[nChar]._talkPattern);
- _ctx->curVoc = SearchVoiceHeader(0, dwMessage);
+ _ctx->curVoc = searchVoiceHeader(0, dwMessage);
_ctx->voice = NULL;
if (_ctx->curVoc) {
// Position within the database of entries, beginning at the first
@@ -1530,15 +1492,15 @@ DECLARE_CUSTOM_FUNCTION(CharSendMessage)(CORO_PARAM, uint32 nChar, uint32 dwMess
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(AddInventory)(CORO_PARAM, uint32 dwCode, uint32, uint32, uint32) {
+void addInventory(CORO_PARAM, uint32 dwCode, uint32, uint32, uint32) {
GLOBALS._inventory->addItem(dwCode);
}
-DECLARE_CUSTOM_FUNCTION(RemoveInventory)(CORO_PARAM, uint32 dwCode, uint32, uint32, uint32) {
+void removeInventory(CORO_PARAM, uint32 dwCode, uint32, uint32, uint32) {
GLOBALS._inventory->removeItem(dwCode);
}
-DECLARE_CUSTOM_FUNCTION(ChangeInventoryStatus)(CORO_PARAM, uint32 dwCode, uint32 dwStatus, uint32, uint32) {
+void changeInventoryStatus(CORO_PARAM, uint32 dwCode, uint32 dwStatus, uint32, uint32) {
GLOBALS._inventory->changeItemStatus(dwCode, dwStatus);
}
@@ -1547,7 +1509,7 @@ DECLARE_CUSTOM_FUNCTION(ChangeInventoryStatus)(CORO_PARAM, uint32 dwCode, uint32
* Master Characters
*/
-DECLARE_CUSTOM_FUNCTION(MCharSetCode)(CORO_PARAM, uint32 nChar, uint32 nCode, uint32, uint32) {
+void mCharSetCode(CORO_PARAM, uint32 nChar, uint32 nCode, uint32, uint32) {
assert(nChar < 10);
GLOBALS._mCharacter[nChar]._code = nCode;
if (nCode == 0)
@@ -1569,56 +1531,52 @@ DECLARE_CUSTOM_FUNCTION(MCharSetCode)(CORO_PARAM, uint32 nChar, uint32 nCode, ui
GLOBALS._isMChar[nChar] = true;
}
-DECLARE_CUSTOM_FUNCTION(MCharResetCode)(CORO_PARAM, uint32 nChar, uint32, uint32, uint32) {
+void mCharResetCode(CORO_PARAM, uint32 nChar, uint32, uint32, uint32) {
GLOBALS._mCharacter[nChar]._item = GLOBALS._loc->getItemFromCode(GLOBALS._mCharacter[nChar]._code);
}
-DECLARE_CUSTOM_FUNCTION(MCharSetPosition)(CORO_PARAM, uint32 nChar, uint32 nX, uint32 nY, uint32) {
+void mCharSetPosition(CORO_PARAM, uint32 nChar, uint32 nX, uint32 nY, uint32) {
assert(nChar < 10);
GLOBALS._mCharacter[nChar]._x = nX;
GLOBALS._mCharacter[nChar]._y = nY;
}
-
-DECLARE_CUSTOM_FUNCTION(MCharSetColor)(CORO_PARAM, uint32 nChar, uint32 r, uint32 g, uint32 b) {
+void mCharSetColor(CORO_PARAM, uint32 nChar, uint32 r, uint32 g, uint32 b) {
assert(nChar < 10);
GLOBALS._mCharacter[nChar]._r = r;
GLOBALS._mCharacter[nChar]._g = g;
GLOBALS._mCharacter[nChar]._b = b;
}
-
-DECLARE_CUSTOM_FUNCTION(MCharSetNumTalksInGroup)(CORO_PARAM, uint32 nChar, uint32 nGroup, uint32 nTalks, uint32) {
+void mCharSetNumTalksInGroup(CORO_PARAM, uint32 nChar, uint32 nGroup, uint32 nTalks, uint32) {
assert(nChar < 10);
assert(nGroup < 10);
GLOBALS._mCharacter[nChar]._numTalks[nGroup] = nTalks;
}
-
-DECLARE_CUSTOM_FUNCTION(MCharSetCurrentGroup)(CORO_PARAM, uint32 nChar, uint32 nGroup, uint32, uint32) {
+void mCharSetCurrentGroup(CORO_PARAM, uint32 nChar, uint32 nGroup, uint32, uint32) {
assert(nChar < 10);
assert(nGroup < 10);
GLOBALS._mCharacter[nChar]._curGroup = nGroup;
}
-DECLARE_CUSTOM_FUNCTION(MCharSetNumTexts)(CORO_PARAM, uint32 nChar, uint32 nTexts, uint32, uint32) {
+void mCharSetNumTexts(CORO_PARAM, uint32 nChar, uint32 nTexts, uint32, uint32) {
assert(nChar < 10);
GLOBALS._mCharacter[nChar]._numTexts = nTexts - 1;
GLOBALS._mCharacter[nChar]._bInTexts = false;
}
-DECLARE_CUSTOM_FUNCTION(MCharSetAlwaysBack)(CORO_PARAM, uint32 nChar, uint32 bAlwaysBack, uint32, uint32) {
+void mCharSetAlwaysBack(CORO_PARAM, uint32 nChar, uint32 bAlwaysBack, uint32, uint32) {
assert(nChar < 10);
GLOBALS._mCharacter[nChar]._bAlwaysBack = bAlwaysBack;
}
-
-DECLARE_CUSTOM_FUNCTION(MCharSendMessage)(CORO_PARAM, uint32 nChar, uint32 dwMessage, uint32 bIsBack, uint32 nFont) {
+void mCharSendMessage(CORO_PARAM, uint32 nChar, uint32 dwMessage, uint32 bIsBack, uint32 nFont) {
CORO_BEGIN_CONTEXT;
RMMessage *msg;
int i;
@@ -1658,11 +1616,10 @@ DECLARE_CUSTOM_FUNCTION(MCharSendMessage)(CORO_PARAM, uint32 nChar, uint32 dwMes
}
}
- _ctx->curVoc = SearchVoiceHeader(0, dwMessage);
+ _ctx->curVoc = searchVoiceHeader(0, dwMessage);
_ctx->voice = NULL;
if (_ctx->curVoc) {
// Position within the database of entries, beginning at the first
- // fseek(g_vm->m_vdbFP, curVoc->offset, SEEK_SET);
g_vm->_vdbFP.seek(_ctx->curVoc->_offset);
_ctx->curOffset = _ctx->curVoc->_offset;
}
@@ -1744,9 +1701,7 @@ DECLARE_CUSTOM_FUNCTION(MCharSendMessage)(CORO_PARAM, uint32 nChar, uint32 dwMes
* Dialogs
*/
-int g_curDialog;
-
-DECLARE_CUSTOM_FUNCTION(SendDialogMessage)(CORO_PARAM, uint32 nPers, uint32 nMsg, uint32, uint32) {
+void sendDialogMessage(CORO_PARAM, uint32 nPers, uint32 nMsg, uint32, uint32) {
CORO_BEGIN_CONTEXT;
char *string;
RMTextDialog *text;
@@ -1766,7 +1721,7 @@ DECLARE_CUSTOM_FUNCTION(SendDialogMessage)(CORO_PARAM, uint32 nPers, uint32 nMsg
if (nPers != 0 && GLOBALS._isMChar[nPers] && GLOBALS._mCharacter[nPers]._bAlwaysBack)
_ctx->bIsBack = true;
- _ctx->curVoc = SearchVoiceHeader(g_curDialog, nMsg);
+ _ctx->curVoc = searchVoiceHeader(GLOBALS._curDialog, nMsg);
_ctx->voice = NULL;
if (_ctx->curVoc) {
@@ -1927,7 +1882,7 @@ DECLARE_CUSTOM_FUNCTION(SendDialogMessage)(CORO_PARAM, uint32 nPers, uint32 nMsg
// @@@@ This cannot be skipped!!!!!!!!!!!!!!!!!!!
-DECLARE_CUSTOM_FUNCTION(StartDialog)(CORO_PARAM, uint32 nDialog, uint32 nStartGroup, uint32, uint32) {
+void startDialog(CORO_PARAM, uint32 nDialog, uint32 nStartGroup, uint32, uint32) {
CORO_BEGIN_CONTEXT;
uint32 nChoice;
uint32 *sl;
@@ -1939,7 +1894,7 @@ DECLARE_CUSTOM_FUNCTION(StartDialog)(CORO_PARAM, uint32 nDialog, uint32 nStartGr
CORO_BEGIN_CODE(_ctx);
- g_curDialog = nDialog;
+ GLOBALS._curDialog = nDialog;
// Call MPAL to start the dialog
mpalQueryDoDialog(nDialog, nStartGroup);
@@ -2010,7 +1965,7 @@ DECLARE_CUSTOM_FUNCTION(StartDialog)(CORO_PARAM, uint32 nDialog, uint32 nStartGr
* Sync between idle and mpal
*/
-DECLARE_CUSTOM_FUNCTION(TakeOwnership)(CORO_PARAM, uint32 num, uint32, uint32, uint32) {
+void takeOwnership(CORO_PARAM, uint32 num, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -2028,14 +1983,16 @@ DECLARE_CUSTOM_FUNCTION(TakeOwnership)(CORO_PARAM, uint32 num, uint32, uint32, u
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(ReleaseOwnership)(CORO_PARAM, uint32 num, uint32, uint32, uint32) {
+void releaseOwnership(CORO_PARAM, uint32 num, uint32, uint32, uint32) {
if (!GLOBALS._mut[num]._lockCount) {
warning("ReleaseOwnership tried to release mutex %d, which isn't held", num);
return;
}
- if (GLOBALS._mut[num]._ownerPid != (uint32)CoroScheduler.getCurrentPID())
- error("ReleaseOwnership tried to release mutex %d, which is held by a different process", num);
+ if (GLOBALS._mut[num]._ownerPid != (uint32)CoroScheduler.getCurrentPID()) {
+ warning("ReleaseOwnership tried to release mutex %d, which is held by a different process", num);
+ return;
+ }
GLOBALS._mut[num]._lockCount--;
if (!GLOBALS._mut[num]._lockCount) {
@@ -2058,7 +2015,7 @@ DECLARE_CUSTOM_FUNCTION(ReleaseOwnership)(CORO_PARAM, uint32 num, uint32, uint32
*
*/
-void ThreadFadeInMusic(CORO_PARAM, const void *nMusic) {
+void threadFadeInMusic(CORO_PARAM, const void *nMusic) {
CORO_BEGIN_CONTEXT;
int i;
CORO_END_CONTEXT(_ctx);
@@ -2067,7 +2024,7 @@ void ThreadFadeInMusic(CORO_PARAM, const void *nMusic) {
CORO_BEGIN_CODE(_ctx);
- debug("Start FadeIn Music");
+ debugC(DEBUG_INTERMEDIATE, kTonyDebugSound, "Start FadeIn Music");
for (_ctx->i = 0; _ctx->i < 16; _ctx->i++) {
g_vm->setMusicVolume(nChannel, _ctx->i * 4);
@@ -2076,14 +2033,14 @@ void ThreadFadeInMusic(CORO_PARAM, const void *nMusic) {
}
g_vm->setMusicVolume(nChannel, 64);
- debug("End FadeIn Music");
+ debugC(DEBUG_INTERMEDIATE, kTonyDebugSound, "End FadeIn Music");
CORO_KILL_SELF();
CORO_END_CODE;
}
-void ThreadFadeOutMusic(CORO_PARAM, const void *nMusic) {
+void threadFadeOutMusic(CORO_PARAM, const void *nMusic) {
CORO_BEGIN_CONTEXT;
int i;
int startVolume;
@@ -2114,52 +2071,52 @@ void ThreadFadeOutMusic(CORO_PARAM, const void *nMusic) {
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(FadeInSoundEffect)(CORO_PARAM, uint32, uint32, uint32, uint32) {
- CoroScheduler.createProcess(ThreadFadeInMusic, &GLOBALS._curSoundEffect, sizeof(int));
+void fadeInSoundEffect(CORO_PARAM, uint32, uint32, uint32, uint32) {
+ CoroScheduler.createProcess(threadFadeInMusic, &GLOBALS._curSoundEffect, sizeof(int));
}
-DECLARE_CUSTOM_FUNCTION(FadeOutSoundEffect)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void fadeOutSoundEffect(CORO_PARAM, uint32, uint32, uint32, uint32) {
GLOBALS._bFadeOutStop = false;
- CoroScheduler.createProcess(ThreadFadeOutMusic, &GLOBALS._curSoundEffect, sizeof(int));
+ CoroScheduler.createProcess(threadFadeOutMusic, &GLOBALS._curSoundEffect, sizeof(int));
}
-DECLARE_CUSTOM_FUNCTION(FadeOutJingle)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void fadeOutJingle(CORO_PARAM, uint32, uint32, uint32, uint32) {
GLOBALS._bFadeOutStop = false;
int channel = 2;
- CoroScheduler.createProcess(ThreadFadeOutMusic, &channel, sizeof(int));
+ CoroScheduler.createProcess(threadFadeOutMusic, &channel, sizeof(int));
}
-DECLARE_CUSTOM_FUNCTION(FadeInJingle)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void fadeInJingle(CORO_PARAM, uint32, uint32, uint32, uint32) {
int channel = 2;
- CoroScheduler.createProcess(ThreadFadeInMusic, &channel, sizeof(int));
+ CoroScheduler.createProcess(threadFadeInMusic, &channel, sizeof(int));
}
-DECLARE_CUSTOM_FUNCTION(StopSoundEffect)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void stopSoundEffect(CORO_PARAM, uint32, uint32, uint32, uint32) {
g_vm->stopMusic(GLOBALS._curSoundEffect);
}
-DECLARE_CUSTOM_FUNCTION(StopJingle)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void stopJingle(CORO_PARAM, uint32, uint32, uint32, uint32) {
g_vm->stopMusic(2);
}
-DECLARE_CUSTOM_FUNCTION(MuteSoundEffect)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void muteSoundEffect(CORO_PARAM, uint32, uint32, uint32, uint32) {
g_vm->setMusicVolume(GLOBALS._curSoundEffect, 0);
}
-DECLARE_CUSTOM_FUNCTION(DemuteSoundEffect)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void demuteSoundEffect(CORO_PARAM, uint32, uint32, uint32, uint32) {
GLOBALS._bFadeOutStop = true;
g_vm->setMusicVolume(GLOBALS._curSoundEffect, 64);
}
-DECLARE_CUSTOM_FUNCTION(MuteJingle)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void muteJingle(CORO_PARAM, uint32, uint32, uint32, uint32) {
g_vm->setMusicVolume(2, 0);
}
-DECLARE_CUSTOM_FUNCTION(DemuteJingle)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void demuteJingle(CORO_PARAM, uint32, uint32, uint32, uint32) {
g_vm->setMusicVolume(2, 64);
}
-void CustPlayMusic(uint32 nChannel, const char *mFN, uint32 nFX, bool bLoop, int nSync = 0) {
+void custPlayMusic(uint32 nChannel, const char *mFN, uint32 nFX, bool bLoop, int nSync = 0) {
if (nSync == 0)
nSync = 2000;
debugC(DEBUG_INTERMEDIATE, kTonyDebugMusic, "Start CustPlayMusic");
@@ -2167,21 +2124,21 @@ void CustPlayMusic(uint32 nChannel, const char *mFN, uint32 nFX, bool bLoop, int
debugC(DEBUG_INTERMEDIATE, kTonyDebugMusic, "End CustPlayMusic");
}
-DECLARE_CUSTOM_FUNCTION(PlaySoundEffect)(CORO_PARAM, uint32 nMusic, uint32 nFX, uint32 bNoLoop, uint32) {
+void playSoundEffect(CORO_PARAM, uint32 nMusic, uint32 nFX, uint32 bNoLoop, uint32) {
if (nFX == 0 || nFX == 1 || nFX == 2) {
debugC(DEBUG_INTERMEDIATE, kTonyDebugSound, "PlaySoundEffect stop fadeout");
GLOBALS._bFadeOutStop = true;
}
GLOBALS._lastMusic = nMusic;
- CustPlayMusic(GLOBALS._curSoundEffect, musicFiles[nMusic].name, nFX, bNoLoop ? false : true, musicFiles[nMusic].sync);
+ custPlayMusic(GLOBALS._curSoundEffect, kMusicFiles[nMusic]._name, nFX, bNoLoop ? false : true, kMusicFiles[nMusic]._sync);
}
-DECLARE_CUSTOM_FUNCTION(PlayJingle)(CORO_PARAM, uint32 nMusic, uint32 nFX, uint32 bLoop, uint32) {
- CustPlayMusic(2, jingleFileNames[nMusic], nFX, bLoop);
+void playJingle(CORO_PARAM, uint32 nMusic, uint32 nFX, uint32 bLoop, uint32) {
+ custPlayMusic(2, kJingleFileNames[nMusic], nFX, bLoop);
}
-DECLARE_CUSTOM_FUNCTION(PlayItemSfx)(CORO_PARAM, uint32 nItem, uint32 nSFX, uint32, uint32) {
+void playItemSfx(CORO_PARAM, uint32 nItem, uint32 nSFX, uint32, uint32) {
if (nItem == 0) {
GLOBALS._tony->playSfx(nSFX);
} else {
@@ -2191,76 +2148,71 @@ DECLARE_CUSTOM_FUNCTION(PlayItemSfx)(CORO_PARAM, uint32 nItem, uint32 nSFX, uint
}
}
-
-void RestoreMusic(CORO_PARAM) {
+void restoreMusic(CORO_PARAM) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
CORO_BEGIN_CODE(_ctx);
- CORO_INVOKE_4(PlaySoundEffect, GLOBALS._lastMusic, 0, 0, 0);
+ CORO_INVOKE_4(playSoundEffect, GLOBALS._lastMusic, 0, 0, 0);
if (GLOBALS._lastTappeto != 0)
- CustPlayMusic(4, ambianceFile[GLOBALS._lastTappeto], 0, true);
+ custPlayMusic(4, kAmbianceFile[GLOBALS._lastTappeto], 0, true);
CORO_END_CODE;
}
-void SaveMusic(Common::OutSaveFile *f) {
+void saveMusic(Common::OutSaveFile *f) {
f->writeByte(GLOBALS._lastMusic);
f->writeByte(GLOBALS._lastTappeto);
}
-void LoadMusic(Common::InSaveFile *f) {
+void loadMusic(Common::InSaveFile *f) {
GLOBALS._lastMusic = f->readByte();
GLOBALS._lastTappeto = f->readByte();
}
-
-DECLARE_CUSTOM_FUNCTION(JingleFadeStart)(CORO_PARAM, uint32 nJingle, uint32 bLoop, uint32, uint32) {
+void jingleFadeStart(CORO_PARAM, uint32 nJingle, uint32 bLoop, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
CORO_BEGIN_CODE(_ctx);
- CORO_INVOKE_4(FadeOutSoundEffect, 0, 0, 0, 0);
- CORO_INVOKE_4(MuteJingle, 0, 0, 0, 0);
- CORO_INVOKE_4(PlayJingle, nJingle, 0, bLoop, 0);
- CORO_INVOKE_4(FadeInJingle, 0, 0, 0, 0);
+ CORO_INVOKE_4(fadeOutSoundEffect, 0, 0, 0, 0);
+ CORO_INVOKE_4(muteJingle, 0, 0, 0, 0);
+ CORO_INVOKE_4(playJingle, nJingle, 0, bLoop, 0);
+ CORO_INVOKE_4(fadeInJingle, 0, 0, 0, 0);
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(JingleFadeEnd)(CORO_PARAM, uint32 nJingle, uint32 bLoop, uint32, uint32) {
+void jingleFadeEnd(CORO_PARAM, uint32 nJingle, uint32 bLoop, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
CORO_BEGIN_CODE(_ctx);
- CORO_INVOKE_4(FadeOutJingle, 0, 0, 0, 0);
- CORO_INVOKE_4(FadeInSoundEffect, 0, 0, 0, 0);
+ CORO_INVOKE_4(fadeOutJingle, 0, 0, 0, 0);
+ CORO_INVOKE_4(fadeInSoundEffect, 0, 0, 0, 0);
CORO_END_CODE;
}
-
-
-
-DECLARE_CUSTOM_FUNCTION(MustSkipIdleStart)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void mustSkipIdleStart(CORO_PARAM, uint32, uint32, uint32, uint32) {
GLOBALS._bSkipIdle = true;
CoroScheduler.setEvent(GLOBALS._hSkipIdle);
}
-DECLARE_CUSTOM_FUNCTION(MustSkipIdleEnd)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void mustSkipIdleEnd(CORO_PARAM, uint32, uint32, uint32, uint32) {
GLOBALS._bSkipIdle = false;
CoroScheduler.resetEvent(GLOBALS._hSkipIdle);
}
-DECLARE_CUSTOM_FUNCTION(PatIrqFreeze)(CORO_PARAM, uint32 bStatus, uint32, uint32, uint32) {
+void patIrqFreeze(CORO_PARAM, uint32 bStatus, uint32, uint32, uint32) {
// Unused in ScummVM.
}
-DECLARE_CUSTOM_FUNCTION(OpenInitLoadMenu)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void openInitLoadMenu(CORO_PARAM, uint32, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -2271,7 +2223,7 @@ DECLARE_CUSTOM_FUNCTION(OpenInitLoadMenu)(CORO_PARAM, uint32, uint32, uint32, ui
CORO_END_CODE;
}
-DECLARE_CUSTOM_FUNCTION(OpenInitOptions)(CORO_PARAM, uint32, uint32, uint32, uint32) {
+void openInitOptions(CORO_PARAM, uint32, uint32, uint32, uint32) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -2282,8 +2234,7 @@ DECLARE_CUSTOM_FUNCTION(OpenInitOptions)(CORO_PARAM, uint32, uint32, uint32, uin
CORO_END_CODE;
}
-
-DECLARE_CUSTOM_FUNCTION(DoCredits)(CORO_PARAM, uint32 nMsg, uint32 dwTime, uint32, uint32) {
+void doCredits(CORO_PARAM, uint32 nMsg, uint32 dwTime, uint32, uint32) {
CORO_BEGIN_CONTEXT;
RMMessage *msg;
RMTextDialog *text;
@@ -2355,159 +2306,157 @@ DECLARE_CUSTOM_FUNCTION(DoCredits)(CORO_PARAM, uint32 nMsg, uint32 dwTime, uint3
CORO_END_CODE;
}
-
-
BEGIN_CUSTOM_FUNCTION_MAP()
-ASSIGN(1, CustLoadLocation)
-ASSIGN(2, MySleep)
-ASSIGN(3, SetPointer)
-ASSIGN(5, MoveTony)
-ASSIGN(6, FaceToMe)
-ASSIGN(7, BackToMe)
-ASSIGN(8, LeftToMe)
-ASSIGN(9, RightToMe)
-ASSIGN(10, SendTonyMessage)
-ASSIGN(11, ChangeBoxStatus)
-ASSIGN(12, ChangeLocation)
-ASSIGN(13, DisableTony)
-ASSIGN(14, EnableTony)
-ASSIGN(15, WaitForPatternEnd)
-ASSIGN(16, SetLocStartPosition)
-ASSIGN(17, ScrollLocation)
-ASSIGN(18, MoveTonyAndWait)
-ASSIGN(19, ChangeHotspot)
-ASSIGN(20, AddInventory)
-ASSIGN(21, RemoveInventory)
-ASSIGN(22, ChangeInventoryStatus)
-ASSIGN(23, SetTonyPosition)
-ASSIGN(24, SendFullscreenMessage)
-ASSIGN(25, SaveTonyPosition)
-ASSIGN(26, RestoreTonyPosition)
-ASSIGN(27, DisableInput)
-ASSIGN(28, EnableInput)
-ASSIGN(29, StopTony)
-
-ASSIGN(30, TonyTakeUp1)
-ASSIGN(31, TonyTakeMid1)
-ASSIGN(32, TonyTakeDown1)
-ASSIGN(33, TonyTakeUp2)
-ASSIGN(34, TonyTakeMid2)
-ASSIGN(35, TonyTakeDown2)
-
-ASSIGN(72, TonyPutUp1)
-ASSIGN(73, TonyPutMid1)
-ASSIGN(74, TonyPutDown1)
-ASSIGN(75, TonyPutUp2)
-ASSIGN(76, TonyPutMid2)
-ASSIGN(77, TonyPutDown2)
-
-ASSIGN(36, TonyOnTheFloor)
-ASSIGN(37, TonyGetUp)
-ASSIGN(38, TonyShepherdess)
-ASSIGN(39, TonyWhistle)
-
-ASSIGN(40, TonyLaugh)
-ASSIGN(41, TonyHips)
-ASSIGN(42, TonySing)
-ASSIGN(43, TonyIndicate)
-ASSIGN(44, TonyScaredWithHands)
-ASSIGN(49, TonyScaredWithoutHands)
-ASSIGN(45, TonyWithGlasses)
-ASSIGN(46, TonyWithWorm)
-ASSIGN(47, TonyWithHammer)
-ASSIGN(48, TonyWithRope)
-ASSIGN(90, TonyWithRabbitANIM)
-ASSIGN(91, TonyWithRecipeANIM)
-ASSIGN(92, TonyWithCardsANIM)
-ASSIGN(93, TonyWithSnowmanANIM)
-ASSIGN(94, TonyWithSnowmanStart)
-ASSIGN(95, TonyWithSnowmanEnd)
-ASSIGN(96, TonyWithRabbitStart)
-ASSIGN(97, TonyWithRabbitEnd)
-ASSIGN(98, TonyWithRecipeStart)
-ASSIGN(99, TonyWithRecipeEnd)
-ASSIGN(100, TonyWithCardsStart)
-ASSIGN(101, TonyWithCardsEnd)
-ASSIGN(102, TonyWithNotebookStart)
-ASSIGN(103, TonyWithNotebookEnd)
-ASSIGN(104, TonyWithMegaphoneStart)
-ASSIGN(105, TonyWithMegaphoneEnd)
-ASSIGN(106, TonyWithBeardStart)
-ASSIGN(107, TonyWithBeardEnd)
-ASSIGN(108, TonyGiggle)
-ASSIGN(109, TonyDisgusted)
-ASSIGN(110, TonySarcastic)
-ASSIGN(111, TonyMacbeth)
-ASSIGN(112, TonySniffLeft)
-ASSIGN(113, TonySniffRight)
-ASSIGN(114, TonyScaredStart)
-ASSIGN(115, TonyScaredEnd)
-ASSIGN(116, TonyWithSecretary)
-
-ASSIGN(50, CharSetCode)
-ASSIGN(51, CharSetColor)
-ASSIGN(52, CharSetTalkPattern)
-ASSIGN(53, CharSendMessage)
-ASSIGN(54, CharSetStartEndTalkPattern)
-
-ASSIGN(60, MCharSetCode)
-ASSIGN(61, MCharSetColor)
-ASSIGN(62, MCharSetCurrentGroup)
-ASSIGN(63, MCharSetNumTalksInGroup)
-ASSIGN(64, MCharSetNumTexts)
-ASSIGN(65, MCharSendMessage)
-ASSIGN(66, MCharSetPosition)
-ASSIGN(67, MCharSetAlwaysBack)
-ASSIGN(68, MCharResetCode)
-
-ASSIGN(70, StartDialog)
-ASSIGN(71, SendDialogMessage)
-
-ASSIGN(80, TakeOwnership)
-ASSIGN(81, ReleaseOwnership)
-
-ASSIGN(86, PlaySoundEffect)
-ASSIGN(87, PlayJingle)
-ASSIGN(88, FadeInSoundEffect)
-ASSIGN(89, FadeOutSoundEffect)
-ASSIGN(123, FadeInJingle)
-ASSIGN(124, FadeOutJingle)
-ASSIGN(125, MuteSoundEffect)
-ASSIGN(126, DemuteSoundEffect)
-ASSIGN(127, MuteJingle)
-ASSIGN(128, DemuteJingle)
-ASSIGN(84, StopSoundEffect)
-ASSIGN(85, StopJingle)
-ASSIGN(83, PlayItemSfx)
-ASSIGN(129, JingleFadeStart)
-ASSIGN(130, JingleFadeEnd)
-
-ASSIGN(120, ShakeScreen)
-ASSIGN(121, AutoSave)
-ASSIGN(122, AbortGame)
-ASSIGN(131, NoBullsEye)
-ASSIGN(132, SendFullscreenMsgStart)
-ASSIGN(133, SendFullscreenMsgEnd)
-ASSIGN(134, CustEnableGUI)
-ASSIGN(135, CustDisableGUI)
-ASSIGN(136, ClearScreen)
-ASSIGN(137, PatIrqFreeze)
-ASSIGN(138, TonySetPerorate)
-ASSIGN(139, OpenInitLoadMenu)
-ASSIGN(140, OpenInitOptions)
-ASSIGN(141, SyncScrollLocation)
-ASSIGN(142, CloseLocation)
-ASSIGN(143, SetAlwaysDisplay)
-ASSIGN(144, DoCredits)
-
-ASSIGN(200, MustSkipIdleStart);
-ASSIGN(201, MustSkipIdleEnd);
+ASSIGN(1, custLoadLocation)
+ASSIGN(2, mySleep)
+ASSIGN(3, setPointer)
+ASSIGN(5, moveTony)
+ASSIGN(6, faceToMe)
+ASSIGN(7, backToMe)
+ASSIGN(8, leftToMe)
+ASSIGN(9, rightToMe)
+ASSIGN(10, sendTonyMessage)
+ASSIGN(11, changeBoxStatus)
+ASSIGN(12, changeLocation)
+ASSIGN(13, disableTony)
+ASSIGN(14, enableTony)
+ASSIGN(15, waitForPatternEnd)
+ASSIGN(16, setLocStartPosition)
+ASSIGN(17, scrollLocation)
+ASSIGN(18, moveTonyAndWait)
+ASSIGN(19, changeHotspot)
+ASSIGN(20, addInventory)
+ASSIGN(21, removeInventory)
+ASSIGN(22, changeInventoryStatus)
+ASSIGN(23, setTonyPosition)
+ASSIGN(24, sendFullscreenMessage)
+ASSIGN(25, saveTonyPosition)
+ASSIGN(26, restoreTonyPosition)
+ASSIGN(27, disableInput)
+ASSIGN(28, enableInput)
+ASSIGN(29, stopTony)
+
+ASSIGN(30, tonyTakeUp1)
+ASSIGN(31, tonyTakeMid1)
+ASSIGN(32, tonyTakeDown1)
+ASSIGN(33, tonyTakeUp2)
+ASSIGN(34, tonyTakeMid2)
+ASSIGN(35, tonyTakeDown2)
+
+ASSIGN(72, tonyPutUp1)
+ASSIGN(73, tonyPutMid1)
+ASSIGN(74, tonyPutDown1)
+ASSIGN(75, tonyPutUp2)
+ASSIGN(76, tonyPutMid2)
+ASSIGN(77, tonyPutDown2)
+
+ASSIGN(36, tonyOnTheFloor)
+ASSIGN(37, tonyGetUp)
+ASSIGN(38, tonyShepherdess)
+ASSIGN(39, tonyWhistle)
+
+ASSIGN(40, tonyLaugh)
+ASSIGN(41, tonyHips)
+ASSIGN(42, tonySing)
+ASSIGN(43, tonyIndicate)
+ASSIGN(44, tonyScaredWithHands)
+ASSIGN(49, tonyScaredWithoutHands)
+ASSIGN(45, tonyWithGlasses)
+ASSIGN(46, tonyWithWorm)
+ASSIGN(47, tonyWithHammer)
+ASSIGN(48, tonyWithRope)
+ASSIGN(90, tonyWithRabbitANIM)
+ASSIGN(91, tonyWithRecipeANIM)
+ASSIGN(92, tonyWithCardsANIM)
+ASSIGN(93, tonyWithSnowmanANIM)
+ASSIGN(94, tonyWithSnowmanStart)
+ASSIGN(95, tonyWithSnowmanEnd)
+ASSIGN(96, tonyWithRabbitStart)
+ASSIGN(97, tonyWithRabbitEnd)
+ASSIGN(98, tonyWithRecipeStart)
+ASSIGN(99, tonyWithRecipeEnd)
+ASSIGN(100, tonyWithCardsStart)
+ASSIGN(101, tonyWithCardsEnd)
+ASSIGN(102, tonyWithNotebookStart)
+ASSIGN(103, tonyWithNotebookEnd)
+ASSIGN(104, tonyWithMegaphoneStart)
+ASSIGN(105, tonyWithMegaphoneEnd)
+ASSIGN(106, tonyWithBeardStart)
+ASSIGN(107, tonyWithBeardEnd)
+ASSIGN(108, tonyGiggle)
+ASSIGN(109, tonyDisgusted)
+ASSIGN(110, tonySarcastic)
+ASSIGN(111, tonyMacbeth)
+ASSIGN(112, tonySniffLeft)
+ASSIGN(113, tonySniffRight)
+ASSIGN(114, tonyScaredStart)
+ASSIGN(115, tonyScaredEnd)
+ASSIGN(116, tonyWithSecretary)
+
+ASSIGN(50, charSetCode)
+ASSIGN(51, charSetColor)
+ASSIGN(52, charSetTalkPattern)
+ASSIGN(53, charSendMessage)
+ASSIGN(54, charSetStartEndTalkPattern)
+
+ASSIGN(60, mCharSetCode)
+ASSIGN(61, mCharSetColor)
+ASSIGN(62, mCharSetCurrentGroup)
+ASSIGN(63, mCharSetNumTalksInGroup)
+ASSIGN(64, mCharSetNumTexts)
+ASSIGN(65, mCharSendMessage)
+ASSIGN(66, mCharSetPosition)
+ASSIGN(67, mCharSetAlwaysBack)
+ASSIGN(68, mCharResetCode)
+
+ASSIGN(70, startDialog)
+ASSIGN(71, sendDialogMessage)
+
+ASSIGN(80, takeOwnership)
+ASSIGN(81, releaseOwnership)
+
+ASSIGN(86, playSoundEffect)
+ASSIGN(87, playJingle)
+ASSIGN(88, fadeInSoundEffect)
+ASSIGN(89, fadeOutSoundEffect)
+ASSIGN(123, fadeInJingle)
+ASSIGN(124, fadeOutJingle)
+ASSIGN(125, muteSoundEffect)
+ASSIGN(126, demuteSoundEffect)
+ASSIGN(127, muteJingle)
+ASSIGN(128, demuteJingle)
+ASSIGN(84, stopSoundEffect)
+ASSIGN(85, stopJingle)
+ASSIGN(83, playItemSfx)
+ASSIGN(129, jingleFadeStart)
+ASSIGN(130, jingleFadeEnd)
+
+ASSIGN(120, shakeScreen)
+ASSIGN(121, autoSave)
+ASSIGN(122, abortGame)
+ASSIGN(131, noBullsEye)
+ASSIGN(132, sendFullscreenMsgStart)
+ASSIGN(133, sendFullscreenMsgEnd)
+ASSIGN(134, custEnableGUI)
+ASSIGN(135, custDisableGUI)
+ASSIGN(136, clearScreen)
+ASSIGN(137, patIrqFreeze)
+ASSIGN(138, tonySetPerorate)
+ASSIGN(139, openInitLoadMenu)
+ASSIGN(140, openInitOptions)
+ASSIGN(141, syncScrollLocation)
+ASSIGN(142, closeLocation)
+ASSIGN(143, setAlwaysDisplay)
+ASSIGN(144, doCredits)
+
+ASSIGN(200, mustSkipIdleStart);
+ASSIGN(201, mustSkipIdleEnd);
END_CUSTOM_FUNCTION_MAP()
void processKilledCallback(Common::PROCESS *p) {
- for (uint i = 0; i < 10; i++)
+ for (uint i = 0; i < 10; i++) {
if (GLOBALS._mut[i]._ownerPid == p->pid) {
// Handle scripts which don't call ReleaseOwnership, such as
// the one in loc37's vEnter when Tony is chasing the mouse.
@@ -2517,6 +2466,7 @@ void processKilledCallback(Common::PROCESS *p) {
GLOBALS._mut[i]._lockCount = 0;
CoroScheduler.setEvent(GLOBALS._mut[i]._eventId);
}
+ }
}
void setupGlobalVars(RMTony *tony, RMPointer *ptr, RMGameBoxes *box, RMLocation *loc, RMInventory *inv, RMInput *input) {
@@ -2531,13 +2481,12 @@ void setupGlobalVars(RMTony *tony, RMPointer *ptr, RMGameBoxes *box, RMLocation
GLOBALS.EnableGUI = mainEnableGUI;
GLOBALS._bAlwaysDisplay = false;
- int i;
CoroScheduler.setResourceCallback(processKilledCallback);
- for (i = 0; i < 10; i++)
+ for (int i = 0; i < 10; i++)
GLOBALS._mut[i]._eventId = CoroScheduler.createEvent(false, true);
- for (i = 0; i < 200; i++)
+ for (int i = 0; i < 200; i++)
GLOBALS._ambiance[i] = 0;
GLOBALS._ambiance[6] = AMBIANCE_CRICKETS;
diff --git a/engines/tony/custom.h b/engines/tony/custom.h
index 524ab14aab..0f1061e8cd 100644
--- a/engines/tony/custom.h
+++ b/engines/tony/custom.h
@@ -36,9 +36,12 @@ namespace Tony {
using namespace MPAL;
-#define INIT_CUSTOM_FUNCTION MapCustomFunctions
+struct MusicFileEntry {
+ const char *_name;
+ int _sync;
+};
-#define DECLARE_CUSTOM_FUNCTION(x) void x
+#define INIT_CUSTOM_FUNCTION MapCustomFunctions
#define BEGIN_CUSTOM_FUNCTION_MAP() \
static void AssignError(int num) { \
@@ -63,6 +66,17 @@ class RMLocation;
class RMInventory;
class RMInput;
+void charsSaveAll(Common::OutSaveFile *f);
+void charsLoadAll(Common::InSaveFile *f);
+void mCharResetCodes();
+void saveChangedHotspot(Common::OutSaveFile *f);
+void loadChangedHotspot(Common::InSaveFile *f);
+void reapplyChangedHotspot();
+
+void restoreMusic(CORO_PARAM);
+void saveMusic(Common::OutSaveFile *f);
+void loadMusic(Common::InSaveFile *f);
+
void INIT_CUSTOM_FUNCTION(LPCUSTOMFUNCTION *lpMap, Common::String *lpStrMap);
void setupGlobalVars(RMTony *tony, RMPointer *ptr, RMGameBoxes *box, RMLocation *loc, RMInventory *inv, RMInput *input);
diff --git a/engines/tony/detection_tables.h b/engines/tony/detection_tables.h
index f9881c29f2..ce3ab01a9f 100644
--- a/engines/tony/detection_tables.h
+++ b/engines/tony/detection_tables.h
@@ -124,6 +124,22 @@ static const TonyGameDescription gameDescriptions[] = {
},
},
{
+ // Tony Tough Italian provided by Giovanni Bajo
+ {
+ "tony",
+ 0,
+ {
+ {"roasted.mpr", 0, "06203dbbc85fdd1e6dc8fc211c1a6207", 135911071},
+ {"roasted.mpc", 0, "6202816f991b15af82aab84e3e4be011", 380183},
+ AD_LISTEND
+ },
+ Common::IT_ITA,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+ },
+ {
// Tony Tough Polish provided by Fabio Barzagli
{
"tony",
@@ -139,6 +155,39 @@ static const TonyGameDescription gameDescriptions[] = {
GUIO1(GUIO_NONE)
},
},
+ {
+ // Tony Tough German "Gamestar" provided in bug #3566035
+ {
+ "tony",
+ 0,
+ {
+ {"roasted.mpr", 0, "06203dbbc85fdd1e6dc8fc211c1a6207", 135911071},
+ {"roasted.mpc", 0, "187de6f88f4083808cb66342ab55a7fd", 389904},
+ AD_LISTEND
+ },
+ Common::DE_DEU,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+ },
+ {
+ // Tony Tough Czech provided in bug #3565765
+ {
+ "tony",
+ 0,
+ {
+ // {"data1.cab", 0, "c6d5dd8f0c1241a6e3f7861b7f27bf7b", 4350},
+ {"roasted.mpr", 0, "06203dbbc85fdd1e6dc8fc211c1a6207", 135911071},
+ {"roasted.mpc", 0, "a8283a101878f3ca105f1f83f07e2c40", 386491},
+ AD_LISTEND
+ },
+ Common::CZ_CZE,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+ },
{ AD_TABLE_END_MARKER }
};
diff --git a/engines/tony/font.cpp b/engines/tony/font.cpp
index 927adf9006..fa018b4464 100644
--- a/engines/tony/font.cpp
+++ b/engines/tony/font.cpp
@@ -84,10 +84,9 @@ void RMFont::unload() {
RMGfxPrimitive *RMFont::makeLetterPrimitive(byte bChar, int &nLength) {
RMFontPrimitive *prim;
- int nLett;
// Convert from character to glyph index
- nLett = convertToLetter(bChar);
+ int nLett = convertToLetter(bChar);
assert(nLett < _nLetters);
// Create primitive font
@@ -120,12 +119,11 @@ void RMFont::close() {
}
int RMFont::stringLen(const Common::String &text) {
- uint len, i;
-
if (text.empty())
return letterLength('\0');
- len = 0;
+ uint len = 0;
+ uint i;
for (i = 0; i < text.size() - 1; i++)
len += letterLength(text[i], text[i + 1]);
len += letterLength(text[i]);
@@ -157,7 +155,6 @@ void RMFontColor::setBaseColor(byte r1, byte g1, byte b1) {
int gstep = g / 14;
int bstep = b / 14;
- int i;
byte pal[768 * 3];
// Check if we are already on the right color
@@ -169,7 +166,7 @@ void RMFontColor::setBaseColor(byte r1, byte g1, byte b1) {
_fontB = b1;
// Constructs a new palette for the font
- for (i = 1; i < 16; i++) {
+ for (int i = 1; i < 16; i++) {
pal[i * 3 + 0] = r >> 16;
pal[i * 3 + 1] = g >> 16;
pal[i * 3 + 2] = b >> 16;
@@ -184,7 +181,7 @@ void RMFontColor::setBaseColor(byte r1, byte g1, byte b1) {
pal[15 * 3 + 2] += 8;
// Puts in all the letters
- for (i = 0; i < _nLetters; i++)
+ for (int i = 0; i < _nLetters; i++)
_letter[i].loadPaletteWA(pal);
}
@@ -204,8 +201,6 @@ int RMFontWithTables::letterLength(int nChar, int nNext) {
\****************************************************************************/
void RMFontDialog::init() {
- int i;
-
// bernie: Number of characters in the font
int nchars =
112 // base
@@ -222,7 +217,7 @@ void RMFontDialog::init() {
_hDefault = 18;
Common::fill(&_l2Table[0][0], &_l2Table[0][0] + (256 * 256), '\0');
- for (i = 0; i < 256; i++) {
+ for (int i = 0; i < 256; i++) {
_cTable[i] = g_vm->_cTableDialog[i];
_lTable[i] = g_vm->_lTableDialog[i];
}
@@ -234,8 +229,6 @@ void RMFontDialog::init() {
\****************************************************************************/
void RMFontMacc::init() {
- int i;
-
// bernie: Number of characters in the font
int nchars =
102 // base
@@ -245,7 +238,6 @@ void RMFontMacc::init() {
+ 8 // francais
+ 5; // deutsch
-
load(RES_F_MACC, nchars, 11, 16);
// Default
@@ -253,7 +245,7 @@ void RMFontMacc::init() {
_hDefault = 17;
Common::fill(&_l2Table[0][0], &_l2Table[0][0] + (256 * 256), '\0');
- for (i = 0; i < 256; i++) {
+ for (int i = 0; i < 256; i++) {
_cTable[i] = g_vm->_cTableMacc[i];
_lTable[i] = g_vm->_lTableMacc[i];
}
@@ -264,8 +256,6 @@ void RMFontMacc::init() {
\****************************************************************************/
void RMFontCredits::init() {
- int i;
-
// bernie: Number of characters in the font
int nchars =
112 // base
@@ -275,7 +265,6 @@ void RMFontCredits::init() {
+ 8 // french
+ 2; // deutsch
-
load(RES_F_CREDITS, nchars, 27, 28, RES_F_CPAL);
// Default
@@ -283,7 +272,7 @@ void RMFontCredits::init() {
_hDefault = 28;
Common::fill(&_l2Table[0][0], &_l2Table[0][0] + (256 * 256), '\0');
- for (i = 0; i < 256; i++) {
+ for (int i = 0; i < 256; i++) {
_cTable[i] = g_vm->_cTableCred[i];
_lTable[i] = g_vm->_lTableCred[i];
}
@@ -305,10 +294,7 @@ void RMFontObj::setBothCase(int nChar, int nNext, signed char spiazz) {
_l2Table[TOLOWER(nChar)][TOLOWER(nNext)] = spiazz;
}
-
void RMFontObj::init() {
- int i;
-
//bernie: Number of characters in the font (solo maiuscolo)
int nchars =
85 // base
@@ -318,7 +304,6 @@ void RMFontObj::init() {
+ 0 // francais (no uppercase chars)
+ 1; // deutsch
-
load(RES_F_OBJ, nchars, 25, 30);
// Initialize the font table
@@ -326,7 +311,7 @@ void RMFontObj::init() {
_hDefault = 30;
Common::fill(&_l2Table[0][0], &_l2Table[0][0] + (256 * 256), '\0');
- for (i = 0; i < 256; i++) {
+ for (int i = 0; i < 256; i++) {
_cTable[i] = g_vm->_cTableObj[i];
_lTable[i] = g_vm->_lTableObj[i];
}
@@ -345,7 +330,6 @@ void RMFontObj::init() {
setBothCase('R', 'U', 3);
}
-
/****************************************************************************\
* RMText Methods
\****************************************************************************/
@@ -409,11 +393,6 @@ void RMText::writeText(const Common::String &text, int nFont, int *time) {
void RMText::writeText(Common::String text, RMFontColor *font, int *time) {
RMGfxPrimitive *prim;
- uint p, old_p;
- int j, x, y;
- int len;
- int numchar;
- int width, height;
// Set the base color
font->setBaseColor(_textR, _textG, _textB);
@@ -428,8 +407,9 @@ void RMText::writeText(Common::String text, RMFontColor *font, int *time) {
// Divide the words into lines. In this cycle, X contains the maximum length reached by a line,
// and the number of lines
Common::Array<Common::String> lines;
- p = 0;
- j = x = 0;
+ uint p = 0;
+ int j = 0;
+ int x = 0;
while (p < text.size()) {
j += font->stringLen(text[p]);
if (j > (((_aHorType == HLEFTPAR) && (lines.size() > 0)) ? _maxLineLength - 25 : _maxLineLength)) {
@@ -443,7 +423,7 @@ void RMText::writeText(Common::String text, RMFontColor *font, int *time) {
// width of a line caused discontinuation of the whole sentence.
// This workaround has the partial word broken up so it will still display
//
- old_p = p;
+ uint old_p = p;
while (text[p] != ' ' && text[p] != '-' && p > 0)
p--;
@@ -475,8 +455,8 @@ void RMText::writeText(Common::String text, RMFontColor *font, int *time) {
x += 8;
// Starting position for the surface: X1, Y
- width = x;
- height = (lines.size() - 1) * font->letterHeight() + font->_fontDimy;
+ int width = x;
+ int height = (lines.size() - 1) * font->letterHeight() + font->_fontDimy;
// Create the surface
create(width, height);
@@ -484,8 +464,8 @@ void RMText::writeText(Common::String text, RMFontColor *font, int *time) {
p = 0;
- y = 0;
- numchar = 0;
+ int y = 0;
+ int numchar = 0;
for (uint i = 0; i < lines.size(); ++i) {
const Common::String &line = lines[i];
@@ -522,6 +502,7 @@ void RMText::writeText(Common::String text, RMFontColor *font, int *time) {
continue;
}
+ int len;
prim = font->makeLetterPrimitive(line[p], len);
prim->getDst()._x1 = x;
prim->getDst()._y1 = y;
@@ -737,8 +718,8 @@ void RMTextDialog::removeThis(CORO_PARAM, bool &result) {
CORO_END_CODE;
}
-void RMTextDialog::Unregister() {
- RMGfxTask::Unregister();
+void RMTextDialog::unregister() {
+ RMGfxTask::unregister();
assert(_nInList == 0);
CoroScheduler.setEvent(_hEndDisplay);
}
@@ -908,7 +889,7 @@ RMPoint RMTextItemName::getHotspot() {
if (_item == NULL)
return _mpos + _curscroll;
else
- return _item->hotspot();
+ return _item->getHotspot();
}
RMItem *RMTextItemName::getSelectedItem() {
@@ -944,7 +925,7 @@ RMDialogChoice::RMDialogChoice() {
_hUnreg = CoroScheduler.createEvent(false, false);
_bRemoveFromOT = false;
-
+
_curAdded = 0;
_bShow = false;
}
@@ -953,8 +934,8 @@ RMDialogChoice::~RMDialogChoice() {
CoroScheduler.closeEvent(_hUnreg);
}
-void RMDialogChoice::Unregister() {
- RMGfxWoodyBuffer::Unregister();
+void RMDialogChoice::unregister() {
+ RMGfxWoodyBuffer::unregister();
assert(!_nInList);
CoroScheduler.pulseEvent(_hUnreg);
@@ -987,8 +968,6 @@ void RMDialogChoice::close() {
}
void RMDialogChoice::setNumChoices(int num) {
- int i;
-
_numChoices = num;
_curAdded = 0;
@@ -997,7 +976,7 @@ void RMDialogChoice::setNumChoices(int num) {
_ptDrawStrings = new RMPoint[num];
// Initialization
- for (i = 0; i < _numChoices; i++) {
+ for (int i = 0; i < _numChoices; i++) {
_drawedStrings[i].setColor(0, 255, 0);
_drawedStrings[i].setAlignType(RMText::HLEFTPAR, RMText::VTOP);
_drawedStrings[i].setMaxLineLength(600);
diff --git a/engines/tony/font.h b/engines/tony/font.h
index 99b20571b1..13c1ddf268 100644
--- a/engines/tony/font.h
+++ b/engines/tony/font.h
@@ -252,7 +252,7 @@ public:
virtual void removeThis(CORO_PARAM, bool &result);
// Overloaded de-registration
- virtual void Unregister();
+ virtual void unregister();
// Overloading of the Draw to center the text, if necessary
virtual void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim);
@@ -344,7 +344,7 @@ protected:
public:
virtual void removeThis(CORO_PARAM, bool &result);
virtual void draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim);
- void Unregister();
+ void unregister();
public:
// Initialization
diff --git a/engines/tony/game.cpp b/engines/tony/game.cpp
index 2bcfdc7fc2..42ace987b4 100644
--- a/engines/tony/game.cpp
+++ b/engines/tony/game.cpp
@@ -34,7 +34,6 @@
#include "tony/mpal/memory.h"
#include "tony/mpal/mpal.h"
#include "tony/mpal/mpalutils.h"
-#include "tony/custom.h"
#include "tony/game.h"
#include "tony/gfxengine.h"
#include "tony/tony.h"
@@ -288,9 +287,7 @@ RMOptionScreen::RMOptionScreen() {
_buttonSave_ArrowRight = NULL;
_bEditSaveName = false;
- int i;
-
- for (i = 0; i < 6; i++) {
+ for (int i = 0; i < 6; i++) {
_curThumb[i] = NULL;
_buttonSave_States[i] = NULL;
}
@@ -501,9 +498,7 @@ void RMOptionScreen::refreshAll(CORO_PARAM) {
}
void RMOptionScreen::refreshThumbnails() {
- int i;
-
- for (i = 0; i < 6; i++) {
+ for (int i = 0; i < 6; i++) {
if (_curThumb[i])
delete _curThumb[i];
@@ -691,9 +686,7 @@ void RMOptionScreen::closeState() {
_buttonExit = NULL;
if (_nState == MENULOAD || _nState == MENUSAVE) {
- int i;
-
- for (i = 0; i < 6; i++) {
+ for (int i = 0; i < 6; i++) {
if (_curThumb[i] != NULL) {
delete _curThumb[i];
_curThumb[i] = NULL;
@@ -981,7 +974,7 @@ void RMOptionScreen::doFrame(CORO_PARAM, RMInput *input) {
CORO_BEGIN_CODE(_ctx);
- // If it is fully open, do nothing
+ // If it is not fully open, do nothing
if (_fadeStep != 6)
return;
@@ -1343,9 +1336,7 @@ void RMOptionScreen::removeThis(CORO_PARAM, bool &result) {
bool RMOptionScreen::loadThumbnailFromSaveState(int nState, byte *lpDestBuf, Common::String &name, byte &diff) {
- Common::String buf;
char namebuf[256];
- int i;
Common::InSaveFile *f;
char id[4];
@@ -1355,7 +1346,7 @@ bool RMOptionScreen::loadThumbnailFromSaveState(int nState, byte *lpDestBuf, Com
diff = 10;
// Get the savegame filename for the given slot
- buf = g_vm->getSaveStateFileName(nState);
+ Common::String buf = g_vm->getSaveStateFileName(nState);
// Try and open the savegame
f = g_system->getSavefileManager()->openForLoading(buf);
@@ -1410,9 +1401,9 @@ bool RMOptionScreen::loadThumbnailFromSaveState(int nState, byte *lpDestBuf, Com
return true;
}
- i = f->readByte();
- f->read(namebuf, i);
- namebuf[i] = '\0';
+ int bufSize = f->readByte();
+ f->read(namebuf, bufSize);
+ namebuf[bufSize] = '\0';
name = namebuf;
delete f;
@@ -1436,9 +1427,7 @@ RMPointer::~RMPointer() {
}
void RMPointer::init() {
- int i;
-
- for (i = 0; i < 5; i++) {
+ for (int i = 0; i < 5; i++) {
RMResRaw res(RES_P_GO + i);
_pointer[i] = new RMGfxSourceBuffer8RLEByteAA;
@@ -1446,7 +1435,7 @@ void RMPointer::init() {
_pointer[i]->loadPaletteWA(RES_P_PAL);
}
- for (i = 0; i < 5; i++) {
+ for (int i = 0; i < 5; i++) {
RMRes res(RES_P_PAP1 + i);
Common::SeekableReadStream *ds = res.getReadStream();
_specialPointer[i] = new RMItem;
@@ -1467,9 +1456,7 @@ void RMPointer::init() {
}
void RMPointer::close() {
- int i;
-
- for (i = 0; i < 5; i++) {
+ for (int i = 0; i < 5; i++) {
if (_pointer[i] != NULL) {
delete _pointer[i];
_pointer[i] = NULL;
diff --git a/engines/tony/gfxcore.cpp b/engines/tony/gfxcore.cpp
index 71bf31396c..04ce01b0ed 100644
--- a/engines/tony/gfxcore.cpp
+++ b/engines/tony/gfxcore.cpp
@@ -56,7 +56,7 @@ void RMGfxTask::Register() {
_nInList++;
}
-void RMGfxTask::Unregister() {
+void RMGfxTask::unregister() {
_nInList--;
assert(_nInList >= 0);
}
@@ -269,7 +269,7 @@ void RMGfxTargetBuffer::clearOT() {
cur = _otlist;
while (cur != NULL) {
- cur->_prim->_task->Unregister();
+ cur->_prim->_task->unregister();
delete cur->_prim;
n = cur->_next;
delete cur;
@@ -303,7 +303,7 @@ void RMGfxTargetBuffer::drawOT(CORO_PARAM) {
CORO_INVOKE_1(_ctx->cur->_prim->_task->removeThis, _ctx->result);
if (_ctx->result) {
// De-register the task
- _ctx->cur->_prim->_task->Unregister();
+ _ctx->cur->_prim->_task->unregister();
// Delete task, freeing the memory
delete _ctx->cur->_prim;
@@ -361,7 +361,7 @@ void RMGfxTargetBuffer::addPrim(RMGfxPrimitive *prim) {
void RMGfxTargetBuffer::addDirtyRect(const Common::Rect &r) {
assert(r.isValidRect());
if (_trackDirtyRects && r.width() > 0 && r.height() > 0)
- _currentDirtyRects.push_back(r);
+ _currentDirtyRects.push_back(r);
}
Common::List<Common::Rect> &RMGfxTargetBuffer::getDirtyRects() {
@@ -507,9 +507,7 @@ int RMGfxSourceBufferPal::loadPaletteWA(const byte *buf, bool bSwapped) {
}
int RMGfxSourceBufferPal::loadPalette(const byte *buf) {
- int i;
-
- for (i = 0; i < 256; i++)
+ for (int i = 0; i < 256; i++)
memcpy(_pal + i * 3, buf + i * 4, 3);
preparePalette();
@@ -518,9 +516,7 @@ int RMGfxSourceBufferPal::loadPalette(const byte *buf) {
}
void RMGfxSourceBufferPal::preparePalette() {
- int i;
-
- for (i = 0; i < 256; i++) {
+ for (int i = 0; i < 256; i++) {
_palFinal[i] = (((int)_pal[i * 3 + 0] >> 3) << 10) |
(((int)_pal[i * 3 + 1] >> 3) << 5) |
(((int)_pal[i * 3 + 2] >> 3) << 0);
@@ -528,10 +524,8 @@ void RMGfxSourceBufferPal::preparePalette() {
}
int RMGfxSourceBufferPal::init(const byte *buf, int dimx, int dimy, bool bLoadPalette) {
- int read;
-
// Load the RAW image
- read = RMGfxSourceBuffer::init(buf, dimx, dimy);
+ int read = RMGfxSourceBuffer::init(buf, dimx, dimy);
// Load the palette if necessary
if (bLoadPalette)
@@ -596,7 +590,7 @@ RMGfxSourceBuffer8::~RMGfxSourceBuffer8() {
}
void RMGfxSourceBuffer8::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
- int x, y, width, height, u, v;
+ int width, height, u, v;
int bufx = bigBuf.getDimx();
uint16 *buf = bigBuf;
byte *raw = _buf;
@@ -623,10 +617,10 @@ void RMGfxSourceBuffer8::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimit
// Normal step
if (_bTrasp0) {
- for (y = 0; y < height; y++) {
+ for (int y = 0; y < height; y++) {
raw = _buf + (y + v) * _dimx + u;
- for (x = 0; x < width; x++) {
+ for (int x = 0; x < width; x++) {
if (*raw)
*buf = _palFinal[*raw];
buf++;
@@ -636,10 +630,10 @@ void RMGfxSourceBuffer8::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimit
buf += bufx - width;
}
} else {
- for (y = 0; y < height; y++) {
+ for (int y = 0; y < height; y++) {
raw = _buf + (y + v) * _dimx + u;
- for (x = 0; x < width; x += 2) {
+ for (int x = 0; x < width; x += 2) {
buf[0] = _palFinal[raw[0]];
buf[1] = _palFinal[raw[1]];
@@ -693,11 +687,9 @@ RMGfxSourceBuffer8AB::~RMGfxSourceBuffer8AB() {
}
int RMGfxSourceBuffer8AB::calcTrasp(int fore, int back) {
- int r, g, b;
-
- r = (GETRED(fore) >> 2) + (GETRED(back) >> 1);
- g = (GETGREEN(fore) >> 2) + (GETGREEN(back) >> 1);
- b = (GETBLUE(fore) >> 2) + (GETBLUE(back) >> 1);
+ int r = (GETRED(fore) >> 2) + (GETRED(back) >> 1);
+ int g = (GETGREEN(fore) >> 2) + (GETGREEN(back) >> 1);
+ int b = (GETBLUE(fore) >> 2) + (GETBLUE(back) >> 1);
if (r > 0x1F)
r = 0x1F;
@@ -713,7 +705,7 @@ int RMGfxSourceBuffer8AB::calcTrasp(int fore, int back) {
void RMGfxSourceBuffer8AB::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
- int x, y, width, height, u, v;
+ int width, height, u, v;
int bufx = bigBuf.getDimx();
uint16 *buf = bigBuf;
byte *raw = _buf;
@@ -740,10 +732,10 @@ void RMGfxSourceBuffer8AB::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrim
// Passaggio normale
if (_bTrasp0) {
- for (y = 0; y < height; y++) {
+ for (int y = 0; y < height; y++) {
raw = _buf + (y + v) * _dimx + u;
- for (x = 0; x < width; x++) {
+ for (int x = 0; x < width; x++) {
if (*raw)
*buf = calcTrasp(_palFinal[*raw], *buf);
@@ -754,10 +746,10 @@ void RMGfxSourceBuffer8AB::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrim
buf += bufx - width;
}
} else {
- for (y = 0; y < height; y++) {
+ for (int y = 0; y < height; y++) {
raw = _buf + (y + v) * _dimx + u;
- for (x = 0; x < width; x += 2) {
+ for (int x = 0; x < width; x += 2) {
buf[0] = calcTrasp(_palFinal[raw[0]], buf[0]);
buf[1] = calcTrasp(_palFinal[raw[1]], buf[1]);
@@ -809,9 +801,7 @@ void RMGfxSourceBuffer8RLE::init(Common::ReadStream &ds, int dimx, int dimy, boo
if (_bNeedRLECompress) {
RMGfxSourceBufferPal::init(ds, dimx, dimy, bLoadPalette);
} else {
- int size;
-
- size = ds.readSint32LE();
+ int size = ds.readSint32LE();
_buf = new byte[size];
ds.read(_buf, size);
@@ -845,7 +835,6 @@ void RMGfxSourceBuffer8RLE::setAlreadyCompressed() {
}
void RMGfxSourceBuffer8RLE::compressRLE() {
- int x, y;
byte *startline;
byte *cur;
byte curdata;
@@ -856,7 +845,7 @@ void RMGfxSourceBuffer8RLE::compressRLE() {
// Perform RLE compression for lines
cur = _megaRLEBuf;
src = _buf;
- for (y = 0; y < _dimy; y++) {
+ for (int y = 0; y < _dimy; y++) {
// Save the beginning of the line
startline = cur;
@@ -867,7 +856,7 @@ void RMGfxSourceBuffer8RLE::compressRLE() {
curdata = 0;
rep = 0;
startsrc = src;
- for (x = 0; x < _dimx;) {
+ for (int x = 0; x < _dimx;) {
if ((curdata == 0 && *src == 0) || (curdata == 1 && *src == _alphaBlendColor)
|| (curdata == 2 && (*src != _alphaBlendColor && *src != 0))) {
src++;
@@ -875,13 +864,13 @@ void RMGfxSourceBuffer8RLE::compressRLE() {
x++;
} else {
if (curdata == 0) {
- RLEWriteTrasp(cur, rep);
+ rleWriteTrasp(cur, rep);
curdata++;
} else if (curdata == 1) {
- RLEWriteAlphaBlend(cur, rep);
+ rleWriteAlphaBlend(cur, rep);
curdata++;
} else {
- RLEWriteData(cur, rep, startsrc);
+ rleWriteData(cur, rep, startsrc);
curdata = 0;
}
@@ -892,16 +881,16 @@ void RMGfxSourceBuffer8RLE::compressRLE() {
// Pending data?
if (curdata == 1) {
- RLEWriteAlphaBlend(cur, rep);
- RLEWriteData(cur, 0, NULL);
+ rleWriteAlphaBlend(cur, rep);
+ rleWriteData(cur, 0, NULL);
}
if (curdata == 2) {
- RLEWriteData(cur, rep, startsrc);
+ rleWriteData(cur, rep, startsrc);
}
// End of line
- RLEWriteEOL(cur);
+ rleWriteEOL(cur);
// Write the length of the line
WRITE_LE_UINT16(startline, (uint16)(cur - startline));
@@ -911,26 +900,25 @@ void RMGfxSourceBuffer8RLE::compressRLE() {
delete[] _buf;
// Copy the compressed image
- x = cur - _megaRLEBuf;
- _buf = new byte[x];
- Common::copy(_megaRLEBuf, _megaRLEBuf + x, _buf);
+ int bufSize = cur - _megaRLEBuf;
+ _buf = new byte[bufSize];
+ Common::copy(_megaRLEBuf, _megaRLEBuf + bufSize, _buf);
}
void RMGfxSourceBuffer8RLE::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
- int y;
byte *src;
uint16 *buf = bigBuf;
- int x1, y1, u, v, width, height;
+ int u, v, width, height;
// Clipping
- x1 = prim->getDst()._x1;
- y1 = prim->getDst()._y1;
+ int x1 = prim->getDst()._x1;
+ int y1 = prim->getDst()._y1;
if (!clip2D(x1, y1, u, v, width, height, false, &bigBuf))
return;
// Go forward through the RLE lines
src = _buf;
- for (y = 0; y < v; y++)
+ for (int y = 0; y < v; y++)
src += READ_LE_UINT16(src);
// Calculate the position in the destination buffer
@@ -952,9 +940,9 @@ void RMGfxSourceBuffer8RLE::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPri
// Specify the drawn area
bigBuf.addDirtyRect(Common::Rect(x1 - width, y1, x1 + 1, y1 + height));
- for (y = 0; y < height; y++) {
+ for (int y = 0; y < height; y++) {
// Decompression
- RLEDecompressLineFlipped(buf + x1, src + 2, u, width);
+ rleDecompressLineFlipped(buf + x1, src + 2, u, width);
// Next line
src += READ_LE_UINT16(src);
@@ -966,9 +954,9 @@ void RMGfxSourceBuffer8RLE::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPri
// Specify the drawn area
bigBuf.addDirtyRect(Common::Rect(x1, y1, x1 + width, y1 + height));
- for (y = 0; y < height; y++) {
+ for (int y = 0; y < height; y++) {
// Decompression
- RLEDecompressLine(buf + x1, src + 2, u, width);
+ rleDecompressLine(buf + x1, src + 2, u, width);
// Next line
src += READ_LE_UINT16(src);
@@ -985,20 +973,19 @@ void RMGfxSourceBuffer8RLE::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPri
\****************************************************************************/
RMGfxSourceBuffer8RLEByte::~RMGfxSourceBuffer8RLEByte() {
-
}
-void RMGfxSourceBuffer8RLEByte::RLEWriteTrasp(byte *&cur, int rep) {
+void RMGfxSourceBuffer8RLEByte::rleWriteTrasp(byte *&cur, int rep) {
assert(rep < 255);
*cur ++ = rep;
}
-void RMGfxSourceBuffer8RLEByte::RLEWriteAlphaBlend(byte *&cur, int rep) {
+void RMGfxSourceBuffer8RLEByte::rleWriteAlphaBlend(byte *&cur, int rep) {
assert(rep < 255);
*cur ++ = rep;
}
-void RMGfxSourceBuffer8RLEByte::RLEWriteData(byte *&cur, int rep, byte *src) {
+void RMGfxSourceBuffer8RLEByte::rleWriteData(byte *&cur, int rep, byte *src) {
assert(rep < 256);
*cur ++ = rep;
@@ -1011,13 +998,12 @@ void RMGfxSourceBuffer8RLEByte::RLEWriteData(byte *&cur, int rep, byte *src) {
return;
}
-void RMGfxSourceBuffer8RLEByte::RLEWriteEOL(byte *&cur) {
+void RMGfxSourceBuffer8RLEByte::rleWriteEOL(byte *&cur) {
*cur ++ = 0xFF;
}
-void RMGfxSourceBuffer8RLEByte::RLEDecompressLine(uint16 *dst, byte *src, int nStartSkip, int nLength) {
- int i, n;
- int r, g, b;
+void RMGfxSourceBuffer8RLEByte::rleDecompressLine(uint16 *dst, byte *src, int nStartSkip, int nLength) {
+ int n;
if (nStartSkip == 0)
goto RLEByteDoTrasp;
@@ -1086,10 +1072,10 @@ RLEByteDoAlpha:
RLEByteDoAlpha2:
if (n > nLength)
n = nLength;
- for (i = 0; i < n; i++) {
- r = (*dst >> 10) & 0x1F;
- g = (*dst >> 5) & 0x1F;
- b = *dst & 0x1F;
+ for (int i = 0; i < n; i++) {
+ int r = (*dst >> 10) & 0x1F;
+ int g = (*dst >> 5) & 0x1F;
+ int b = *dst & 0x1F;
r = (r >> 2) + (_alphaR >> 1);
g = (g >> 2) + (_alphaG >> 1);
@@ -1111,7 +1097,7 @@ RLEByteDoCopy2:
if (n > nLength)
n = nLength;
- for (i = 0; i < n; i++)
+ for (int i = 0; i < n; i++)
*dst ++ = _palFinal[*src++];
nLength -= n;
@@ -1121,9 +1107,8 @@ RLEByteDoCopy2:
}
}
-void RMGfxSourceBuffer8RLEByte::RLEDecompressLineFlipped(uint16 *dst, byte *src, int nStartSkip, int nLength) {
- int i, n;
- int r, g, b;
+void RMGfxSourceBuffer8RLEByte::rleDecompressLineFlipped(uint16 *dst, byte *src, int nStartSkip, int nLength) {
+ int n;
if (nStartSkip == 0)
goto RLEByteFlippedDoTrasp;
@@ -1192,10 +1177,10 @@ RLEByteFlippedDoAlpha:
RLEByteFlippedDoAlpha2:
if (n > nLength)
n = nLength;
- for (i = 0; i < n; i++) {
- r = (*dst >> 10) & 0x1F;
- g = (*dst >> 5) & 0x1F;
- b = *dst & 0x1F;
+ for (int i = 0; i < n; i++) {
+ int r = (*dst >> 10) & 0x1F;
+ int g = (*dst >> 5) & 0x1F;
+ int b = *dst & 0x1F;
r = (r >> 2) + (_alphaR >> 1);
g = (g >> 2) + (_alphaG >> 1);
@@ -1217,7 +1202,7 @@ RLEByteFlippedDoCopy2:
if (n > nLength)
n = nLength;
- for (i = 0; i < n; i++)
+ for (int i = 0; i < n; i++)
*dst-- = _palFinal[*src++];
nLength -= n;
@@ -1236,17 +1221,17 @@ RMGfxSourceBuffer8RLEWord::~RMGfxSourceBuffer8RLEWord() {
}
-void RMGfxSourceBuffer8RLEWord::RLEWriteTrasp(byte *&cur, int rep) {
+void RMGfxSourceBuffer8RLEWord::rleWriteTrasp(byte *&cur, int rep) {
WRITE_LE_UINT16(cur, rep);
cur += 2;
}
-void RMGfxSourceBuffer8RLEWord::RLEWriteAlphaBlend(byte *&cur, int rep) {
+void RMGfxSourceBuffer8RLEWord::rleWriteAlphaBlend(byte *&cur, int rep) {
WRITE_LE_UINT16(cur, rep);
cur += 2;
}
-void RMGfxSourceBuffer8RLEWord::RLEWriteData(byte *&cur, int rep, byte *src) {
+void RMGfxSourceBuffer8RLEWord::rleWriteData(byte *&cur, int rep, byte *src) {
WRITE_LE_UINT16(cur, rep);
cur += 2;
@@ -1257,14 +1242,13 @@ void RMGfxSourceBuffer8RLEWord::RLEWriteData(byte *&cur, int rep, byte *src) {
}
}
-void RMGfxSourceBuffer8RLEWord::RLEWriteEOL(byte *&cur) {
+void RMGfxSourceBuffer8RLEWord::rleWriteEOL(byte *&cur) {
*cur ++ = 0xFF;
*cur ++ = 0xFF;
}
-void RMGfxSourceBuffer8RLEWord::RLEDecompressLine(uint16 *dst, byte *src, int nStartSkip, int nLength) {
- int i, n;
- int r, g, b;
+void RMGfxSourceBuffer8RLEWord::rleDecompressLine(uint16 *dst, byte *src, int nStartSkip, int nLength) {
+ int n;
if (nStartSkip == 0)
goto RLEWordDoTrasp;
@@ -1341,10 +1325,10 @@ RLEWordDoAlpha2:
if (n > nLength)
n = nLength;
- for (i = 0; i < n; i++) {
- r = (*dst >> 10) & 0x1F;
- g = (*dst >> 5) & 0x1F;
- b = *dst & 0x1F;
+ for (int i = 0; i < n; i++) {
+ int r = (*dst >> 10) & 0x1F;
+ int g = (*dst >> 5) & 0x1F;
+ int b = *dst & 0x1F;
r = (r >> 2) + (_alphaR >> 1);
g = (g >> 2) + (_alphaG >> 1);
@@ -1368,7 +1352,7 @@ RLEWordDoCopy2:
if (n > nLength)
n = nLength;
- for (i = 0; i < n; i++)
+ for (int i = 0; i < n; i++)
*dst++ = _palFinal[*src++];
nLength -= n;
@@ -1380,9 +1364,8 @@ RLEWordDoCopy2:
}
}
-void RMGfxSourceBuffer8RLEWord::RLEDecompressLineFlipped(uint16 *dst, byte *src, int nStartSkip, int nLength) {
- int i, n;
- int r, g, b;
+void RMGfxSourceBuffer8RLEWord::rleDecompressLineFlipped(uint16 *dst, byte *src, int nStartSkip, int nLength) {
+ int n;
if (nStartSkip == 0)
goto RLEWordFlippedDoTrasp;
@@ -1459,10 +1442,10 @@ RLEWordFlippedDoAlpha2:
if (n > nLength)
n = nLength;
- for (i = 0; i < n; i++) {
- r = (*dst >> 10) & 0x1F;
- g = (*dst >> 5) & 0x1F;
- b = *dst & 0x1F;
+ for (int i = 0; i < n; i++) {
+ int r = (*dst >> 10) & 0x1F;
+ int g = (*dst >> 5) & 0x1F;
+ int b = *dst & 0x1F;
r = (r >> 2) + (_alphaR >> 1);
g = (g >> 2) + (_alphaG >> 1);
@@ -1486,7 +1469,7 @@ RLEWordFlippedDoCopy2:
if (n > nLength)
n = nLength;
- for (i = 0; i < n; i++)
+ for (int i = 0; i < n; i++)
*dst-- = _palFinal[*src++];
nLength -= n;
@@ -1505,12 +1488,11 @@ RMGfxSourceBuffer8RLEWordAB::~RMGfxSourceBuffer8RLEWordAB() {
}
-void RMGfxSourceBuffer8RLEWordAB::RLEDecompressLine(uint16 *dst, byte *src, int nStartSkip, int nLength) {
- int i, n;
- int r, g, b, r2, g2, b2;
+void RMGfxSourceBuffer8RLEWordAB::rleDecompressLine(uint16 *dst, byte *src, int nStartSkip, int nLength) {
+ int n;
if (!GLOBALS._bCfgTransparence) {
- RMGfxSourceBuffer8RLEWord::RLEDecompressLine(dst, src, nStartSkip, nLength);
+ RMGfxSourceBuffer8RLEWord::rleDecompressLine(dst, src, nStartSkip, nLength);
return;
}
@@ -1590,10 +1572,10 @@ RLEWordDoAlpha2:
n = nLength;
// @@@ SHOULD NOT BE THERE !!!!!
- for (i = 0; i < n; i++) {
- r = (*dst >> 10) & 0x1F;
- g = (*dst >> 5) & 0x1F;
- b = *dst & 0x1F;
+ for (int i = 0; i < n; i++) {
+ int r = (*dst >> 10) & 0x1F;
+ int g = (*dst >> 5) & 0x1F;
+ int b = *dst & 0x1F;
r = (r >> 2) + (_alphaR >> 1);
g = (g >> 2) + (_alphaG >> 1);
@@ -1617,14 +1599,14 @@ RLEWordDoCopy2:
if (n > nLength)
n = nLength;
- for (i = 0; i < n; i++) {
- r = (*dst >> 10) & 0x1F;
- g = (*dst >> 5) & 0x1F;
- b = *dst & 0x1F;
+ for (int i = 0; i < n; i++) {
+ int r = (*dst >> 10) & 0x1F;
+ int g = (*dst >> 5) & 0x1F;
+ int b = *dst & 0x1F;
- r2 = (_palFinal[*src] >> 10) & 0x1F;
- g2 = (_palFinal[*src] >> 5) & 0x1F;
- b2 = _palFinal[*src] & 0x1F;
+ int r2 = (_palFinal[*src] >> 10) & 0x1F;
+ int g2 = (_palFinal[*src] >> 5) & 0x1F;
+ int b2 = _palFinal[*src] & 0x1F;
r = (r >> 1) + (r2 >> 1);
g = (g >> 1) + (g2 >> 1);
@@ -1658,7 +1640,6 @@ void RMGfxSourceBuffer8AA::prepareImage() {
}
void RMGfxSourceBuffer8AA::calculateAA() {
- int x, y;
byte *src, *srcaa;
// First pass: fill the edges
@@ -1666,8 +1647,8 @@ void RMGfxSourceBuffer8AA::calculateAA() {
src = _buf;
srcaa = _megaAABuf;
- for (y = 0; y < _dimy; y++) {
- for (x = 0; x < _dimx; x++) {
+ for (int y = 0; y < _dimy; y++) {
+ for (int x = 0; x < _dimx; x++) {
if (*src == 0) {
if ((y > 0 && src[-_dimx] != 0) ||
(y < _dimy - 1 && src[_dimx] != 0) ||
@@ -1683,8 +1664,8 @@ void RMGfxSourceBuffer8AA::calculateAA() {
src = _buf;
srcaa = _megaAABuf;
- for (y = 0; y < _dimy; y++) {
- for (x = 0; x < _dimx; x++) {
+ for (int y = 0; y < _dimy; y++) {
+ for (int x = 0; x < _dimx; x++) {
if (*src != 0) {
if ((y > 0 && srcaa[-_dimx] == 1) ||
(y < _dimy - 1 && srcaa[_dimx] == 1) ||
@@ -1715,23 +1696,20 @@ RMGfxSourceBuffer8AA::~RMGfxSourceBuffer8AA() {
}
void RMGfxSourceBuffer8AA::drawAA(RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
- int x, y;
byte *src;
uint16 *mybuf;
uint16 *buf;
- int x1, y1, u, v, width, height;
- int r, g, b;
- int step;
+ int u, v, width, height;
// Clip the sprite
- x1 = prim->getDst()._x1;
- y1 = prim->getDst()._y1;
+ int x1 = prim->getDst()._x1;
+ int y1 = prim->getDst()._y1;
if (!clip2D(x1, y1, u, v, width, height, false, &bigBuf))
return;
// Go forward through the RLE lines
src = _buf;
- for (y = 0; y < v; y++)
+ for (int y = 0; y < v; y++)
src += READ_LE_UINT16(src);
// Eliminate horizontal clipping
@@ -1758,6 +1736,7 @@ void RMGfxSourceBuffer8AA::drawAA(RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *pri
buf = bigBuf;
buf += y1 * bigBuf.getDimx();
+ int step;
if (prim->isFlipped())
step = -1;
else
@@ -1765,17 +1744,17 @@ void RMGfxSourceBuffer8AA::drawAA(RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *pri
// Loop
buf += bigBuf.getDimx(); // Skip the first line
- for (y = 1; y < height - 1; y++) {
+ for (int y = 1; y < height - 1; y++) {
// if (prim->IsFlipped())
// mybuf=&buf[x1+m_dimx-1];
// else
mybuf = &buf[x1];
- for (x = 0; x < width; x++, mybuf += step) {
+ for (int x = 0; x < width; x++, mybuf += step) {
if (_aabuf[(y + v) * _dimx + x + u] == 2 && x != 0 && x != width - 1) {
- r = GETRED(mybuf[1]) + GETRED(mybuf[-1]) + GETRED(mybuf[-bigBuf.getDimx()]) + GETRED(mybuf[bigBuf.getDimx()]);
- g = GETGREEN(mybuf[1]) + GETGREEN(mybuf[-1]) + GETGREEN(mybuf[-bigBuf.getDimx()]) + GETGREEN(mybuf[bigBuf.getDimx()]);
- b = GETBLUE(mybuf[1]) + GETBLUE(mybuf[-1]) + GETBLUE(mybuf[-bigBuf.getDimx()]) + GETBLUE(mybuf[bigBuf.getDimx()]);
+ int r = GETRED(mybuf[1]) + GETRED(mybuf[-1]) + GETRED(mybuf[-bigBuf.getDimx()]) + GETRED(mybuf[bigBuf.getDimx()]);
+ int g = GETGREEN(mybuf[1]) + GETGREEN(mybuf[-1]) + GETGREEN(mybuf[-bigBuf.getDimx()]) + GETGREEN(mybuf[bigBuf.getDimx()]);
+ int b = GETBLUE(mybuf[1]) + GETBLUE(mybuf[-1]) + GETBLUE(mybuf[-bigBuf.getDimx()]) + GETBLUE(mybuf[bigBuf.getDimx()]);
r += GETRED(mybuf[0]);
g += GETGREEN(mybuf[0]);
@@ -1785,9 +1764,12 @@ void RMGfxSourceBuffer8AA::drawAA(RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *pri
g /= 5;
b /= 5;
- if (r > 31) r = 31;
- if (g > 31) g = 31;
- if (b > 31) b = 31;
+ if (r > 31)
+ r = 31;
+ if (g > 31)
+ g = 31;
+ if (b > 31)
+ b = 31;
mybuf[0] = (r << 10) | (g << 5) | b;
}
@@ -1803,17 +1785,17 @@ void RMGfxSourceBuffer8AA::drawAA(RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *pri
// Looppone
buf += bigBuf.getDimx();
- for (y = 1; y < height - 1; y++) {
+ for (int y = 1; y < height - 1; y++) {
// if (prim->IsFlipped())
// mybuf=&buf[x1+m_dimx-1];
// else
mybuf = &buf[x1];
- for (x = 0; x < width; x++, mybuf += step) {
+ for (int x = 0; x < width; x++, mybuf += step) {
if (_aabuf[(y + v) * _dimx + x + u] == 1 && x != 0 && x != width - 1) {
- r = GETRED(mybuf[1]) + GETRED(mybuf[-1]) + GETRED(mybuf[-bigBuf.getDimx()]) + GETRED(mybuf[bigBuf.getDimx()]);
- g = GETGREEN(mybuf[1]) + GETGREEN(mybuf[-1]) + GETGREEN(mybuf[-bigBuf.getDimx()]) + GETGREEN(mybuf[bigBuf.getDimx()]);
- b = GETBLUE(mybuf[1]) + GETBLUE(mybuf[-1]) + GETBLUE(mybuf[-bigBuf.getDimx()]) + GETBLUE(mybuf[bigBuf.getDimx()]);
+ int r = GETRED(mybuf[1]) + GETRED(mybuf[-1]) + GETRED(mybuf[-bigBuf.getDimx()]) + GETRED(mybuf[bigBuf.getDimx()]);
+ int g = GETGREEN(mybuf[1]) + GETGREEN(mybuf[-1]) + GETGREEN(mybuf[-bigBuf.getDimx()]) + GETGREEN(mybuf[bigBuf.getDimx()]);
+ int b = GETBLUE(mybuf[1]) + GETBLUE(mybuf[-1]) + GETBLUE(mybuf[-bigBuf.getDimx()]) + GETBLUE(mybuf[bigBuf.getDimx()]);
r += GETRED(mybuf[0]) * 2;
g += GETGREEN(mybuf[0]) * 2;
@@ -1823,9 +1805,12 @@ void RMGfxSourceBuffer8AA::drawAA(RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *pri
g /= 6;
b /= 6;
- if (r > 31) r = 31;
- if (g > 31) g = 31;
- if (b > 31) b = 31;
+ if (r > 31)
+ r = 31;
+ if (g > 31)
+ g = 31;
+ if (b > 31)
+ b = 31;
mybuf[0] = (r << 10) | (g << 5) | b;
}
@@ -1941,16 +1926,13 @@ RMGfxSourceBuffer16::~RMGfxSourceBuffer16() {
void RMGfxSourceBuffer16::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
uint16 *buf = bigBuf;
uint16 *raw = (uint16 *)_buf;
- int dimx, dimy;
- int u, v;
- int x1, y1;
- dimx = _dimx;
- dimy = _dimy;
- u = 0;
- v = 0;
- x1 = 0;
- y1 = 0;
+ int dimx = _dimx;
+ int dimy = _dimy;
+ int u = 0;
+ int v = 0;
+ int x1 = 0;
+ int y1 = 0;
if (prim->haveSrc()) {
u = prim->getSrc()._x1;
@@ -1999,10 +1981,9 @@ void RMGfxSourceBuffer16::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimi
void RMGfxSourceBuffer16::prepareImage() {
// Color space conversion if necessary!
- int i;
uint16 *buf = (uint16 *)_buf;
- for (i = 0; i < _dimx * _dimy; i++)
+ for (int i = 0; i < _dimx * _dimy; i++)
WRITE_LE_UINT16(&buf[i], FROM_LE_16(buf[i]) & 0x7FFF);
}
@@ -2041,7 +2022,6 @@ void RMGfxBox::setColor(byte r, byte g, byte b) {
}
void RMGfxBox::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
- int i, j;
uint16 *buf = bigBuf;
RMRect rcDst;
@@ -2050,8 +2030,8 @@ void RMGfxBox::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim)
buf += rcDst._y1 * bigBuf.getDimx() + rcDst._x1;
// Loop through the pixels
- for (j = 0; j < rcDst.height(); j++) {
- for (i = 0; i < rcDst.width(); i++)
+ for (int j = 0; j < rcDst.height(); j++) {
+ for (int i = 0; i < rcDst.width(); i++)
*buf++ = _wFillColor;
buf += bigBuf.getDimx() - rcDst.width();
diff --git a/engines/tony/gfxcore.h b/engines/tony/gfxcore.h
index ac4eee05e4..f0deed83ee 100644
--- a/engines/tony/gfxcore.h
+++ b/engines/tony/gfxcore.h
@@ -146,7 +146,7 @@ public:
// Registration
virtual void Register();
- virtual void Unregister();
+ virtual void unregister();
};
@@ -303,12 +303,12 @@ protected:
protected:
static byte _megaRLEBuf[];
- virtual void RLEWriteTrasp(byte *&cur, int rep) = 0;
- virtual void RLEWriteData(byte *&cur, int rep, byte *src) = 0;
- virtual void RLEWriteEOL(byte *&cur) = 0;
- virtual void RLEWriteAlphaBlend(byte *&cur, int rep) = 0;
- virtual void RLEDecompressLine(uint16 *dst, byte *src, int nStartSkip, int nLength) = 0;
- virtual void RLEDecompressLineFlipped(uint16 *dst, byte *src, int nStartSkip, int nLength) = 0;
+ virtual void rleWriteTrasp(byte *&cur, int rep) = 0;
+ virtual void rleWriteData(byte *&cur, int rep, byte *src) = 0;
+ virtual void rleWriteEOL(byte *&cur) = 0;
+ virtual void rleWriteAlphaBlend(byte *&cur, int rep) = 0;
+ virtual void rleDecompressLine(uint16 *dst, byte *src, int nStartSkip, int nLength) = 0;
+ virtual void rleDecompressLineFlipped(uint16 *dst, byte *src, int nStartSkip, int nLength) = 0;
// Perform image compression in RLE
void compressRLE();
@@ -338,12 +338,12 @@ public:
class RMGfxSourceBuffer8RLEByte : public RMGfxSourceBuffer8RLE {
protected:
- void RLEWriteTrasp(byte * &cur, int rep);
- void RLEWriteAlphaBlend(byte * &cur, int rep);
- void RLEWriteData(byte * &cur, int rep, byte *src);
- void RLEWriteEOL(byte * &cur);
- void RLEDecompressLine(uint16 *dst, byte *src, int nStartSkip, int nLength);
- void RLEDecompressLineFlipped(uint16 *dst, byte *src, int nStartSkip, int nLength);
+ void rleWriteTrasp(byte * &cur, int rep);
+ void rleWriteAlphaBlend(byte * &cur, int rep);
+ void rleWriteData(byte * &cur, int rep, byte *src);
+ void rleWriteEOL(byte * &cur);
+ void rleDecompressLine(uint16 *dst, byte *src, int nStartSkip, int nLength);
+ void rleDecompressLineFlipped(uint16 *dst, byte *src, int nStartSkip, int nLength);
public:
virtual ~RMGfxSourceBuffer8RLEByte();
@@ -351,12 +351,12 @@ public:
class RMGfxSourceBuffer8RLEWord : public RMGfxSourceBuffer8RLE {
protected:
- void RLEWriteTrasp(byte * &cur, int rep);
- void RLEWriteAlphaBlend(byte * &cur, int rep);
- void RLEWriteData(byte * &cur, int rep, byte *src);
- void RLEWriteEOL(byte * &cur);
- virtual void RLEDecompressLine(uint16 *dst, byte *src, int nStartSkip, int nLength);
- virtual void RLEDecompressLineFlipped(uint16 *dst, byte *src, int nStartSkip, int nLength);
+ void rleWriteTrasp(byte * &cur, int rep);
+ void rleWriteAlphaBlend(byte * &cur, int rep);
+ void rleWriteData(byte * &cur, int rep, byte *src);
+ void rleWriteEOL(byte * &cur);
+ virtual void rleDecompressLine(uint16 *dst, byte *src, int nStartSkip, int nLength);
+ virtual void rleDecompressLineFlipped(uint16 *dst, byte *src, int nStartSkip, int nLength);
public:
virtual ~RMGfxSourceBuffer8RLEWord();
@@ -364,7 +364,7 @@ public:
class RMGfxSourceBuffer8RLEWordAB : public RMGfxSourceBuffer8RLEWord {
protected:
- virtual void RLEDecompressLine(uint16 *dst, byte *src, int nStartSkip, int nLength);
+ virtual void rleDecompressLine(uint16 *dst, byte *src, int nStartSkip, int nLength);
public:
virtual ~RMGfxSourceBuffer8RLEWordAB();
diff --git a/engines/tony/gfxengine.cpp b/engines/tony/gfxengine.cpp
index 5c038e154d..c81e553770 100644
--- a/engines/tony/gfxengine.cpp
+++ b/engines/tony/gfxengine.cpp
@@ -40,7 +40,7 @@ namespace Tony {
* RMGfxEngine Methods
\****************************************************************************/
-void ExitAllIdles(CORO_PARAM, const void *param) {
+void exitAllIdles(CORO_PARAM, const void *param) {
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
@@ -129,7 +129,7 @@ void RMGfxEngine::openOptionScreen(CORO_PARAM, int type) {
GLOBALS._bIdleExited = false;
- CoroScheduler.createProcess(ExitAllIdles, &_nCurLoc, sizeof(int));
+ CoroScheduler.createProcess(exitAllIdles, &_nCurLoc, sizeof(int));
}
}
@@ -394,13 +394,10 @@ void RMGfxEngine::initForNewLocation(int nLoc, RMPoint ptTonyStart, RMPoint star
}
uint32 RMGfxEngine::loadLocation(int nLoc, RMPoint ptTonyStart, RMPoint start) {
- bool bLoaded;
- int i;
-
_nCurLoc = nLoc;
- bLoaded = false;
- for (i = 0; i < 5; i++) {
+ bool bLoaded = false;
+ for (int i = 0; i < 5; i++) {
// Try the loading of the location
RMRes res(_nCurLoc);
if (!res.isValid())
@@ -532,36 +529,22 @@ void RMGfxEngine::disableMouse() {
_bAlwaysDrawMouse = false;
}
-void CharsSaveAll(Common::OutSaveFile *f);
-void CharsLoadAll(Common::InSaveFile *f);
-void MCharResetCodes();
-void SaveChangedHotspot(Common::OutSaveFile *f);
-void LoadChangedHotspot(Common::InSaveFile *f);
-void ReapplyChangedHotspot();
-
-void RestoreMusic(CORO_PARAM);
-void SaveMusic(Common::OutSaveFile *f);
-void LoadMusic(Common::InSaveFile *f);
-
#define TONY_SAVEGAME_VERSION 8
void RMGfxEngine::saveState(const Common::String &fn, byte *curThumb, const Common::String &name) {
Common::OutSaveFile *f;
byte *state;
- uint thumbsize;
- uint size;
- int i;
char buf[4];
RMPoint tp = _tony.position();
// Saving: MPAL variables, current location, and Tony inventory position
// For now, we only save the MPAL state
- size = mpalGetSaveStateSize();
+ uint size = mpalGetSaveStateSize();
state = new byte[size];
mpalSaveState(state);
- thumbsize = 160 * 120 * 2;
+ uint thumbsize = 160 * 120 * 2;
buf[0] = 'R';
buf[1] = 'M';
@@ -577,7 +560,7 @@ void RMGfxEngine::saveState(const Common::String &fn, byte *curThumb, const Comm
f->write(curThumb, thumbsize);
// Difficulty level
- i = mpalQueryGlobalVar("VERSIONEFACILE");
+ int i = mpalQueryGlobalVar("VERSIONEFACILE");
f->writeByte(i);
i = strlen(name.c_str());
@@ -608,16 +591,14 @@ void RMGfxEngine::saveState(const Common::String &fn, byte *curThumb, const Comm
delete[] state;
// New Ver5
- bool bStat;
-
// Saves the state of the shepherdess and show yourself
- bStat = _tony.getShepherdess();
+ bool bStat = _tony.getShepherdess();
f->writeByte(bStat);
bStat = _inter.getPerorate();
f->writeByte(bStat);
// Save the chars
- CharsSaveAll(f);
+ charsSaveAll(f);
// Save the options
f->writeByte(GLOBALS._bCfgInvLocked);
@@ -639,10 +620,10 @@ void RMGfxEngine::saveState(const Common::String &fn, byte *curThumb, const Comm
f->writeByte(GLOBALS._nCfgSFXVolume);
// Save the hotspots
- SaveChangedHotspot(f);
+ saveChangedHotspot(f);
// Save the music
- SaveMusic(f);
+ saveMusic(f);
f->finalize();
delete f;
@@ -653,7 +634,7 @@ void RMGfxEngine::loadState(CORO_PARAM, const Common::String &fn) {
CORO_BEGIN_CONTEXT;
Common::InSaveFile *f;
byte *state, *statecmp;
- uint size, sizecmp;
+ uint32 size, sizecmp;
char buf[4];
RMPoint tp;
int loc;
@@ -734,7 +715,7 @@ void RMGfxEngine::loadState(CORO_PARAM, const Common::String &fn) {
_inv.loadState(_ctx->state);
delete[] _ctx->state;
- if (_ctx->ver >= 0x2) { // Versione 2: box please
+ if (_ctx->ver >= 0x2) { // Version 2: box please
_ctx->size = _ctx->f->readUint32LE();
_ctx->state = new byte[_ctx->size];
_ctx->f->read(_ctx->state, _ctx->size);
@@ -743,7 +724,7 @@ void RMGfxEngine::loadState(CORO_PARAM, const Common::String &fn) {
}
if (_ctx->ver >= 5) {
- // Versione 5
+ // Version 5
bool bStat = false;
bStat = _ctx->f->readByte();
@@ -751,7 +732,7 @@ void RMGfxEngine::loadState(CORO_PARAM, const Common::String &fn) {
bStat = _ctx->f->readByte();
_inter.setPerorate(bStat);
- CharsLoadAll(_ctx->f);
+ charsLoadAll(_ctx->f);
}
if (_ctx->ver >= 6) {
@@ -775,11 +756,11 @@ void RMGfxEngine::loadState(CORO_PARAM, const Common::String &fn) {
GLOBALS._nCfgSFXVolume = _ctx->f->readByte();
// Load hotspots
- LoadChangedHotspot(_ctx->f);
+ loadChangedHotspot(_ctx->f);
}
if (_ctx->ver >= 7) {
- LoadMusic(_ctx->f);
+ loadMusic(_ctx->f);
}
delete _ctx->f;
@@ -793,13 +774,13 @@ void RMGfxEngine::loadState(CORO_PARAM, const Common::String &fn) {
mpalQueryDoAction(0, _ctx->loc, 0);
else {
// In the new ones, we just reset the mcode
- MCharResetCodes();
+ mCharResetCodes();
}
if (_ctx->ver >= 6)
- ReapplyChangedHotspot();
+ reapplyChangedHotspot();
- CORO_INVOKE_0(RestoreMusic);
+ CORO_INVOKE_0(restoreMusic);
_bGUIInterface = true;
_bGUIInventory = true;
diff --git a/engines/tony/inventory.cpp b/engines/tony/inventory.cpp
index 81d62a035c..12540e5b7f 100644
--- a/engines/tony/inventory.cpp
+++ b/engines/tony/inventory.cpp
@@ -73,9 +73,6 @@ bool RMInventory::checkPointInside(const RMPoint &pt) {
void RMInventory::init() {
- int i, j;
- int curres;
-
// Create the main buffer
create(RM_SX, 68);
setPriority(185);
@@ -89,10 +86,10 @@ void RMInventory::init() {
_nItems = 78; // @@@ Number of takeable items
_items = new RMInventoryItem[_nItems + 1];
- curres = 10500;
+ int curres = 10500;
// Loop through the items
- for (i = 0; i <= _nItems; i++) {
+ for (int i = 0; i <= _nItems; i++) {
// Load the items from the resource
RMRes res(curres);
assert(res.isValid());
@@ -115,7 +112,7 @@ void RMInventory::init() {
_items[i]._pointer = new RMGfxSourceBuffer8RLEByteAA[_items[i]._icon.numPattern()];
- for (j = 0; j < _items[i]._icon.numPattern(); j++) {
+ for (int j = 0; j < _items[i]._icon.numPattern(); j++) {
RMResRaw raw(curres);
assert(raw.isValid());
@@ -232,9 +229,7 @@ void RMInventory::removeThis(CORO_PARAM, bool &result) {
}
void RMInventory::removeItem(int code) {
- int i;
-
- for (i = 0; i < _nInv; i++)
+ for (int i = 0; i < _nInv; i++) {
if (_inv[i] == code - 10000) {
g_system->lockMutex(_csModifyInterface);
@@ -247,6 +242,7 @@ void RMInventory::removeItem(int code) {
g_system->unlockMutex(_csModifyInterface);
return;
}
+ }
}
void RMInventory::addItem(int code) {
@@ -286,9 +282,7 @@ void RMInventory::changeItemStatus(uint32 code, uint32 dwStatus) {
void RMInventory::prepare() {
- int i;
-
- for (i = 1; i < RM_SX / 64 - 1; i++) {
+ for (int i = 1; i < RM_SX / 64 - 1; i++) {
if (i - 1 + _curPos < _nInv)
addPrim(new RMGfxPrimitive(&_items[_inv[i - 1 + _curPos]]._icon, RMPoint(i * 64, 0)));
else
@@ -325,10 +319,8 @@ void RMInventory::endCombine() {
}
bool RMInventory::leftClick(const RMPoint &mpos, int &nCombineObj) {
- int n;
-
// The left click picks an item from your inventory to use it with the background
- n = mpos._x / 64;
+ int n = mpos._x / 64;
if (_state == OPENED) {
if (n > 0 && n < RM_SX / 64 - 1 && _inv[n - 1 + _curPos] != 0) {
@@ -679,18 +671,17 @@ RMItem *RMInventory::whichItemIsIn(const RMPoint &mpt) {
int RMInventory::getSaveStateSize() {
// m_inv pattern m_nInv
- return 256 * 4 + 256 * 4 + 4 ;
+ return 256 * 4 + 256 * 4 + 4;
}
void RMInventory::saveState(byte *state) {
- int i, x;
-
WRITE_LE_UINT32(state, _nInv);
state += 4;
Common::copy(_inv, _inv + 256, (uint32 *)state);
state += 256 * 4;
- for (i = 0; i < 256; i++) {
+ int x;
+ for (int i = 0; i < 256; i++) {
if (i < _nItems)
x = _items[i]._status;
else
@@ -702,14 +693,13 @@ void RMInventory::saveState(byte *state) {
}
int RMInventory::loadState(byte *state) {
- int i, x;
-
_nInv = READ_LE_UINT32(state);
state += 4;
Common::copy((uint32 *)state, (uint32 *)state + 256, _inv);
state += 256 * 4;
- for (i = 0; i < 256; i++) {
+ int x;
+ for (int i = 0; i < 256; i++) {
x = READ_LE_UINT32(state);
state += 4;
@@ -721,7 +711,7 @@ int RMInventory::loadState(byte *state) {
_curPos = 0;
_bCombining = false;
-
+
_items[29]._icon.setPattern(1);
if (_nInv > 8)
@@ -768,17 +758,15 @@ bool RMInterface::active() {
}
int RMInterface::onWhichBox(RMPoint pt) {
- int max, i;
-
pt -= _openStart;
// Check how many verbs you have to consider
- max = 4;
+ int max = 4;
if (_bPerorate)
max = 5;
// Find the verb
- for (i = 0; i < max; i++) {
+ for (int i = 0; i < max; i++) {
if (_hotbbox[i].ptInRect(pt))
return i;
}
@@ -895,7 +883,6 @@ bool RMInterface::getPerorate() {
}
void RMInterface::init() {
- int i;
RMResRaw inter(RES_I_INTERFACE);
RMRes pal(RES_I_INTERPPAL);
@@ -904,7 +891,7 @@ void RMInterface::init() {
RMGfxSourceBuffer::init(inter, inter.width(), inter.height());
loadPaletteWA(RES_I_INTERPAL);
- for (i = 0; i < 5; i++) {
+ for (int i = 0; i < 5; i++) {
RMResRaw part(RES_I_INTERP1 + i);
_hotzone[i].init(part, part.width(), part.height());
@@ -942,11 +929,9 @@ void RMInterface::init() {
}
void RMInterface::close() {
- int i;
-
destroy();
- for (i = 0; i < 5; i++)
+ for (int i = 0; i < 5; i++)
_hotzone[i].destroy();
}
diff --git a/engines/tony/loc.cpp b/engines/tony/loc.cpp
index 4fe19594f9..18470aa6fc 100644
--- a/engines/tony/loc.cpp
+++ b/engines/tony/loc.cpp
@@ -51,10 +51,8 @@ void RMPalette::readFromStream(Common::ReadStream &ds) {
\****************************************************************************/
void RMPattern::RMSlot::readFromStream(Common::ReadStream &ds, bool bLOX) {
- byte type;
-
// Type
- type = ds.readByte();
+ byte type = ds.readByte();
_type = (RMPattern::RMSlotType)type;
// Data
@@ -73,8 +71,6 @@ void RMPattern::RMSlot::readFromStream(Common::ReadStream &ds, bool bLOX) {
\****************************************************************************/
void RMPattern::readFromStream(Common::ReadStream &ds, bool bLOX) {
- int i;
-
// Pattern name
if (!bLOX)
_name = readString(ds);
@@ -94,7 +90,7 @@ void RMPattern::readFromStream(Common::ReadStream &ds, bool bLOX) {
// Create and read the slots
_slots = new RMSlot[_nSlots];
- for (i = 0; i < _nSlots && !ds.err(); i++) {
+ for (int i = 0; i < _nSlots && !ds.err(); i++) {
if (bLOX)
_slots[i].readFromStream(ds, true);
else
@@ -118,14 +114,12 @@ void RMPattern::stopSfx(RMSfx *sfx) {
}
int RMPattern::init(RMSfx *sfx, bool bPlayP0, byte *bFlag) {
- int i;
-
// Read the current time
_nStartTime = g_vm->getTime();
_nCurSlot = 0;
// Find the first frame of the pattern
- i = 0;
+ int i = 0;
while (_slots[i]._type != SPRITE) {
assert(i + 1 < _nSlots);
i++;
@@ -297,15 +291,13 @@ void RMSprite::getSizeFromStream(Common::SeekableReadStream &ds, int *dimx, int
}
void RMSprite::readFromStream(Common::SeekableReadStream &ds, bool bLOX) {
- int dimx, dimy;
-
// Sprite name
if (!bLOX)
_name = readString(ds);
// Dimensions
- dimx = ds.readSint32LE();
- dimy = ds.readSint32LE();
+ int dimx = ds.readSint32LE();
+ int dimy = ds.readSint32LE();
// Bounding box
_rcBox.readFromStream(ds);
@@ -343,12 +335,10 @@ RMSprite::~RMSprite() {
\****************************************************************************/
void RMSfx::readFromStream(Common::ReadStream &ds, bool bLOX) {
- int size;
-
// sfx name
_name = readString(ds);
- size = ds.readSint32LE();
+ int size = ds.readSint32LE();
// Read the entire buffer into a MemoryReadStream
byte *buffer = (byte *)malloc(size);
@@ -390,7 +380,7 @@ void RMSfx::setVolume(int vol) {
void RMSfx::pause(bool bPause) {
if (_fx) {
- _fx->pause(bPause);
+ _fx->setPause(bPause);
}
}
@@ -463,9 +453,6 @@ bool RMItem::isIn(const RMPoint &pt, int *size) {
}
void RMItem::readFromStream(Common::SeekableReadStream &ds, bool bLOX) {
- int i, dimx, dimy;
- byte cm;
-
// MPAL code
_mpalCode = ds.readSint32LE();
@@ -490,7 +477,7 @@ void RMItem::readFromStream(Common::SeekableReadStream &ds, bool bLOX) {
_nPatterns = ds.readSint32LE();
// Color mode
- cm = ds.readByte();
+ byte cm = ds.readByte();
_cm = (RMColorMode)cm;
// Flag for the presence of custom palette differences
@@ -519,9 +506,10 @@ void RMItem::readFromStream(Common::SeekableReadStream &ds, bool bLOX) {
_sfx = new RMSfx[_nSfx];
_patterns = new RMPattern[_nPatterns + 1];
+ int dimx, dimy;
// Read in class data
- if (!ds.err())
- for (i = 0; i < _nSprites && !ds.err(); i++) {
+ if (!ds.err()) {
+ for (int i = 0; i < _nSprites && !ds.err(); i++) {
// Download the sprites
if (bLOX) {
_sprites[i].LOXGetSizeFromStream(ds, &dimx, &dimy);
@@ -536,23 +524,26 @@ void RMItem::readFromStream(Common::SeekableReadStream &ds, bool bLOX) {
if (_cm == CM_256 && _bPal)
_sprites[i].setPalette(_pal._data);
}
+ }
- if (!ds.err())
- for (i = 0; i < _nSfx && !ds.err(); i++) {
+ if (!ds.err()) {
+ for (int i = 0; i < _nSfx && !ds.err(); i++) {
if (bLOX)
_sfx[i].readFromStream(ds, true);
else
_sfx[i].readFromStream(ds, false);
}
+ }
// Read the pattern from pattern 1
- if (!ds.err())
- for (i = 1; i <= _nPatterns && !ds.err(); i++) {
+ if (!ds.err()) {
+ for (int i = 1; i <= _nPatterns && !ds.err(); i++) {
if (bLOX)
_patterns[i].readFromStream(ds, true);
else
_patterns[i].readFromStream(ds, false);
}
+ }
// Initialize the current pattern
if (_bInitCurPattern)
@@ -662,7 +653,7 @@ void RMItem::setStatus(int nStatus) {
_bIsActive = (nStatus > 0);
}
-RMPoint RMItem::hotspot() {
+RMPoint RMItem::getHotspot() {
return _hot;
}
@@ -677,7 +668,7 @@ void RMItem::setPattern(int nPattern, bool bPlayP0) {
if (_nCurPattern > 0)
_patterns[_nCurPattern].stopSfx(_sfx);
}
-
+
// Remember the current pattern
_nCurPattern = nPattern;
@@ -789,14 +780,11 @@ void RMItem::playSfx(int nSfx) {
}
void RMItem::pauseSound(bool bPause) {
- int i;
-
- for (i = 0; i < _nSfx; i++)
+ for (int i = 0; i < _nSfx; i++)
_sfx[i].pause(bPause);
}
-
/****************************************************************************\
* RMWipe Methods
\****************************************************************************/
@@ -823,8 +811,8 @@ int RMWipe::priority() {
return 200;
}
-void RMWipe::Unregister() {
- RMGfxTask::Unregister();
+void RMWipe::unregister() {
+ RMGfxTask::unregister();
assert(_nInList == 0);
CoroScheduler.setEvent(_hUnregistered);
}
@@ -952,7 +940,7 @@ short RMCharacter::findPath(short source, short destination) {
error = 1; // Possible error
// 1st cycle: explore possible new nodes
- for (int i = 0; i < cur->_numbBox; i++)
+ for (int i = 0; i < cur->_numbBox; i++) {
if (valid[i] == 1) {
error = 0; // Failure de-bunked
int j = 0;
@@ -967,12 +955,13 @@ short RMCharacter::findPath(short source, short destination) {
minCost = nodeCost[i] + 1;
}
}
+ }
if (error)
finish = true; // All nodes saturated
// 2nd cycle: adding new nodes that were found, saturate old nodes
- for (int i = 0; i < cur->_numbBox; i++)
+ for (int i = 0; i < cur->_numbBox; i++) {
if ((valid[i] == 1) && ((nodeCost[i] + 1) == minCost)) {
box[i]._adj[nextNode[i]] = 2;
nodeCost[nextNode[i]] = minCost;
@@ -984,6 +973,7 @@ short RMCharacter::findPath(short source, short destination) {
if (nextNode[i] == destination)
finish = true;
}
+ }
}
// Remove the path from the adjacent modified matrixes
@@ -1079,91 +1069,91 @@ void RMCharacter::goTo(CORO_PARAM, RMPoint destcoord, bool bReversed) {
}
-RMPoint RMCharacter::searching(char UP, char DOWN, char RIGHT, char LEFT, RMPoint punto) {
- short passi, minimo;
- RMPoint nuovo, trovato;
- minimo = 32000;
+RMPoint RMCharacter::searching(char UP, char DOWN, char RIGHT, char LEFT, RMPoint point) {
+ short steps;
+ RMPoint newPt, foundPt;
+ short minStep = 32000;
if (UP) {
- nuovo = punto;
- passi = 0;
- while ((inWhichBox(nuovo) == -1) && (nuovo._y >= 0)) {
- nuovo._y--;
- passi++;
+ newPt = point;
+ steps = 0;
+ while ((inWhichBox(newPt) == -1) && (newPt._y >= 0)) {
+ newPt._y--;
+ steps++;
}
- if ((inWhichBox(nuovo) != -1) && (passi < minimo) &&
- findPath(inWhichBox(_pos), inWhichBox(nuovo))) {
- minimo = passi;
- nuovo._y--; // to avoid error?
- trovato = nuovo;
+ if ((inWhichBox(newPt) != -1) && (steps < minStep) &&
+ findPath(inWhichBox(_pos), inWhichBox(newPt))) {
+ minStep = steps;
+ newPt._y--; // to avoid error?
+ foundPt = newPt;
}
}
if (DOWN) {
- nuovo = punto;
- passi = 0;
- while ((inWhichBox(nuovo) == -1) && (nuovo._y < 480)) {
- nuovo._y++;
- passi++;
+ newPt = point;
+ steps = 0;
+ while ((inWhichBox(newPt) == -1) && (newPt._y < 480)) {
+ newPt._y++;
+ steps++;
}
- if ((inWhichBox(nuovo) != -1) && (passi < minimo) &&
- findPath(inWhichBox(_pos), inWhichBox(nuovo))) {
- minimo = passi;
- nuovo._y++; // to avoid error?
- trovato = nuovo;
+ if ((inWhichBox(newPt) != -1) && (steps < minStep) &&
+ findPath(inWhichBox(_pos), inWhichBox(newPt))) {
+ minStep = steps;
+ newPt._y++; // to avoid error?
+ foundPt = newPt;
}
}
if (RIGHT) {
- nuovo = punto;
- passi = 0;
- while ((inWhichBox(nuovo) == -1) && (nuovo._x < 640)) {
- nuovo._x++;
- passi++;
+ newPt = point;
+ steps = 0;
+ while ((inWhichBox(newPt) == -1) && (newPt._x < 640)) {
+ newPt._x++;
+ steps++;
}
- if ((inWhichBox(nuovo) != -1) && (passi < minimo) &&
- findPath(inWhichBox(_pos), inWhichBox(nuovo))) {
- minimo = passi;
- nuovo._x++; // to avoid error?
- trovato = nuovo;
+ if ((inWhichBox(newPt) != -1) && (steps < minStep) &&
+ findPath(inWhichBox(_pos), inWhichBox(newPt))) {
+ minStep = steps;
+ newPt._x++; // to avoid error?
+ foundPt = newPt;
}
}
if (LEFT) {
- nuovo = punto;
- passi = 0;
- while ((inWhichBox(nuovo) == -1) && (nuovo._x >= 0)) {
- nuovo._x--;
- passi++;
+ newPt = point;
+ steps = 0;
+ while ((inWhichBox(newPt) == -1) && (newPt._x >= 0)) {
+ newPt._x--;
+ steps++;
}
- if ((inWhichBox(nuovo) != -1) && (passi < minimo) &&
- findPath(inWhichBox(_pos), inWhichBox(nuovo))) {
- minimo = passi;
- nuovo._x--; // to avoid error?
- trovato = nuovo;
+ if ((inWhichBox(newPt) != -1) && (steps < minStep) &&
+ findPath(inWhichBox(_pos), inWhichBox(newPt))) {
+ minStep = steps;
+ newPt._x--; // to avoid error?
+ foundPt = newPt;
}
}
- if (minimo == 32000)
- trovato = punto;
+ if (minStep == 32000)
+ foundPt = point;
- return trovato;
+ return foundPt;
}
-RMPoint RMCharacter::nearestPoint(const RMPoint &punto) {
- return searching(1, 1, 1, 1, punto);
+RMPoint RMCharacter::nearestPoint(const RMPoint &point) {
+ return searching(1, 1, 1, 1, point);
}
-short RMCharacter::scanLine(const RMPoint &punto) {
+short RMCharacter::scanLine(const RMPoint &point) {
int Ldx, Ldy, Lcount;
float Lfx, Lfy, Lslope;
RMPoint Lstart, Lend, Lscan;
signed char Lspeed, Lstatus;
Lstart = _pos;
- Lend = punto;
+ Lend = point;
Ldx = Lstart._x - Lend._x;
Ldy = Lstart._y - Lend._y;
Lfx = Ldx;
@@ -1209,60 +1199,60 @@ short RMCharacter::scanLine(const RMPoint &punto) {
/**
* Calculates intersections between the straight line and the closest BBOX
*/
-RMPoint RMCharacter::invScanLine(const RMPoint &punto) {
- int Ldx, Ldy, Lcount;
- float Lfx, Lfy, Lslope;
- RMPoint Lstart, Lend, Lscan;
- signed char Lspeed, Lstatus, Lbox = -1;
-
- Lstart = punto; // Exchange!
- Lend = _pos; // :-)
- Ldx = Lstart._x - Lend._x;
- Ldy = Lstart._y - Lend._y;
- Lfx = Ldx;
- Lfy = Ldy;
- Ldx = ABS(Ldx);
- Ldy = ABS(Ldy);
- Lspeed = 1;
- Lcount = 0;
-
- if (Ldx > Ldy) {
- Lslope = Lfy / Lfx;
- if (Lend._x < Lstart._x)
- Lspeed = -Lspeed;
- Lstatus = 1;
+RMPoint RMCharacter::invScanLine(const RMPoint &point) {
+ RMPoint lStart = point; // Exchange!
+ RMPoint lEnd = _pos; // :-)
+ int lDx = lStart._x - lEnd._x;
+ int lDy = lStart._y - lEnd._y;
+ float lFx = lDx;
+ float lFy = lDy;
+ lDx = ABS(lDx);
+ lDy = ABS(lDy);
+ signed char lSpeed = 1;
+ int lCount = 0;
+
+ signed char lStatus;
+ float lSlope;
+
+ if (lDx > lDy) {
+ lSlope = lFy / lFx;
+ if (lEnd._x < lStart._x)
+ lSpeed = -lSpeed;
+ lStatus = 1;
} else {
- Lslope = Lfx / Lfy;
- if (Lend._y < Lstart._y)
- Lspeed = -Lspeed;
- Lstatus = 0;
+ lSlope = lFx / lFy;
+ if (lEnd._y < lStart._y)
+ lSpeed = -lSpeed;
+ lStatus = 0;
}
- Lscan = Lstart;
+
+ RMPoint lScan = lStart;
+ signed char lBox = -1;
for (;;) {
- if (inWhichBox(Lscan) != -1) {
- if (inWhichBox(Lscan) != Lbox) {
- if (inWhichBox(_pos) == inWhichBox(Lscan) || findPath(inWhichBox(_pos), inWhichBox(Lscan)))
- return Lscan;
+ if (inWhichBox(lScan) != -1) {
+ if (inWhichBox(lScan) != lBox) {
+ if (inWhichBox(_pos) == inWhichBox(lScan) || findPath(inWhichBox(_pos), inWhichBox(lScan)))
+ return lScan;
else
- Lbox = inWhichBox(Lscan);
+ lBox = inWhichBox(lScan);
}
}
- Lcount++;
- if (Lstatus) {
- Ldx = Lspeed * Lcount;
- Ldy = (int)(Lslope * Ldx);
+ lCount++;
+ if (lStatus) {
+ lDx = lSpeed * lCount;
+ lDy = (int)(lSlope * lDx);
} else {
- Ldy = Lspeed * Lcount;
- Ldx = (int)(Lslope * Ldy);
+ lDy = lSpeed * lCount;
+ lDx = (int)(lSlope * lDy);
}
- Lscan._x = Lstart._x + Ldx;
- Lscan._y = Lstart._y + Ldy;
+ lScan._x = lStart._x + lDx;
+ lScan._y = lStart._y + lDy;
// WORKAROUND: Handles cases where the points never fall inside a bounding box
- if (Lscan._x < -100 || Lscan._y < -100 || Lscan._x >= 1000 || Lscan._y >= 1000)
- return punto;
+ if (lScan._x < -100 || lScan._y < -100 || lScan._x >= 1000 || lScan._y >= 1000)
+ return point;
}
}
@@ -1272,25 +1262,24 @@ RMPoint RMCharacter::invScanLine(const RMPoint &punto) {
*/
RMPoint RMCharacter::nearestHotSpot(int sourcebox, int destbox) {
- RMPoint puntocaldo;
- short cc;
- int x, y, distanzaminima;
- distanzaminima = 10000000;
+ RMPoint hotspot;
+ int x, y;
+ int minDist = 10000000;
RMBoxLoc *cur = _theBoxes->getBoxes(_curLocation);
- for (cc = 0; cc < cur->_boxes[sourcebox]._numHotspot; cc++)
+ for (short cc = 0; cc < cur->_boxes[sourcebox]._numHotspot; cc++)
if ((cur->_boxes[sourcebox]._hotspot[cc]._destination) == destbox) {
x = ABS(cur->_boxes[sourcebox]._hotspot[cc]._hotx - _pos._x);
y = ABS(cur->_boxes[sourcebox]._hotspot[cc]._hoty - _pos._y);
- if ((x * x + y * y) < distanzaminima) {
- distanzaminima = x * x + y * y;
- puntocaldo._x = cur->_boxes[sourcebox]._hotspot[cc]._hotx;
- puntocaldo._y = cur->_boxes[sourcebox]._hotspot[cc]._hoty;
+ if ((x * x + y * y) < minDist) {
+ minDist = x * x + y * y;
+ hotspot._x = cur->_boxes[sourcebox]._hotspot[cc]._hotx;
+ hotspot._y = cur->_boxes[sourcebox]._hotspot[cc]._hoty;
}
}
- return puntocaldo;
+ return hotspot;
}
void RMCharacter::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
@@ -1310,13 +1299,12 @@ void RMCharacter::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *pr
void RMCharacter::newBoxEntered(int nBox) {
RMBoxLoc *cur;
- bool bOldReverse;
// Recall on ExitBox
mpalQueryDoAction(3, _curLocation, _curBox);
cur = _theBoxes->getBoxes(_curLocation);
- bOldReverse = cur->_boxes[_curBox]._bReversed;
+ bool bOldReverse = cur->_boxes[_curBox]._bReversed;
_curBox = nBox;
// If Z is changed, we must remove it from the OT
@@ -1673,7 +1661,7 @@ RMCharacter::RMCharacter() {
_bMovingWithoutMinpath = false;
_bDrawNow = false;
_bNeedToStop = false;
-
+
memset(_path, 0, sizeof(_path));
_pos.set(0, 0);
@@ -1693,10 +1681,6 @@ void RMCharacter::linkToBoxes(RMGameBoxes *boxes) {
\****************************************************************************/
void RMBox::readFromStream(Common::ReadStream &ds) {
- uint16 w;
- int i;
- byte b;
-
// Bbox
_left = ds.readSint32LE();
_top = ds.readSint32LE();
@@ -1704,24 +1688,25 @@ void RMBox::readFromStream(Common::ReadStream &ds) {
_bottom = ds.readSint32LE();
// Adjacency
- for (i = 0; i < MAXBOXES; i++) {
+ for (int i = 0; i < MAXBOXES; i++) {
_adj[i] = ds.readSint32LE();
}
// Misc
_numHotspot = ds.readSint32LE();
_destZ = ds.readByte();
- b = ds.readByte();
+ byte b = ds.readByte();
_bActive = b;
b = ds.readByte();
_bReversed = b;
// Reversed expansion space
- for (i = 0; i < 30; i++)
+ for (int i = 0; i < 30; i++)
ds.readByte();
+ uint16 w;
// Hotspots
- for (i = 0; i < _numHotspot; i++) {
+ for (int i = 0; i < _numHotspot; i++) {
w = ds.readUint16LE();
_hotspot[i]._hotx = w;
w = ds.readUint16LE();
@@ -1745,14 +1730,12 @@ RMBoxLoc::~RMBoxLoc() {
}
void RMBoxLoc::readFromStream(Common::ReadStream &ds) {
- int i;
char buf[2];
- byte ver;
// ID and version
buf[0] = ds.readByte();
buf[1] = ds.readByte();
- ver = ds.readByte();
+ byte ver = ds.readByte();
assert(buf[0] == 'B' && buf[1] == 'X');
assert(ver == 3);
@@ -1763,19 +1746,18 @@ void RMBoxLoc::readFromStream(Common::ReadStream &ds) {
_boxes = new RMBox[_numbBox];
// Read in boxes
- for (i = 0; i < _numbBox; i++)
+ for (int i = 0; i < _numbBox; i++)
_boxes[i].readFromStream(ds);
}
void RMBoxLoc::recalcAllAdj() {
- int i, j;
-
- for (i = 0; i < _numbBox; i++) {
+ for (int i = 0; i < _numbBox; i++) {
Common::fill(_boxes[i]._adj, _boxes[i]._adj + MAXBOXES, 0);
- for (j = 0; j < _boxes[i]._numHotspot; j++)
+ for (int j = 0; j < _boxes[i]._numHotspot; j++) {
if (_boxes[_boxes[i]._hotspot[j]._destination]._bActive)
_boxes[i]._adj[_boxes[i]._hotspot[j]._destination] = 1;
+ }
}
}
@@ -1794,11 +1776,9 @@ RMGameBoxes::~RMGameBoxes() {
}
void RMGameBoxes::init() {
- int i;
-
// Load boxes from disk
_nLocBoxes = 130;
- for (i = 1; i <= _nLocBoxes; i++) {
+ for (int i = 1; i <= _nLocBoxes; i++) {
RMRes res(10000 + i);
Common::SeekableReadStream *ds = res.getReadStream();
@@ -1834,13 +1814,12 @@ bool RMGameBoxes::isInBox(int nLoc, int nBox, const RMPoint &pt) {
}
int RMGameBoxes::whichBox(int nLoc, const RMPoint &punto) {
- int i;
RMBoxLoc *cur = getBoxes(nLoc);
if (!cur)
return -1;
- for (i = 0; i < cur->_numbBox; i++) {
+ for (int i = 0; i < cur->_numbBox; i++) {
if (cur->_boxes[i]._bActive) {
if ((punto._x >= cur->_boxes[i]._left) && (punto._x <= cur->_boxes[i]._right) &&
(punto._y >= cur->_boxes[i]._top) && (punto._y <= cur->_boxes[i]._bottom))
@@ -1857,12 +1836,9 @@ void RMGameBoxes::changeBoxStatus(int nLoc, int nBox, int status) {
}
int RMGameBoxes::getSaveStateSize() {
- int size;
- int i;
+ int size = 4;
- size = 4;
-
- for (i = 1; i <= _nLocBoxes; i++) {
+ for (int i = 1; i <= _nLocBoxes; i++) {
size += 4;
size += _allBoxes[i]->_numbBox;
}
@@ -1871,38 +1847,34 @@ int RMGameBoxes::getSaveStateSize() {
}
void RMGameBoxes::saveState(byte *state) {
- int i, j;
-
// Save the number of locations with boxes
WRITE_LE_UINT32(state, _nLocBoxes);
state += 4;
// For each location, write out the number of boxes and their status
- for (i = 1; i <= _nLocBoxes; i++) {
+ for (int i = 1; i <= _nLocBoxes; i++) {
WRITE_LE_UINT32(state, _allBoxes[i]->_numbBox);
state += 4;
- for (j = 0; j < _allBoxes[i]->_numbBox; j++)
+ for (int j = 0; j < _allBoxes[i]->_numbBox; j++)
*state++ = _allBoxes[i]->_boxes[j]._bActive;
}
}
void RMGameBoxes::loadState(byte *state) {
- int i, j;
- int nloc, nbox;
-
// Load number of items
- nloc = READ_LE_UINT32(state);
+ int nloc = READ_LE_UINT32(state);
state += 4;
assert(nloc <= _nLocBoxes);
+ int nbox;
// For each location, read the number of boxes and their status
- for (i = 1; i <= nloc; i++) {
+ for (int i = 1; i <= nloc; i++) {
nbox = READ_LE_UINT32(state);
state += 4;
- for (j = 0; j < nbox ; j++) {
+ for (int j = 0; j < nbox ; j++) {
if (j < _allBoxes[i]->_numbBox)
_allBoxes[i]->_boxes[j]._bActive = *state;
@@ -1944,10 +1916,6 @@ int RMLocation::TEMPGetNumLoc() {
*/
bool RMLocation::load(Common::SeekableReadStream &ds) {
char id[3];
- int dimx, dimy;
- byte ver;
- byte cm;
- int i;
// Reset dirty rectangling
_prevScroll.set(-1, -1);
@@ -1965,7 +1933,7 @@ bool RMLocation::load(Common::SeekableReadStream &ds) {
return false;
// Version
- ver = ds.readByte();
+ byte ver = ds.readByte();
assert(ver == 6);
// Location name
@@ -1981,12 +1949,12 @@ bool RMLocation::load(Common::SeekableReadStream &ds) {
ds.skip(1);
// Location dimensions
- dimx = ds.readSint32LE();
- dimy = ds.readSint32LE();
+ int dimx = ds.readSint32LE();
+ int dimy = ds.readSint32LE();
_curScroll.set(0, 0);
// Read the color mode
- cm = ds.readByte();
+ byte cm = ds.readByte();
_cmode = (RMColorMode)cm;
// Initialize the source buffer and read the location
@@ -2019,7 +1987,7 @@ bool RMLocation::load(Common::SeekableReadStream &ds) {
g_vm->freezeTime();
- for (i = 0; i < _nItems && !ds.err(); i++)
+ for (int i = 0; i < _nItems && !ds.err(); i++)
_items[i].readFromStream(ds);
g_vm->unfreezeTime();
@@ -2028,12 +1996,8 @@ bool RMLocation::load(Common::SeekableReadStream &ds) {
bool RMLocation::loadLOX(Common::SeekableReadStream &ds) {
- int dimx, dimy;
- byte ver;
- int i;
-
// Version
- ver = ds.readByte();
+ byte ver = ds.readByte();
assert(ver == 1);
// Location name
@@ -2045,8 +2009,8 @@ bool RMLocation::loadLOX(Common::SeekableReadStream &ds) {
TEMPTonyStart._y = ds.readSint32LE();
// Dimensions
- dimx = ds.readSint32LE();
- dimy = ds.readSint32LE();
+ int dimx = ds.readSint32LE();
+ int dimy = ds.readSint32LE();
_curScroll.set(0, 0);
// It's always 65K (16-bit) mode
@@ -2063,7 +2027,7 @@ bool RMLocation::loadLOX(Common::SeekableReadStream &ds) {
if (_nItems > 0)
_items = new RMItem[_nItems];
- for (i = 0; i < _nItems && !ds.err(); i++)
+ for (int i = 0; i < _nItems && !ds.err(); i++)
_items[i].readFromStream(ds, true);
return ds.err();
@@ -2111,22 +2075,18 @@ void RMLocation::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *pri
* Prepare a frame, adding the location to the OT list, and all the items that have changed animation frame.
*/
void RMLocation::doFrame(RMGfxTargetBuffer *bigBuf) {
- int i;
-
// If the location is not in the OT list, add it in
if (!_nInList)
bigBuf->addPrim(new RMGfxPrimitive(this));
// Process all the location items
- for (i = 0; i < _nItems; i++)
+ for (int i = 0; i < _nItems; i++)
_items[i].doFrame(bigBuf);
}
RMItem *RMLocation::getItemFromCode(uint32 dwCode) {
- int i;
-
- for (i = 0; i < _nItems; i++) {
+ for (int i = 0; i < _nItems; i++) {
if (_items[i].mpalCode() == (int)dwCode)
return &_items[i];
}
@@ -2239,9 +2199,7 @@ void RMLocation::setScrollPosition(const RMPoint &scroll) {
void RMLocation::pauseSound(bool bPause) {
- int i;
-
- for (i = 0; i < _nItems; i++)
+ for (int i = 0; i < _nItems; i++)
_items[i].pauseSound(bPause);
}
diff --git a/engines/tony/loc.h b/engines/tony/loc.h
index 61eece2440..04ba772458 100644
--- a/engines/tony/loc.h
+++ b/engines/tony/loc.h
@@ -256,7 +256,7 @@ public:
void setStatus(int nStatus);
bool isIn(const RMPoint &pt, int *size = NULL);
- RMPoint hotspot();
+ RMPoint getHotspot();
bool getName(Common::String &name);
int mpalCode();
@@ -403,12 +403,12 @@ private:
int inWhichBox(const RMPoint &pt);
short findPath(short source, short destination);
- RMPoint searching(char UP, char DOWN, char RIGHT, char LEFT, RMPoint punto);
+ RMPoint searching(char UP, char DOWN, char RIGHT, char LEFT, RMPoint point);
RMPoint nearestPoint(const RMPoint &punto);
void goTo(CORO_PARAM, RMPoint destcoord, bool bReversed = false);
- short scanLine(const RMPoint &punto);
- RMPoint invScanLine(const RMPoint &punto);
+ short scanLine(const RMPoint &point);
+ RMPoint invScanLine(const RMPoint &point);
RMPoint nearestHotSpot(int sourcebox, int destbox);
void newBoxEntered(int nBox);
@@ -478,7 +478,7 @@ public:
void closeFade();
void waitForFadeEnd(CORO_PARAM);
- virtual void Unregister();
+ virtual void unregister();
virtual void removeThis(CORO_PARAM, bool &result);
virtual int priority();
};
diff --git a/engines/tony/mpal/expr.cpp b/engines/tony/mpal/expr.cpp
index 7923d263c0..824cd91651 100644
--- a/engines/tony/mpal/expr.cpp
+++ b/engines/tony/mpal/expr.cpp
@@ -35,68 +35,6 @@ namespace Tony {
namespace MPAL {
-/**
- * @defgroup Mathamatical operations
- */
-//@{
-
-#define OP_MUL ((1 << 4) | 0)
-#define OP_DIV ((1 << 4) | 1)
-#define OP_MODULE ((1 << 4) | 2)
-#define OP_ADD ((2 << 4) | 0)
-#define OP_SUB ((2 << 4) | 1)
-#define OP_SHL ((3 << 4) | 0)
-#define OP_SHR ((3 << 4) | 1)
-#define OP_MINOR ((4 << 4) | 0)
-#define OP_MAJOR ((4 << 4) | 1)
-#define OP_MINEQ ((4 << 4) | 2)
-#define OP_MAJEQ ((4 << 4) | 3)
-#define OP_EQUAL ((5 << 4) | 0)
-#define OP_NOEQUAL ((5 << 4) | 1)
-#define OP_BITAND ((6 << 4) | 0)
-#define OP_BITXOR ((7 << 4) | 0)
-#define OP_BITOR ((8 << 4) | 0)
-#define OP_AND ((9 << 4) | 0)
-#define OP_OR ((10 << 4) | 0)
-
-
-/**
- * Object types that can be contained in an EXPRESSION structure
- */
-enum ExprListTypes {
- ELT_NUMBER = 1,
- ELT_VAR = 2,
- ELT_PARENTH = 3,
- ELT_PARENTH2 = 4
-};
-
-//@}
-
-/**
- * @defgroup Structures
- */
-//@{
-
-/**
- * Mathamatical framework to manage operations
- */
-typedef struct {
- byte _type; // Tipo di oggetto (vedi enum ExprListTypes)
- byte _unary; // Unary operatore (NON SUPPORTATO)
-
- union {
- int _num; // Numero (se type==ELT_NUMBER)
- char *_name; // Nome variabile (se type==ELT_VAR)
- MpalHandle _son; // Handle a espressione (type==ELT_PARENTH)
- byte *_pson; // Handle lockato (type==ELT_PARENTH2)
- } _val;
-
- byte _symbol; // Simbolo matematico (vedi #define OP_*)
-
-} Expression;
-typedef Expression *LpExpression;
-
-//@}
/**
* Duplicate a mathematical expression.
@@ -106,15 +44,14 @@ typedef Expression *LpExpression;
*/
static byte *duplicateExpression(MpalHandle h) {
byte *orig, *clone;
- LpExpression one, two;
orig = (byte *)globalLock(h);
int num = *(byte *)orig;
- one = (LpExpression)(orig+1);
+ LpExpression one = (LpExpression)(orig+1);
clone = (byte *)globalAlloc(GMEM_FIXED, sizeof(Expression) * num + 1);
- two = (LpExpression)(clone + 1);
+ LpExpression two = (LpExpression)(clone + 1);
memcpy(clone, orig, sizeof(Expression) * num + 1);
@@ -180,7 +117,6 @@ static int Compute(int a, int b, byte symbol) {
static void solve(LpExpression one, int num) {
LpExpression two, three;
- int j;
while (num > 1) {
two = one + 1;
@@ -189,7 +125,7 @@ static void solve(LpExpression one, int num) {
memmove(one, two, (num - 1) * sizeof(Expression));
--num;
} else {
- j = 1;
+ int j = 1;
three = two + 1;
while ((three->_symbol != 0) && (two->_symbol & 0xF0) > (three->_symbol & 0xF0)) {
++two;
@@ -213,13 +149,11 @@ static void solve(LpExpression one, int num) {
* @returns Value
*/
static int evaluateAndFreeExpression(byte *expr) {
- LpExpression one, cur;
-
int num = *expr;
- one = (LpExpression)(expr + 1);
+ LpExpression one = (LpExpression)(expr + 1);
// 1) Substitutions of variables
- cur = one;
+ LpExpression cur = one;
for (int i = 0; i < num; i++, cur++) {
if (cur->_type == ELT_VAR) {
cur->_type = ELT_NUMBER;
@@ -254,7 +188,6 @@ static int evaluateAndFreeExpression(byte *expr) {
* @returns Pointer to the buffer immediately after the expression, or NULL if error.
*/
const byte *parseExpression(const byte *lpBuf, MpalHandle *h) {
- LpExpression cur;
byte *start;
uint32 num = *lpBuf;
@@ -270,12 +203,14 @@ const byte *parseExpression(const byte *lpBuf, MpalHandle *h) {
start = (byte *)globalLock(*h);
*start = (byte)num;
- cur = (LpExpression)(start + 1);
+ LpExpression cur = (LpExpression)(start + 1);
for (uint32 i = 0;i < num; i++) {
cur->_type = *(lpBuf);
- cur->_unary = *(lpBuf + 1);
+
+ // *(lpBuf + 1) contains the unary operator, unused => skipped
lpBuf += 2;
+
switch (cur->_type) {
case ELT_NUMBER:
cur->_val._num = (int32)READ_LE_UINT32(lpBuf);
@@ -322,10 +257,8 @@ const byte *parseExpression(const byte *lpBuf, MpalHandle *h) {
* @returns Numeric value
*/
int evaluateExpression(MpalHandle h) {
- int ret;
-
lockVar();
- ret = evaluateAndFreeExpression(duplicateExpression(h));
+ int ret = evaluateAndFreeExpression(duplicateExpression(h));
unlockVar();
return ret;
@@ -339,7 +272,6 @@ int evaluateExpression(MpalHandle h) {
*/
bool compareExpressions(MpalHandle h1, MpalHandle h2) {
byte *e1, *e2;
- LpExpression one, two;
e1 = (byte *)globalLock(h1);
e2 = (byte *)globalLock(h2);
@@ -353,8 +285,8 @@ bool compareExpressions(MpalHandle h1, MpalHandle h2) {
return false;
}
- one = (LpExpression)(e1 + 1);
- two = (LpExpression)(e2 + 1);
+ LpExpression one = (LpExpression)(e1 + 1);
+ LpExpression two = (LpExpression)(e2 + 1);
for (int i = 0; i < num1; i++) {
if (one->_type != two->_type || (i != num1 - 1 && one->_symbol != two->_symbol)) {
diff --git a/engines/tony/mpal/expr.h b/engines/tony/mpal/expr.h
index 9036099993..405624b4fe 100644
--- a/engines/tony/mpal/expr.h
+++ b/engines/tony/mpal/expr.h
@@ -35,6 +35,67 @@ namespace Tony {
namespace MPAL {
+/**
+ * @defgroup Mathamatical operations
+ */
+//@{
+
+#define OP_MUL ((1 << 4) | 0)
+#define OP_DIV ((1 << 4) | 1)
+#define OP_MODULE ((1 << 4) | 2)
+#define OP_ADD ((2 << 4) | 0)
+#define OP_SUB ((2 << 4) | 1)
+#define OP_SHL ((3 << 4) | 0)
+#define OP_SHR ((3 << 4) | 1)
+#define OP_MINOR ((4 << 4) | 0)
+#define OP_MAJOR ((4 << 4) | 1)
+#define OP_MINEQ ((4 << 4) | 2)
+#define OP_MAJEQ ((4 << 4) | 3)
+#define OP_EQUAL ((5 << 4) | 0)
+#define OP_NOEQUAL ((5 << 4) | 1)
+#define OP_BITAND ((6 << 4) | 0)
+#define OP_BITXOR ((7 << 4) | 0)
+#define OP_BITOR ((8 << 4) | 0)
+#define OP_AND ((9 << 4) | 0)
+#define OP_OR ((10 << 4) | 0)
+
+//@}
+
+/**
+ * @defgroup Structures
+ */
+
+//@{
+/**
+ * Mathamatical framework to manage operations
+ */
+typedef struct {
+ byte _type; // Object Type (see enum ExprListTypes)
+
+ union {
+ int _num; // Identifier (if type == ELT_NUMBER)
+ char *_name; // Variable name (if type == ELT_VAR)
+ MpalHandle _son; // Handle expressions (if type == ELT_PARENTH)
+ byte *_pson; // Handle lockato (if type == ELT_PARENTH2)
+ } _val;
+
+ byte _symbol; // Mathematic symbols (see #define OP_*)
+
+} Expression;
+typedef Expression *LpExpression;
+
+//@}
+
+/**
+ * Object types that can be contained in an EXPRESSION structure
+ */
+enum ExprListTypes {
+ ELT_NUMBER = 1,
+ ELT_VAR = 2,
+ ELT_PARENTH = 3,
+ ELT_PARENTH2 = 4
+};
+
/****************************************************************************\
* Function Prototypes
\****************************************************************************/
diff --git a/engines/tony/mpal/loadmpc.cpp b/engines/tony/mpal/loadmpc.cpp
index 953820be74..9c45cdf982 100644
--- a/engines/tony/mpal/loadmpc.cpp
+++ b/engines/tony/mpal/loadmpc.cpp
@@ -139,7 +139,6 @@ static void FreeScript(LpMpalScript lpmsScript) {
* @returns Pointer to the buffer after the item, or NULL on failure.
*/
static const byte *parseDialog(const byte *lpBuf, LpMpalDialog lpmdDialog) {
- uint32 num2, num3;
byte *lpLock;
lpmdDialog->_nObj = READ_LE_UINT32(lpBuf);
@@ -266,7 +265,7 @@ static const byte *parseDialog(const byte *lpBuf, LpMpalDialog lpmdDialog) {
lpmdDialog->_choice[i]._nChoice = READ_LE_UINT16(lpBuf);
lpBuf += 2;
- num2 = *lpBuf++;
+ uint32 num2 = *lpBuf++;
if (num2 >= MAX_SELECTS_PER_CHOICE)
error("Too much selects in choice #%d in dialog #%d", lpmdDialog->_choice[i]._nChoice, lpmdDialog->_nObj);
@@ -296,7 +295,7 @@ static const byte *parseDialog(const byte *lpBuf, LpMpalDialog lpmdDialog) {
lpBuf += 4;
// PlayGroup
- num3 = *lpBuf++;
+ uint32 num3 = *lpBuf++;
if (num3 >= MAX_PLAYGROUPS_PER_SELECT)
error("Too much playgroups in select #%d in choice #%d in dialog #%d", j, lpmdDialog->_choice[i]._nChoice, lpmdDialog->_nObj);
@@ -365,7 +364,6 @@ static const byte *parseItem(const byte *lpBuf, LpMpalItem lpmiItem) {
lpBuf++;
}
-
if (*lpBuf == 0) {
lpBuf++;
lpmiItem->_action[i]._when = NULL;
diff --git a/engines/tony/mpal/memory.cpp b/engines/tony/mpal/memory.cpp
index 428c07b3b7..dfbf16e789 100644
--- a/engines/tony/mpal/memory.cpp
+++ b/engines/tony/mpal/memory.cpp
@@ -33,8 +33,6 @@ namespace MPAL {
* MemoryManager methods
\****************************************************************************/
-const uint32 BLOCK_ID = 0x12345678;
-
/**
* Allocates a new memory block
* @return Returns a MemoryItem instance for the new block
@@ -64,7 +62,7 @@ void *MemoryManager::alloc(uint32 size, uint flags) {
return &item->_data[0];
}
-#define OFFSETOF(type, field) ((unsigned long) &(((type *) 0)->field))
+#define OFFSETOF(type, field) ((size_t) &(((type *) 0)->field))
/**
* Returns a reference to the MemoryItem for a gien byte pointer
diff --git a/engines/tony/mpal/memory.h b/engines/tony/mpal/memory.h
index ba7865938f..9c21cc20e6 100644
--- a/engines/tony/mpal/memory.h
+++ b/engines/tony/mpal/memory.h
@@ -69,6 +69,8 @@ public:
#define GMEM_MOVEABLE 2
#define GMEM_ZEROINIT 4
+const uint32 BLOCK_ID = 0x12345678;
+
} // end of namespace MPAL
} // end of namespace Tony
diff --git a/engines/tony/mpal/mpal.cpp b/engines/tony/mpal/mpal.cpp
index 10f5753540..8d83363c24 100644
--- a/engines/tony/mpal/mpal.cpp
+++ b/engines/tony/mpal/mpal.cpp
@@ -39,19 +39,6 @@ namespace Tony {
namespace MPAL {
-#define GETARG(type) va_arg(v, type)
-
-/****************************************************************************\
-* Copyright
-\****************************************************************************/
-
-const char *mpalCopyright =
- "\n\nMPAL - MultiPurpose Adventure Language for Windows 95\n"
- "Copyright 1997-98 Giovanni Bajo and Luca Giusti\n"
- "ALL RIGHTS RESERVED\n"
- "\n"
- "\n";
-
/****************************************************************************\
* Internal functions
\****************************************************************************/
@@ -363,24 +350,22 @@ static char *duplicateDialogPeriod(uint32 nPeriod) {
MpalHandle resLoad(uint32 dwId) {
MpalHandle h;
char head[4];
- uint32 nBytesRead;
- uint32 nSizeComp, nSizeDecomp;
byte *temp, *buf;
for (int i = 0; i < GLOBALS._nResources; i++)
if (GLOBALS._lpResources[i * 2] == dwId) {
GLOBALS._hMpr.seek(GLOBALS._lpResources[i * 2 + 1]);
- nBytesRead = GLOBALS._hMpr.read(head, 4);
+ uint32 nBytesRead = GLOBALS._hMpr.read(head, 4);
if (nBytesRead != 4)
return NULL;
if (head[0] != 'R' || head[1] != 'E' || head[2] != 'S' || head[3] != 'D')
return NULL;
- nSizeDecomp = GLOBALS._hMpr.readUint32LE();
+ uint32 nSizeDecomp = GLOBALS._hMpr.readUint32LE();
if (GLOBALS._hMpr.err())
return NULL;
- nSizeComp = GLOBALS._hMpr.readUint32LE();
+ uint32 nSizeComp = GLOBALS._hMpr.readUint32LE();
if (GLOBALS._hMpr.err())
return NULL;
@@ -463,18 +448,16 @@ static uint32 *GetItemList(uint32 nLoc) {
static LpItem getItemData(uint32 nOrdItem) {
LpMpalItem curitem = GLOBALS._lpmiItems + nOrdItem;
- LpItem ret;
- MpalHandle hDat;
char *dat;
char *patlength;
// Zeroing out the allocated memory is required!!!
- ret = (LpItem)globalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(Item));
+ LpItem ret = (LpItem)globalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(Item));
if (ret == NULL)
return NULL;
ret->_speed = 150;
- hDat = resLoad(curitem->_dwRes);
+ MpalHandle hDat = resLoad(curitem->_dwRes);
dat = (char *)globalLock(hDat);
if (dat[0] == 'D' && dat[1] == 'A' && dat[2] == 'T') {
@@ -659,6 +642,9 @@ void ScriptThread(CORO_PARAM, const void *param) {
CORO_KILL_SELF();
return;
}
+
+ // WORKAROUND: Wait for events to pulse.
+ CORO_SLEEP(1);
}
}
@@ -727,6 +713,9 @@ void ActionThread(CORO_PARAM, const void *param) {
GLOBALS._mpalError = 1;
break;
}
+
+ // WORKAROUND: Wait for events to pulse.
+ CORO_SLEEP(1);
}
globalDestroy(_ctx->item);
@@ -1138,6 +1127,9 @@ void GroupThread(CORO_PARAM, const void *param) {
CORO_KILL_SELF();
return;
}
+
+ // WORKAROUND: Wait for events to pulse.
+ CORO_SLEEP(1);
}
// The gruop is finished, so we can return to the calling function.
@@ -1403,11 +1395,7 @@ bool doSelection(uint32 i, uint32 dwData) {
*/
bool mpalInit(const char *lpszMpcFileName, const char *lpszMprFileName,
LPLPCUSTOMFUNCTION lplpcfArray, Common::String *lpcfStrings) {
- Common::File hMpc;
byte buf[5];
- uint32 nBytesRead;
- bool bCompress;
- uint32 dwSizeDecomp, dwSizeComp;
byte *cmpbuf;
// Save the array of custom functions
@@ -1415,21 +1403,22 @@ bool mpalInit(const char *lpszMpcFileName, const char *lpszMprFileName,
GLOBALS._lplpFunctionStrings = lpcfStrings;
// OPen the MPC file for reading
+ Common::File hMpc;
if (!hMpc.open(lpszMpcFileName))
return false;
// Read and check the header
- nBytesRead = hMpc.read(buf, 5);
+ uint32 nBytesRead = hMpc.read(buf, 5);
if (nBytesRead != 5)
return false;
if (buf[0] != 'M' || buf[1] != 'P' || buf[2] != 'C' || buf[3] != 0x20)
return false;
- bCompress = buf[4];
+ bool bCompress = buf[4];
// Reads the size of the uncompressed file, and allocate memory
- dwSizeDecomp = hMpc.readUint32LE();
+ uint32 dwSizeDecomp = hMpc.readUint32LE();
if (hMpc.err())
return false;
@@ -1439,7 +1428,7 @@ bool mpalInit(const char *lpszMpcFileName, const char *lpszMprFileName,
if (bCompress) {
// Get the compressed size and read the data in
- dwSizeComp = hMpc.readUint32LE();
+ uint32 dwSizeComp = hMpc.readUint32LE();
if (hMpc.err())
return false;
@@ -1480,7 +1469,7 @@ bool mpalInit(const char *lpszMpcFileName, const char *lpszMprFileName,
// Seek to the end of the file to read overall information
GLOBALS._hMpr.seek(-12, SEEK_END);
- dwSizeComp = GLOBALS._hMpr.readUint32LE();
+ uint32 dwSizeComp = GLOBALS._hMpr.readUint32LE();
if (GLOBALS._hMpr.err())
return false;
@@ -1958,11 +1947,9 @@ uint32 mpalGetError() {
* @returns TRUE if the script 'was launched, FALSE on failure
*/
bool mpalExecuteScript(int nScript) {
- LpMpalScript s;
-
LockScripts();
int n = scriptGetOrderFromNum(nScript);
- s = (LpMpalScript)globalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(MpalScript));
+ LpMpalScript s = (LpMpalScript)globalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(MpalScript));
if (s == NULL)
return false;
diff --git a/engines/tony/mpal/mpal.h b/engines/tony/mpal/mpal.h
index c5f505063f..5e1b02b3fc 100644
--- a/engines/tony/mpal/mpal.h
+++ b/engines/tony/mpal/mpal.h
@@ -102,6 +102,8 @@ namespace MPAL {
#define MAXPATTERN 40 // pattern of animation of an object
#define MAXPOLLINGLOCATIONS 64
+#define GETARG(type) va_arg(v, type)
+
/**
* Macro for use with queries that may refer to X and Y co-ordinates
*/
diff --git a/engines/tony/mpal/mpalutils.cpp b/engines/tony/mpal/mpalutils.cpp
index 92d4af37fc..0919aed5ac 100644
--- a/engines/tony/mpal/mpalutils.cpp
+++ b/engines/tony/mpal/mpalutils.cpp
@@ -81,7 +81,7 @@ Common::SeekableReadStream *RMRes::getReadStream() {
}
bool RMRes::isValid() {
- return _h != NULL;
+ return _h != NULL;
}
/****************************************************************************\
diff --git a/engines/tony/mpal/mpalutils.h b/engines/tony/mpal/mpalutils.h
index 629e157e29..d92bb6f9a2 100644
--- a/engines/tony/mpal/mpalutils.h
+++ b/engines/tony/mpal/mpalutils.h
@@ -59,7 +59,7 @@ class RMResRaw : public RMRes {
public:
RMResRaw(uint32 resID);
virtual ~RMResRaw();
-
+
const byte *dataPointer();
operator const byte*();
diff --git a/engines/tony/sound.cpp b/engines/tony/sound.cpp
index 2c2c280eb2..20386d6353 100644
--- a/engines/tony/sound.cpp
+++ b/engines/tony/sound.cpp
@@ -45,7 +45,7 @@ namespace Tony {
*
*/
FPSound::FPSound() {
- _bSoundSupported = false;
+ _soundSupported = false;
}
/**
@@ -54,8 +54,8 @@ FPSound::FPSound() {
* @returns True is everything is OK, False otherwise
*/
bool FPSound::init() {
- _bSoundSupported = g_system->getMixer()->isReady();
- return _bSoundSupported;
+ _soundSupported = g_system->getMixer()->isReady();
+ return _soundSupported;
}
/**
@@ -69,55 +69,55 @@ FPSound::~FPSound() {
/**
* Allocates an object of type FPStream, and return its pointer
*
- * @param lplpStream Will contain a pointer to the object you just created.
+ * @param streamPtr Will contain a pointer to the object you just created.
*
* @returns True is everything is OK, False otherwise
*/
-bool FPSound::createStream(FPStream **lplpStream) {
- (*lplpStream) = new FPStream(_bSoundSupported);
+bool FPSound::createStream(FPStream **streamPtr) {
+ (*streamPtr) = new FPStream(_soundSupported);
- return (*lplpStream != NULL);
+ return (*streamPtr != NULL);
}
/**
* Allocates an object of type FpSfx, and return its pointer
*
- * @param lplpSfx Will contain a pointer to the object you just created.
+ * @param soundPtr Will contain a pointer to the object you just created.
*
* @returns True is everything is OK, False otherwise
*/
-bool FPSound::createSfx(FPSfx **lplpSfx) {
- (*lplpSfx) = new FPSfx(_bSoundSupported);
+bool FPSound::createSfx(FPSfx **sfxPtr) {
+ (*sfxPtr) = new FPSfx(_soundSupported);
- return (*lplpSfx != NULL);
+ return (*sfxPtr != NULL);
}
/**
* Set the general volume
*
- * @param dwVolume Volume to set (0-63)
+ * @param volume Volume to set (0-63)
*/
-void FPSound::setMasterVolume(int dwVolume) {
- if (!_bSoundSupported)
+void FPSound::setMasterVolume(int volume) {
+ if (!_soundSupported)
return;
- g_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, CLIP<int>(dwVolume, 0, 63) * Audio::Mixer::kMaxChannelVolume / 63);
+ g_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, CLIP<int>(volume, 0, 63) * Audio::Mixer::kMaxChannelVolume / 63);
}
/**
* Get the general volume
*
- * @param lpdwVolume Variable that will contain the volume (0-63)
+ * @param volumePtr Variable that will contain the volume (0-63)
*/
-void FPSound::getMasterVolume(int *lpdwVolume) {
- if (!_bSoundSupported)
+void FPSound::getMasterVolume(int *volumePtr) {
+ if (!_soundSupported)
return;
- *lpdwVolume = g_system->getMixer()->getVolumeForSoundType(Audio::Mixer::kPlainSoundType) * 63 / Audio::Mixer::kMaxChannelVolume;
+ *volumePtr = g_system->getMixer()->getVolumeForSoundType(Audio::Mixer::kPlainSoundType) * 63 / Audio::Mixer::kMaxChannelVolume;
}
/**
@@ -128,15 +128,15 @@ void FPSound::getMasterVolume(int *lpdwVolume) {
*
*/
-FPSfx::FPSfx(bool bSoundOn) {
- _bSoundSupported = bSoundOn;
- _bFileLoaded = false;
+FPSfx::FPSfx(bool soundOn) {
+ _soundSupported = soundOn;
+ _fileLoaded = false;
_lastVolume = 63;
_hEndOfBuffer = CoroScheduler.createEvent(true, false);
- _bIsVoice = false;
+ _isVoice = false;
_loopStream = 0;
_rewindableStream = 0;
- _bPaused = false;
+ _paused = false;
g_vm->_activeSfx.push_back(this);
}
@@ -150,7 +150,7 @@ FPSfx::FPSfx(bool bSoundOn) {
*/
FPSfx::~FPSfx() {
- if (!_bSoundSupported)
+ if (!_soundSupported)
return;
g_system->getMixer()->stopHandle(_handle);
@@ -187,22 +187,22 @@ bool FPSfx::loadWave(Common::SeekableReadStream *stream) {
if (!_rewindableStream)
return false;
- _bFileLoaded = true;
+ _fileLoaded = true;
setVolume(_lastVolume);
return true;
}
bool FPSfx::loadVoiceFromVDB(Common::File &vdbFP) {
- if (!_bSoundSupported)
+ if (!_soundSupported)
return true;
uint32 size = vdbFP.readUint32LE();
uint32 rate = vdbFP.readUint32LE();
- _bIsVoice = true;
+ _isVoice = true;
_rewindableStream = Audio::makeADPCMStream(vdbFP.readStream(size), DisposeAfterUse::YES, 0, Audio::kADPCMDVI, rate, 1);
- _bFileLoaded = true;
+ _fileLoaded = true;
setVolume(62);
return true;
}
@@ -210,18 +210,18 @@ bool FPSfx::loadVoiceFromVDB(Common::File &vdbFP) {
/**
* Opens a file and loads a sound effect.
*
- * @param lpszFileName Sfx filename
- * @param dwCodec CODEC used to uncompress the samples
+ * @param fileName Sfx filename
+ * @param codec CODEC used to uncompress the samples
*
* @returns True is everything is OK, False otherwise
*/
-bool FPSfx::loadFile(const char *lpszFileName, uint32 dwCodec) {
- if (!_bSoundSupported)
+bool FPSfx::loadFile(const char *fileName, uint32 codec) {
+ if (!_soundSupported)
return true;
Common::File file;
- if (!file.open(lpszFileName)) {
+ if (!file.open(fileName)) {
warning("FPSfx::LoadFile(): Cannot open sfx file!");
return false;
}
@@ -236,7 +236,7 @@ bool FPSfx::loadFile(const char *lpszFileName, uint32 dwCodec) {
Common::SeekableReadStream *buffer = file.readStream(file.size() - file.pos());
- if (dwCodec == FPCODEC_ADPCM) {
+ if (codec == FPCODEC_ADPCM) {
_rewindableStream = Audio::makeADPCMStream(buffer, DisposeAfterUse::YES, 0, Audio::kADPCMDVI, rate, channels);
} else {
byte flags = Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN;
@@ -247,7 +247,7 @@ bool FPSfx::loadFile(const char *lpszFileName, uint32 dwCodec) {
_rewindableStream = Audio::makeRawStream(buffer, rate, flags, DisposeAfterUse::YES);
}
- _bFileLoaded = true;
+ _fileLoaded = true;
return true;
}
@@ -260,14 +260,14 @@ bool FPSfx::loadFile(const char *lpszFileName, uint32 dwCodec) {
bool FPSfx::play() {
stop(); // sanity check
- if (_bFileLoaded) {
+ if (_fileLoaded) {
CoroScheduler.resetEvent(_hEndOfBuffer);
_rewindableStream->rewind();
Audio::AudioStream *stream = _rewindableStream;
- if (_bLoop) {
+ if (_loop) {
if (!_loopStream)
_loopStream = Audio::makeLoopingAudioStream(_rewindableStream, 0);
@@ -279,7 +279,7 @@ bool FPSfx::play() {
setVolume(_lastVolume);
- if (_bPaused)
+ if (_paused)
g_system->getMixer()->pauseHandle(_handle, true);
}
@@ -293,9 +293,9 @@ bool FPSfx::play() {
*/
bool FPSfx::stop() {
- if (_bFileLoaded) {
+ if (_fileLoaded) {
g_system->getMixer()->stopHandle(_handle);
- _bPaused = false;
+ _paused = false;
}
return true;
@@ -304,15 +304,15 @@ bool FPSfx::stop() {
/**
* Enables or disables the Sfx loop.
*
- * @param _bLoop True to enable the loop, False to disable
+ * @param loop True to enable the loop, False to disable
*
* @remarks The loop must be activated BEFORE the sfx starts
* playing. Any changes made during the play will have
* no effect until the sfx is stopped then played again.
*/
-void FPSfx::setLoop(bool bLop) {
- _bLoop = bLop;
+void FPSfx::setLoop(bool loop) {
+ _loop = loop;
}
/**
@@ -320,65 +320,65 @@ void FPSfx::setLoop(bool bLop) {
*
*/
-void FPSfx::pause(bool bPause) {
- if (_bFileLoaded) {
- if (g_system->getMixer()->isSoundHandleActive(_handle) && (bPause ^ _bPaused))
- g_system->getMixer()->pauseHandle(_handle, bPause);
+void FPSfx::setPause(bool pause) {
+ if (_fileLoaded) {
+ if (g_system->getMixer()->isSoundHandleActive(_handle) && (pause ^ _paused))
+ g_system->getMixer()->pauseHandle(_handle, pause);
- _bPaused = bPause;
+ _paused = pause;
}
}
/**
* Change the volume of Sfx
*
- * @param dwVolume Volume to be set (0-63)
+ * @param volume Volume to be set (0-63)
*
*/
-void FPSfx::setVolume(int dwVolume) {
- if (dwVolume > 63)
- dwVolume = 63;
+void FPSfx::setVolume(int volume) {
+ if (volume > 63)
+ volume = 63;
- if (dwVolume < 0)
- dwVolume = 0;
+ if (volume < 0)
+ volume = 0;
- _lastVolume = dwVolume;
+ _lastVolume = volume;
- if (_bIsVoice) {
+ if (_isVoice) {
if (!GLOBALS._bCfgDubbing)
- dwVolume = 0;
+ volume = 0;
else {
- dwVolume -= (10 - GLOBALS._nCfgDubbingVolume) * 2;
- if (dwVolume < 0)
- dwVolume = 0;
+ volume -= (10 - GLOBALS._nCfgDubbingVolume) * 2;
+ if (volume < 0)
+ volume = 0;
}
} else {
if (!GLOBALS._bCfgSFX)
- dwVolume = 0;
+ volume = 0;
else {
- dwVolume -= (10 - GLOBALS._nCfgSFXVolume) * 2;
- if (dwVolume < 0)
- dwVolume = 0;
+ volume -= (10 - GLOBALS._nCfgSFXVolume) * 2;
+ if (volume < 0)
+ volume = 0;
}
}
if (g_system->getMixer()->isSoundHandleActive(_handle))
- g_system->getMixer()->setChannelVolume(_handle, dwVolume * Audio::Mixer::kMaxChannelVolume / 63);
+ g_system->getMixer()->setChannelVolume(_handle, volume * Audio::Mixer::kMaxChannelVolume / 63);
}
/**
* Gets the Sfx volume
*
- * @param lpdwVolume Will contain the current Sfx volume
+ * @param volumePtr Will contain the current Sfx volume
*
*/
-void FPSfx::getVolume(int *lpdwVolume) {
+void FPSfx::getVolume(int *volumePtr) {
if (g_system->getMixer()->isSoundHandleActive(_handle))
- *lpdwVolume = g_system->getMixer()->getChannelVolume(_handle) * 63 / Audio::Mixer::kMaxChannelVolume;
+ *volumePtr = g_system->getMixer()->getChannelVolume(_handle) * 63 / Audio::Mixer::kMaxChannelVolume;
else
- *lpdwVolume = 0;
+ *volumePtr = 0;
}
/**
@@ -421,14 +421,14 @@ void FPSfx::soundCheckProcess(CORO_PARAM, const void *param) {
* @remarks Do *NOT* declare an object directly, but rather
* create it using FPSound::CreateStream()
*/
-FPStream::FPStream(bool bSoundOn) {
- _bSoundSupported = bSoundOn;
- _bFileLoaded = false;
- _bPaused = false;
- _bLoop = false;
- _bDoFadeOut = false;
- _bSyncExit = false;
- _dwBufferSize = _dwSize = 0;
+FPStream::FPStream(bool soundOn) {
+ _soundSupported = soundOn;
+ _fileLoaded = false;
+ _paused = false;
+ _loop = false;
+ _doFadeOut = false;
+ _syncExit = false;
+ _bufferSize = _size = 0;
_lastVolume = 0;
_syncToPlay = NULL;
_loopStream = NULL;
@@ -442,13 +442,13 @@ FPStream::FPStream(bool bSoundOn) {
*/
FPStream::~FPStream() {
- if (!_bSoundSupported)
+ if (!_soundSupported)
return;
if (g_system->getMixer()->isSoundHandleActive(_handle))
stop();
- if (_bFileLoaded)
+ if (_fileLoaded)
unloadFile();
_syncToPlay = NULL;
@@ -470,31 +470,32 @@ void FPStream::release() {
* Opens a file stream
*
* @param fileName Filename to be opened
- * @param dwCodec CODEC to be used to uncompress samples
+ * @param codec CODEC to be used to uncompress samples
*
* @returns True is everything is OK, False otherwise
*/
-bool FPStream::loadFile(const Common::String &fileName, uint32 dwCodType, int nBufSize) {
- if (!_bSoundSupported)
+bool FPStream::loadFile(const Common::String &fileName, uint32 codec, int bufSize) {
+ if (!_soundSupported)
return true;
- if (_bFileLoaded)
+ if (_fileLoaded)
unloadFile();
// Save the codec type
- _dwCodec = dwCodType;
+ _codec = codec;
// Open the file stream for reading
if (!_file.open(fileName)) {
// Fallback: try with an extra '0' prefix
if (!_file.open("0" + fileName))
return false;
+ warning("FPStream::loadFile(): Fallback from %s to %s", fileName.c_str(), _file.getName());
}
// Save the size of the stream
- _dwSize = _file.size();
+ _size = _file.size();
- switch (_dwCodec) {
+ switch (_codec) {
case FPCODEC_RAW:
_rewindableStream = Audio::makeRawStream(&_file, 44100, Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN | Audio::FLAG_STEREO, DisposeAfterUse::NO);
break;
@@ -509,8 +510,8 @@ bool FPStream::loadFile(const Common::String &fileName, uint32 dwCodType, int nB
}
// All done
- _bFileLoaded = true;
- _bPaused = false;
+ _fileLoaded = true;
+ _paused = false;
setVolume(63);
@@ -527,7 +528,7 @@ bool FPStream::loadFile(const Common::String &fileName, uint32 dwCodType, int nB
* memory used by the stream.
*/
bool FPStream::unloadFile() {
- if (!_bSoundSupported || !_bFileLoaded)
+ if (!_soundSupported || !_fileLoaded)
return true;
assert(!g_system->getMixer()->isSoundHandleActive(_handle));
@@ -540,7 +541,7 @@ bool FPStream::unloadFile() {
_file.close();
// Flag that the file is no longer in memory
- _bFileLoaded = false;
+ _fileLoaded = false;
return true;
}
@@ -552,7 +553,7 @@ bool FPStream::unloadFile() {
*/
bool FPStream::play() {
- if (!_bSoundSupported || !_bFileLoaded)
+ if (!_soundSupported || !_fileLoaded)
return false;
stop();
@@ -561,7 +562,7 @@ bool FPStream::play() {
Audio::AudioStream *stream = _rewindableStream;
- if (_bLoop) {
+ if (_loop) {
if (!_loopStream)
_loopStream = new Audio::LoopingAudioStream(_rewindableStream, 0, DisposeAfterUse::NO);
@@ -571,7 +572,7 @@ bool FPStream::play() {
// FIXME: Should this be kMusicSoundType or KPlainSoundType?
g_system->getMixer()->playStream(Audio::Mixer::kMusicSoundType, &_handle, stream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO);
setVolume(_lastVolume);
- _bPaused = false;
+ _paused = false;
return true;
}
@@ -584,10 +585,10 @@ bool FPStream::play() {
*/
bool FPStream::stop() {
- if (!_bSoundSupported)
+ if (!_soundSupported)
return true;
- if (!_bFileLoaded)
+ if (!_fileLoaded)
return false;
if (!g_system->getMixer()->isSoundHandleActive(_handle))
@@ -595,49 +596,49 @@ bool FPStream::stop() {
g_system->getMixer()->stopHandle(_handle);
- _bPaused = false;
+ _paused = false;
return true;
}
-void FPStream::waitForSync(FPStream *toplay) {
+void FPStream::waitForSync(FPStream *toPlay) {
// FIXME: The idea here is that you wait for this stream to reach
// a buffer which is a multiple of nBufSize/nSync, and then the
// thread stops it and immediately starts the 'toplay' stream.
stop();
- toplay->play();
+ toPlay->play();
}
/**
* Unables or disables stream loop.
*
- * @param _bLoop True enable loop, False disables it
+ * @param loop True enable loop, False disables it
*
* @remarks The loop must be activated BEFORE the stream starts
* playing. Any changes made during the play will have no
* effect until the stream is stopped then played again.
*/
void FPStream::setLoop(bool loop) {
- _bLoop = loop;
+ _loop = loop;
}
/**
* Pause sound effect
*
- * @param bPause True enables pause, False disables it
+ * @param pause True enables pause, False disables it
*/
-void FPStream::pause(bool bPause) {
- if (!_bFileLoaded)
+void FPStream::setPause(bool pause) {
+ if (!_fileLoaded)
return;
- if (bPause == _bPaused)
+ if (pause == _paused)
return;
if (g_system->getMixer()->isSoundHandleActive(_handle))
- g_system->getMixer()->pauseHandle(_handle, bPause);
+ g_system->getMixer()->pauseHandle(_handle, pause);
- _bPaused = bPause;
+ _paused = pause;
// Trick to reset the volume after a possible new sound configuration
setVolume(_lastVolume);
@@ -646,43 +647,43 @@ void FPStream::pause(bool bPause) {
/**
* Change the volume of the stream
*
- * @param dwVolume Volume to be set (0-63)
+ * @param volume Volume to be set (0-63)
*
*/
-void FPStream::setVolume(int dwVolume) {
- if (dwVolume > 63)
- dwVolume = 63;
+void FPStream::setVolume(int volume) {
+ if (volume > 63)
+ volume = 63;
- if (dwVolume < 0)
- dwVolume = 0;
+ if (volume < 0)
+ volume = 0;
- _lastVolume = dwVolume;
+ _lastVolume = volume;
if (!GLOBALS._bCfgMusic)
- dwVolume = 0;
+ volume = 0;
else {
- dwVolume -= (10 - GLOBALS._nCfgMusicVolume) * 2;
- if (dwVolume < 0)
- dwVolume = 0;
+ volume -= (10 - GLOBALS._nCfgMusicVolume) * 2;
+ if (volume < 0)
+ volume = 0;
}
if (g_system->getMixer()->isSoundHandleActive(_handle))
- g_system->getMixer()->setChannelVolume(_handle, dwVolume * Audio::Mixer::kMaxChannelVolume / 63);
+ g_system->getMixer()->setChannelVolume(_handle, volume * Audio::Mixer::kMaxChannelVolume / 63);
}
/**
* Gets the volume of the stream
*
- * @param lpdwVolume Variable that will contain the current volume
+ * @param volumePtr Variable that will contain the current volume
*
*/
-void FPStream::getVolume(int *lpdwVolume) {
+void FPStream::getVolume(int *volumePtr) {
if (g_system->getMixer()->isSoundHandleActive(_handle))
- *lpdwVolume = g_system->getMixer()->getChannelVolume(_handle) * 63 / Audio::Mixer::kMaxChannelVolume;
+ *volumePtr = g_system->getMixer()->getChannelVolume(_handle) * 63 / Audio::Mixer::kMaxChannelVolume;
else
- *lpdwVolume = 0;
+ *volumePtr = 0;
}
} // End of namespace Tony
diff --git a/engines/tony/sound.h b/engines/tony/sound.h
index c859f781f4..7422de02b3 100644
--- a/engines/tony/sound.h
+++ b/engines/tony/sound.h
@@ -55,7 +55,7 @@ enum SoundCodecs {
class FPSound {
private:
- bool _bSoundSupported;
+ bool _soundSupported;
public:
/**
@@ -83,49 +83,49 @@ public:
/**
* Allocates an object of type FPStream, and return its pointer
*
- * @param lplpStream Will contain a pointer to the object you just created.
+ * @param streamPtr Will contain a pointer to the object you just created.
*
* @returns True is everything is OK, False otherwise
*/
- bool createStream(FPStream **lplpStream);
+ bool createStream(FPStream **streamPtr);
/**
* Allocates an object of type FpSfx, and return its pointer
*
- * @param lplpSfx Will contain a pointer to the object you just created.
+ * @param sfxPtr Will contain a pointer to the object you just created.
*
* @returns True is everything is OK, False otherwise
*/
- bool createSfx(FPSfx **lplpSfx);
+ bool createSfx(FPSfx **sfxPtr);
/**
* Set the general volume
*
- * @param dwVolume Volume to set (0-63)
+ * @param volume Volume to set (0-63)
*/
- void setMasterVolume(int dwVolume);
+ void setMasterVolume(int volume);
/**
* Get the general volume
*
- * @param lpdwVolume Variable that will contain the volume (0-63)
+ * @param volume Variable that will contain the volume (0-63)
*/
- void getMasterVolume(int *lpdwVolume);
+ void getMasterVolume(int *volume);
};
class FPSfx {
private:
- bool _bSoundSupported; // True if the sound is active
- bool _bFileLoaded; // True is a file is opened
- bool _bLoop; // True is sound effect should loop
+ bool _soundSupported; // True if the sound is active
+ bool _fileLoaded; // True is a file is opened
+ bool _loop; // True is sound effect should loop
int _lastVolume;
- bool _bIsVoice;
- bool _bPaused;
+ bool _isVoice;
+ bool _paused;
Audio::AudioStream *_loopStream;
Audio::RewindableAudioStream *_rewindableStream;
@@ -147,7 +147,7 @@ public:
*
*/
- FPSfx(bool bSoundOn);
+ FPSfx(bool soundOn);
/**
* Default Destructor.
@@ -173,13 +173,13 @@ public:
/**
* Opens a file and loads a sound effect.
*
- * @param lpszFileName Sfx filename
- * @param dwCodec CODEC used to uncompress the samples
+ * @param fileName Sfx filename
+ * @param codec CODEC used to uncompress the samples
*
* @returns True is everything is OK, False otherwise
*/
- bool loadFile(const char *lpszFileName, uint32 dwCodec = FPCODEC_RAW);
+ bool loadFile(const char *fileName, uint32 codec = FPCODEC_RAW);
bool loadWave(Common::SeekableReadStream *stream);
bool loadVoiceFromVDB(Common::File &vdbFP);
@@ -204,37 +204,37 @@ public:
*
*/
- void pause(bool bPause);
+ void setPause(bool pause);
/**
* Enables or disables the Sfx loop.
*
- * @param bLoop True to enable the loop, False to disable
+ * @param loop True to enable the loop, False to disable
*
* @remarks The loop must be activated BEFORE the sfx starts
* playing. Any changes made during the play will have
* no effect until the sfx is stopped then played again.
*/
- void setLoop(bool bLoop);
+ void setLoop(bool loop);
/**
* Change the volume of Sfx
*
- * @param dwVolume Volume to be set (0-63)
+ * @param volume Volume to be set (0-63)
*
*/
- void setVolume(int dwVolume);
+ void setVolume(int volume);
/**
* Gets the Sfx volume
*
- * @param lpdwVolume Will contain the current Sfx volume
+ * @param volumePtr Will contain the current Sfx volume
*
*/
- void getVolume(int *lpdwVolume);
+ void getVolume(int *volumePtr);
/**
* Returns true if the underlying sound has ended
@@ -244,18 +244,18 @@ public:
class FPStream {
private:
- uint32 _dwBufferSize; // Buffer size (bytes)
- uint32 _dwSize; // Stream size (bytes)
- uint32 _dwCodec; // CODEC used
-
- Common::File _file; // File handle used for the stream
-
- bool _bSoundSupported; // True if the sound is active
- bool _bFileLoaded; // True if the file is open
- bool _bLoop; // True if the stream should loop
- bool _bDoFadeOut; // True if fade out is required
- bool _bSyncExit;
- bool _bPaused;
+ uint32 _bufferSize; // Buffer size (bytes)
+ uint32 _size; // Stream size (bytes)
+ uint32 _codec; // CODEC used
+
+ Common::File _file; // File handle used for the stream
+
+ bool _soundSupported; // True if the sound is active
+ bool _fileLoaded; // True if the file is open
+ bool _loop; // True if the stream should loop
+ bool _doFadeOut; // True if fade out is required
+ bool _syncExit;
+ bool _paused;
int _lastVolume;
FPStream *_syncToPlay;
@@ -272,7 +272,7 @@ public:
* create it using FPSound::CreateStream()
*/
- FPStream(bool bSoundOn);
+ FPStream(bool soundOn);
/**
* Default destructor.
@@ -297,12 +297,12 @@ public:
* Opens a file stream
*
* @param fileName Filename to be opened
- * @param dwCodec CODEC to be used to uncompress samples
+ * @param codec CODEC to be used to uncompress samples
*
* @returns True is everything is OK, False otherwise
*/
- bool loadFile(const Common::String &fileName, uint32 dwCodec = FPCODEC_RAW, int nSync = 2000);
+ bool loadFile(const Common::String &fileName, uint32 codec = FPCODEC_RAW, int sync = 2000);
/**
* Closes a file stream (opened or not).
@@ -332,44 +332,44 @@ public:
*/
bool stop();
- void waitForSync(FPStream *toplay);
+ void waitForSync(FPStream *toPlay);
/**
* Pause sound effect
*
- * @param bPause True enables pause, False disables it
+ * @param pause True enables pause, False disables it
*/
- void pause(bool bPause);
+ void setPause(bool pause);
/**
* Unables or disables stream loop.
*
- * @param bLoop True enable loop, False disables it
+ * @param loop True enable loop, False disables it
*
* @remarks The loop must be activated BEFORE the stream starts
* playing. Any changes made during the play will have no
* effect until the stream is stopped then played again.
*/
- void setLoop(bool bLoop);
+ void setLoop(bool loop);
/**
* Change the volume of the stream
*
- * @param dwVolume Volume to be set (0-63)
+ * @param volume Volume to be set (0-63)
*/
- void setVolume(int dwVolume);
+ void setVolume(int volume);
/**
* Gets the volume of the stream
*
- * @param lpdwVolume Variable that will contain the current volume
+ * @param volumePtr Variable that will contain the current volume
*
*/
- void getVolume(int *lpdwVolume);
+ void getVolume(int *volumePtr);
};
} // End of namespace Tony
diff --git a/engines/tony/tony.cpp b/engines/tony/tony.cpp
index 4ffb84ced8..86740c6fe5 100644
--- a/engines/tony/tony.cpp
+++ b/engines/tony/tony.cpp
@@ -55,6 +55,7 @@ TonyEngine::TonyEngine(OSystem *syst, const TonyGameDescription *gameDesc) : Eng
SearchMan.addSubDirectoryMatching(gameDataDir, "Roasted");
SearchMan.addSubDirectoryMatching(gameDataDir, "Music");
SearchMan.addSubDirectoryMatching(gameDataDir, "Music/utilsfx");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "Music/Layer");
// Set up load slot number
_initialLoadSlotNumber = -1;
@@ -244,16 +245,16 @@ bool TonyEngine::loadTonyDat() {
expectedLangVariant = 0;
break;
}
-
+
int numVariant = in.readUint16BE();
- if (expectedLangVariant > numVariant) {
+ if (expectedLangVariant > numVariant - 1) {
msg = Common::String::format("Font variant not present in 'tony.dat'. Get it from the ScummVM website");
GUIErrorMessage(msg);
warning("%s", msg.c_str());
-
+
return false;
}
-
+
in.seek(in.pos() + (2 * 256 * 8 * expectedLangVariant));
for (int i = 0; i < 256; i++) {
_cTableDialog[i] = in.readSint16BE();
@@ -323,7 +324,7 @@ void TonyEngine::playMusic(int nChannel, const Common::String &fname, int nFX, b
if (!getIsDemo()) {
if (!_stream[GLOBALS._nextChannel]->loadFile(fname, FPCODEC_ADPCM, nSync))
- g_vm->abortGame();
+ error("failed to open music file '%s'", fname.c_str());
} else {
_stream[GLOBALS._nextChannel]->loadFile(fname, FPCODEC_ADPCM, nSync);
}
@@ -335,7 +336,7 @@ void TonyEngine::playMusic(int nChannel, const Common::String &fname, int nFX, b
} else {
if (!getIsDemo()) {
if (!_stream[nChannel]->loadFile(fname, FPCODEC_ADPCM, nSync))
- g_vm->abortGame();
+ error("failed to open music file '%s'", fname.c_str());
} else {
_stream[nChannel]->loadFile(fname, FPCODEC_ADPCM, nSync);
}
@@ -356,7 +357,7 @@ void TonyEngine::doNextMusic(CORO_PARAM, const void *param) {
if (!g_vm->getIsDemo()) {
if (!streams[GLOBALS._nextChannel]->loadFile(GLOBALS._nextMusic, FPCODEC_ADPCM, GLOBALS._nextSync))
- g_vm->abortGame();
+ error("failed to open next music file '%s'", GLOBALS._nextMusic.c_str());
} else {
streams[GLOBALS._nextChannel]->loadFile(GLOBALS._nextMusic, FPCODEC_ADPCM, GLOBALS._nextSync);
}
@@ -513,13 +514,13 @@ void TonyEngine::pauseSound(bool bPause) {
for (uint i = 0; i < 6; i++)
if (_stream[i])
- _stream[i]->pause(bPause);
+ _stream[i]->setPause(bPause);
for (uint i = 0; i < MAX_SFX_CHANNELS; i++) {
if (_sfx[i])
- _sfx[i]->pause(bPause);
+ _sfx[i]->setPause(bPause);
if (_utilSfx[i])
- _utilSfx[i]->pause(bPause);
+ _utilSfx[i]->setPause(bPause);
}
}
@@ -631,10 +632,6 @@ void TonyEngine::openInitOptions(CORO_PARAM) {
_theEngine.openOptionScreen(coroParam, 2);
}
-void TonyEngine::abortGame() {
- _bQuitNow = true;
-}
-
/**
* Main process for playing the game.
*
@@ -772,9 +769,9 @@ void TonyEngine::syncSoundSettings() {
}
void TonyEngine::saveSoundSettings() {
- ConfMan.setBool("speech_mute", GLOBALS._bCfgDubbing);
- ConfMan.setBool("sfx_mute", GLOBALS._bCfgSFX);
- ConfMan.setBool("music_mute", GLOBALS._bCfgMusic);
+ ConfMan.setBool("speech_mute", !GLOBALS._bCfgDubbing);
+ ConfMan.setBool("sfx_mute", !GLOBALS._bCfgSFX);
+ ConfMan.setBool("music_mute", !GLOBALS._bCfgMusic);
ConfMan.setInt("speech_volume", GLOBALS._nCfgDubbingVolume * 256 / 10);
ConfMan.setInt("sfx_volume", GLOBALS._nCfgSFXVolume * 256 / 10);
diff --git a/engines/tony/tony.h b/engines/tony/tony.h
index 22090dfe51..332b122923 100644
--- a/engines/tony/tony.h
+++ b/engines/tony/tony.h
@@ -71,7 +71,7 @@ struct TonyGameDescription;
#define MAX_SFX_CHANNELS 32
#define TONY_DAT_VER_MAJ 0
-#define TONY_DAT_VER_MIN 1
+#define TONY_DAT_VER_MIN 3
struct VoiceHeader {
int _offset;
@@ -169,7 +169,6 @@ public:
void play();
void close();
- void abortGame();
void getDataDirectory(DataDir dir, char *path);
diff --git a/engines/tony/utils.cpp b/engines/tony/utils.cpp
index 3cc09a1454..81060146b7 100644
--- a/engines/tony/utils.cpp
+++ b/engines/tony/utils.cpp
@@ -383,7 +383,7 @@ void RMResUpdate::init(const Common::String &fileName) {
// It doesn't exist, so exit immediately
return;
- uint8 version = _hFile.readByte();
+ _hFile.readByte(); // Version, unused
_numUpd = _hFile.readUint32LE();
diff --git a/engines/tony/window.cpp b/engines/tony/window.cpp
index 013be84b4b..c9c450424f 100644
--- a/engines/tony/window.cpp
+++ b/engines/tony/window.cpp
@@ -256,7 +256,7 @@ void RMWindow::plotLines(const byte *lpBuf, const Common::Point &center, int x,
}
void RMWindow::showDirtyRects(bool v) {
- _showDirtyRects = v;
+ _showDirtyRects = v;
}
/****************************************************************************\
diff --git a/engines/toon/detection.cpp b/engines/toon/detection.cpp
index 3877fa2a6c..38b1f4f6e1 100644
--- a/engines/toon/detection.cpp
+++ b/engines/toon/detection.cpp
@@ -84,7 +84,7 @@ static const ADGameDescription gameDescriptions[] = {
{"study.svl", 0, "d4aff126ee27be3c3d25e2996369d7cb", 2324368},
},
Common::RU_RUS, Common::kPlatformPC, ADGF_NO_FLAGS, GUIO0()
- },
+ },
{
"toon", "",
{
diff --git a/engines/toon/movie.h b/engines/toon/movie.h
index e795182cba..4dd6583bf6 100644
--- a/engines/toon/movie.h
+++ b/engines/toon/movie.h
@@ -40,7 +40,7 @@ protected:
SmackerVideoTrack *createVideoTrack(uint32 width, uint32 height, uint32 frameCount, const Common::Rational &frameRate, uint32 flags, uint32 signature) const;
private:
- bool _lowRes;
+ bool _lowRes;
};
class Movie {
diff --git a/engines/toon/picture.cpp b/engines/toon/picture.cpp
index 204b0fe576..f59cdca064 100644
--- a/engines/toon/picture.cpp
+++ b/engines/toon/picture.cpp
@@ -71,7 +71,7 @@ bool Picture::loadPicture(const Common::String &file) {
_data = new uint8[decSize + 100];
_paletteEntries = READ_LE_UINT16(fileData + 14) / 3;
_useFullPalette = (_paletteEntries == 256);
-
+
if (_paletteEntries) {
_palette = new uint8[_paletteEntries * 3];
memcpy(_palette, fileData + 16, _paletteEntries * 3);
diff --git a/engines/touche/staticres.cpp b/engines/touche/staticres.cpp
index c18a947358..23b76558e4 100644
--- a/engines/touche/staticres.cpp
+++ b/engines/touche/staticres.cpp
@@ -471,7 +471,10 @@ const uint16 Graphics::_freGerFontOffs[] = {
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x1920
+ 0x0000, 0x0000, 0x0000, 0x1920, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000
};
const int Graphics::_freGerFontSize = ARRAYSIZE(Graphics::_freGerFontOffs);
diff --git a/engines/tsage/blue_force/blueforce_scenes3.cpp b/engines/tsage/blue_force/blueforce_scenes3.cpp
index 22c831f531..81e4af6e97 100644
--- a/engines/tsage/blue_force/blueforce_scenes3.cpp
+++ b/engines/tsage/blue_force/blueforce_scenes3.cpp
@@ -346,6 +346,14 @@ void Scene300::postInit(SceneObjectList *OwnerList) {
break;
}
+ if (BF_GLOBALS.getFlag(onBike) && !BF_GLOBALS.getFlag(onDuty)) {
+ BF_GLOBALS._sound1.play(30);
+ } else if ((BF_GLOBALS._dayNumber == 2) && (BF_GLOBALS._bookmark < bEndDayOne)) {
+ BF_GLOBALS._sound1.changeSound(49);
+ } else if (BF_GLOBALS._sceneManager._previousScene != 190) {
+ BF_GLOBALS._sound1.changeSound(33);
+ }
+
_item10.setDetails(4, 300, 7, 13, 16, 1);
_item11.setDetails(2, 300, 9, 13, 18, 1);
_item12.setDetails(5, 300, 10, 13, 19, 1);
diff --git a/engines/tsage/blue_force/blueforce_scenes7.cpp b/engines/tsage/blue_force/blueforce_scenes7.cpp
index bb29ad1f34..4cdd2f3f15 100644
--- a/engines/tsage/blue_force/blueforce_scenes7.cpp
+++ b/engines/tsage/blue_force/blueforce_scenes7.cpp
@@ -159,7 +159,7 @@ void Scene710::postInit(SceneObjectList *OwnerList) {
_stripManager.addSpeaker(&_skipSpeaker);
_stripManager.addSpeaker(&_lauraSpeaker);
_stripManager.addSpeaker(&_gameTextSpeaker);
-
+
_kid.postInit();
_kid._moveDiff = Common::Point(4, 2);
_laura.postInit();
diff --git a/engines/tsage/blue_force/blueforce_speakers.cpp b/engines/tsage/blue_force/blueforce_speakers.cpp
index 8af18b43b8..2a57616640 100644
--- a/engines/tsage/blue_force/blueforce_speakers.cpp
+++ b/engines/tsage/blue_force/blueforce_speakers.cpp
@@ -809,7 +809,7 @@ void SpeakerGiggles::setText(const Common::String &msg) {
SpeakerFBI::SpeakerFBI(): VisualSpeaker() {
_color1 = 27;
_color2 = 89;
-
+
_speakerName = "FBI";
}
@@ -832,7 +832,7 @@ void SpeakerFBI::setText(const Common::String &msg) {
SpeakerNico::SpeakerNico(): VisualSpeaker() {
_color1 = 105;
_color2 = 102;
-
+
_speakerName = "NICO";
}
@@ -845,7 +845,7 @@ void SpeakerNico::setText(const Common::String &msg) {
_object1.fixPriority(254);
_object1.setPosition(Common::Point(BF_GLOBALS._sceneManager._scene->_sceneBounds.left + 262,
BF_GLOBALS._sceneManager._scene->_sceneBounds.top + 166));
-
+
_object2.postInit();
_object2.setVisage(905);
_object2.setStrip2(1);
@@ -862,7 +862,7 @@ void SpeakerNico::setText(const Common::String &msg) {
SpeakerDA::SpeakerDA(): VisualSpeaker() {
_color1 = 82;
_color2 = 80;
-
+
_speakerName = "DA";
}
@@ -875,7 +875,7 @@ void SpeakerDA::setText(const Common::String &msg) {
_object1.fixPriority(254);
_object1.setPosition(Common::Point(BF_GLOBALS._sceneManager._scene->_sceneBounds.left + 84,
BF_GLOBALS._sceneManager._scene->_sceneBounds.top + 166));
-
+
_object2.postInit();
_object2.setVisage(915);
_object2.setStrip2(1);
@@ -892,7 +892,7 @@ void SpeakerDA::setText(const Common::String &msg) {
SpeakerGrandma::SpeakerGrandma(): VisualSpeaker() {
_color1 = 20;
_color2 = 23;
-
+
_speakerName = "GRANDMA";
}
@@ -905,7 +905,7 @@ void SpeakerGrandma::setText(const Common::String &msg) {
_object1.fixPriority(254);
_object1.setPosition(Common::Point(BF_GLOBALS._sceneManager._scene->_sceneBounds.left + 43,
BF_GLOBALS._sceneManager._scene->_sceneBounds.top + 166));
-
+
_object2.postInit();
_object2.setVisage(274);
_object2.setStrip2(3);
@@ -922,7 +922,7 @@ void SpeakerGrandma::setText(const Common::String &msg) {
SpeakerLyle::SpeakerLyle(): VisualSpeaker() {
_color1 = 29;
_color2 = 89;
-
+
_speakerName = "LYLE";
}
@@ -935,7 +935,7 @@ void SpeakerLyle::setText(const Common::String &msg) {
_object1.fixPriority(254);
_object1.setPosition(Common::Point(BF_GLOBALS._sceneManager._scene->_sceneBounds.left + 75,
BF_GLOBALS._sceneManager._scene->_sceneBounds.top + 166));
-
+
_object2.postInit();
_object2.setVisage(278);
_object2.setStrip2(1);
@@ -952,7 +952,7 @@ void SpeakerLyle::setText(const Common::String &msg) {
SpeakerGranText::SpeakerGranText(): VisualSpeaker() {
_color1 = 20;
_color2 = 23;
-
+
_speakerName = "GRANTEXT";
}
@@ -961,7 +961,7 @@ SpeakerGranText::SpeakerGranText(): VisualSpeaker() {
SpeakerLyleText::SpeakerLyleText(): VisualSpeaker() {
_color1 = 29;
_color2 = 89;
-
+
_speakerName = "LYLETEXT";
}
@@ -969,7 +969,7 @@ SpeakerLyleText::SpeakerLyleText(): VisualSpeaker() {
SpeakerKate::SpeakerKate(): VisualSpeaker() {
_color1 = 108;
-
+
_speakerName = "KATE";
}
@@ -982,7 +982,7 @@ void SpeakerKate::setText(const Common::String &msg) {
_object1.fixPriority(254);
_object1.setPosition(Common::Point(BF_GLOBALS._sceneManager._scene->_sceneBounds.left + 270,
BF_GLOBALS._sceneManager._scene->_sceneBounds.top + 166));
-
+
_object2.postInit();
_object2.setVisage(122);
_object2.setStrip2(1);
@@ -1000,7 +1000,7 @@ void SpeakerKate::setText(const Common::String &msg) {
SpeakerTony::SpeakerTony(): VisualSpeaker() {
_color1 = 108;
_color2 = 8;
-
+
_speakerName = "TONY";
}
diff --git a/engines/tsage/blue_force/blueforce_speakers.h b/engines/tsage/blue_force/blueforce_speakers.h
index 508279a929..e406a50fbe 100644
--- a/engines/tsage/blue_force/blueforce_speakers.h
+++ b/engines/tsage/blue_force/blueforce_speakers.h
@@ -290,7 +290,7 @@ public:
virtual Common::String getClassName() { return "FBI"; }
virtual void setText(const Common::String &msg);
};
-
+
class SpeakerNico: public VisualSpeaker {
public:
SpeakerNico();
@@ -340,7 +340,7 @@ public:
class SpeakerKate: public VisualSpeaker {
public:
SpeakerKate();
-
+
virtual Common::String getClassName() { return "SpeakerKate"; }
virtual void setText(const Common::String &msg);
};
@@ -348,7 +348,7 @@ public:
class SpeakerTony: public VisualSpeaker {
public:
SpeakerTony();
-
+
virtual Common::String getClassName() { return "SpeakerTony"; }
virtual void setText(const Common::String &msg);
};
diff --git a/engines/tsage/detection.cpp b/engines/tsage/detection.cpp
index bcadfdc201..a35d663b93 100644
--- a/engines/tsage/detection.cpp
+++ b/engines/tsage/detection.cpp
@@ -156,7 +156,7 @@ public:
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const {
Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(
generateGameStateFileName(target, slot));
-
+
if (f) {
TsAGE::tSageSavegameHeader header;
TsAGE::Saver::readSavegameHeader(f, header);
diff --git a/engines/tsage/globals.cpp b/engines/tsage/globals.cpp
index de9463268b..4589a926c9 100644
--- a/engines/tsage/globals.cpp
+++ b/engines/tsage/globals.cpp
@@ -205,7 +205,7 @@ void Globals::dispatchSounds() {
void TsAGE2Globals::reset() {
Globals::reset();
-
+
// Reset the inventory
T2_GLOBALS._uiElements.updateInventory();
T2_GLOBALS._uiElements._scoreValue = 0;
@@ -277,7 +277,7 @@ void BlueForceGlobals::synchronize(Serializer &s) {
void BlueForceGlobals::reset() {
TsAGE2Globals::reset();
_scenePalette.clearListeners();
-
+
_scrollFollower = &_player;
_bookmark = bNone;
@@ -368,7 +368,7 @@ namespace Ringworld2 {
void Ringworld2Globals::reset() {
Globals::reset();
-
+
// Reset the inventory
R2_INVENTORY.reset();
T2_GLOBALS._uiElements.updateInventory();
@@ -526,7 +526,7 @@ void Ringworld2Globals::synchronize(Serializer &s) {
for (i = 0; i < MAX_CHARACTERS; ++i)
s.syncAsByte(_v565F1[i]);
-
+
s.syncAsByte(_v565AE);
s.syncAsByte(_v566A4);
s.syncAsByte(_v566A5);
diff --git a/engines/tsage/ringworld/ringworld_logic.cpp b/engines/tsage/ringworld/ringworld_logic.cpp
index 7d571b40d7..0584570ac2 100644
--- a/engines/tsage/ringworld/ringworld_logic.cpp
+++ b/engines/tsage/ringworld/ringworld_logic.cpp
@@ -610,7 +610,7 @@ void NamedHotspot::doAction(int action) {
case CURSOR_USE:
if (_useLineNum == -1)
break;
-
+
SceneItem::display(_resNum, _useLineNum, SET_Y, 20, SET_WIDTH, 200, SET_EXT_BGCOLOR, 7, LIST_END);
return;
case CURSOR_TALK:
diff --git a/engines/tsage/ringworld2/ringworld2_logic.cpp b/engines/tsage/ringworld2/ringworld2_logic.cpp
index a06899fe5a..97042cb621 100644
--- a/engines/tsage/ringworld2/ringworld2_logic.cpp
+++ b/engines/tsage/ringworld2/ringworld2_logic.cpp
@@ -1695,7 +1695,7 @@ bool AnimationPlayer::load(int animId, Action *endAction) {
_playbackTickPrior = -1;
_playbackTick = 0;
- // The final multiplication is used to deliberately slow down playback, since the original
+ // The final multiplication is used to deliberately slow down playback, since the original
// was slowed down by the amount of time spent to decode and display the frames
_frameDelay = (60 / _subData._frameRate) * 8;
_gameFrame = R2_GLOBALS._events.getFrameNumber();
@@ -1706,7 +1706,7 @@ bool AnimationPlayer::load(int animId, Action *endAction) {
int v = (_subData._sliceSize + 2) * _subData._ySlices * _subData._framesPerSlices;
_dataNeeded = (_subData._field16 / _subData._framesPerSlices) + v + 96;
}
-
+
debugC(1, ktSageDebugGraphics, "Data needed %d", _dataNeeded);
// Set up animation data objects
@@ -1760,7 +1760,7 @@ bool AnimationPlayer::load(int animId, Action *endAction) {
byte r = _subData._palData[idx * 3];
byte g = _subData._palData[idx * 3 + 1];
byte b = _subData._palData[idx * 3 + 2];
-
+
int palIndex = R2_GLOBALS._scenePalette.indexOf(r, g, b);
_palIndexes[idx] = palIndex;
}
diff --git a/engines/tsage/scenes.h b/engines/tsage/scenes.h
index 2daa71ba98..d5ac88c692 100644
--- a/engines/tsage/scenes.h
+++ b/engines/tsage/scenes.h
@@ -67,7 +67,7 @@ public:
void setZoomPercents(int yStart, int minPercent, int yEnd, int maxPercent);
void loadBackground(int xAmount, int yAmount);
-
+
void loadSceneData(int sceneNum);
};
diff --git a/engines/tsage/tsage.cpp b/engines/tsage/tsage.cpp
index 40f4dfcfd2..87697f950b 100644
--- a/engines/tsage/tsage.cpp
+++ b/engines/tsage/tsage.cpp
@@ -45,7 +45,7 @@ TSageEngine::TSageEngine(OSystem *system, const tSageGameDescription *gameDesc)
else if (g_vm->getGameID() == GType_BlueForce)
_debugger = new BlueForceDebugger();
else if (g_vm->getGameID() == GType_Ringworld2)
- _debugger = new Ringworld2Debugger();
+ _debugger = new Ringworld2Debugger();
}
Common::Error TSageEngine::init() {
@@ -92,7 +92,7 @@ void TSageEngine::initialize() {
g_resourceManager->addLib("TSAGE.RLB");
}
g_globals = new BlueForce::BlueForceGlobals();
-
+
// Setup the user interface
T2_GLOBALS._uiElements.setup(Common::Point(0, UI_INTERFACE_Y - 2));
@@ -107,7 +107,7 @@ void TSageEngine::initialize() {
// Reset all global variables
R2_GLOBALS.reset();
- }
+ }
g_globals->gfxManager().setDefaults();
diff --git a/engines/tucker/resource.cpp b/engines/tucker/resource.cpp
index bee09f7391..1b04f3fae9 100644
--- a/engines/tucker/resource.cpp
+++ b/engines/tucker/resource.cpp
@@ -29,6 +29,9 @@
#include "audio/decoders/vorbis.h"
#include "audio/decoders/wave.h"
+#include "graphics/surface.h"
+#include "graphics/decoders/pcx.h"
+
#include "tucker/tucker.h"
#include "tucker/graphics.h"
@@ -298,23 +301,21 @@ void TuckerEngine::loadImage(const char *fname, uint8 *dst, int type) {
return;
}
}
- f.seek(128, SEEK_SET);
- int size = 0;
- while (size < 64000) {
- int code = f.readByte();
- if (code >= 0xC0) {
- const int sz = code - 0xC0;
- code = f.readByte();
- memset(dst + size, code, sz);
- size += sz;
- } else {
- dst[size++] = code;
- }
- }
+
+ ::Graphics::PCXDecoder pcx;
+ if (!pcx.loadStream(f))
+ error("Error while reading PCX image");
+
+ const ::Graphics::Surface *pcxSurface = pcx.getSurface();
+ if (pcxSurface->format.bytesPerPixel != 1)
+ error("Invalid bytes per pixel in PCX surface (%d)", pcxSurface->format.bytesPerPixel);
+ if (pcxSurface->w != 320 || pcxSurface->h != 200)
+ error("Invalid PCX surface size (%d x %d)", pcxSurface->w, pcxSurface->h);
+ for (uint16 y = 0; y < pcxSurface->h; y++)
+ memcpy(dst + y * 320, pcxSurface->getBasePtr(0, y), pcxSurface->w);
+
if (type != 0) {
- if (f.readByte() != 12)
- return;
- f.read(_currentPalette, 768);
+ memcpy(_currentPalette, pcx.getPalette(), 3 * 256);
setBlackPalette();
}
}
diff --git a/engines/wintermute/ad/ad_actor.cpp b/engines/wintermute/ad/ad_actor.cpp
index 9087d66844..d175855d1e 100644
--- a/engines/wintermute/ad/ad_actor.cpp
+++ b/engines/wintermute/ad/ad_actor.cpp
@@ -602,13 +602,13 @@ bool AdActor::update() {
}
// finished playing animation?
- if (_state == STATE_PLAYING_ANIM && _animSprite != NULL && _animSprite->_finished) {
+ if (_state == STATE_PLAYING_ANIM && _animSprite != NULL && _animSprite->isFinished()) {
_state = _nextState;
_nextState = STATE_READY;
_currentSprite = _animSprite;
}
- if (_state == STATE_PLAYING_ANIM_SET && _animSprite2 != NULL && _animSprite2->_finished) {
+ if (_state == STATE_PLAYING_ANIM_SET && _animSprite2 != NULL && _animSprite2->isFinished()) {
_state = _nextState;
_nextState = STATE_READY;
_currentSprite = _animSprite2;
@@ -649,7 +649,7 @@ bool AdActor::update() {
//////////////////////////////////////////////////////////////////////////
case STATE_TURNING_LEFT:
- if (_tempSprite2 == NULL || _tempSprite2->_finished) {
+ if (_tempSprite2 == NULL || _tempSprite2->isFinished()) {
if (_dir > 0) {
_dir = (TDirection)(_dir - 1);
} else {
@@ -686,7 +686,7 @@ bool AdActor::update() {
//////////////////////////////////////////////////////////////////////////
case STATE_TURNING_RIGHT:
- if (_tempSprite2 == NULL || _tempSprite2->_finished) {
+ if (_tempSprite2 == NULL || _tempSprite2->isFinished()) {
_dir = (TDirection)(_dir + 1);
if ((int)_dir >= (int)NUM_DIRECTIONS) {
@@ -753,7 +753,7 @@ bool AdActor::update() {
}
bool timeIsUp = (_sentence->_sound && _sentence->_soundStarted && (!_sentence->_sound->isPlaying() && !_sentence->_sound->isPaused())) || (!_sentence->_sound && _sentence->_duration <= _gameRef->_timer - _sentence->_startTime);
- if (_tempSprite2 == NULL || _tempSprite2->_finished || (/*_tempSprite2->_looping &&*/ timeIsUp)) {
+ if (_tempSprite2 == NULL || _tempSprite2->isFinished() || (/*_tempSprite2->_looping &&*/ timeIsUp)) {
if (timeIsUp) {
_sentence->finish();
_tempSprite2 = NULL;
@@ -798,7 +798,7 @@ bool AdActor::update() {
if (_currentSprite && !already_moved) {
_currentSprite->getCurrentFrame(_zoomable ? ((AdGame *)_gameRef)->_scene->getZoomAt(_posX, _posY) : 100, _zoomable ? ((AdGame *)_gameRef)->_scene->getZoomAt(_posX, _posY) : 100);
- if (_currentSprite->_changed) {
+ if (_currentSprite->isChanged()) {
_posX += _currentSprite->_moveX;
_posY += _currentSprite->_moveY;
afterMove();
@@ -830,7 +830,7 @@ void AdActor::followPath() {
// are there points to follow?
if (_path->getCurrent() != NULL) {
- _state = STATE_FOLLOWING_PATH;;
+ _state = STATE_FOLLOWING_PATH;
initLine(BasePoint(_posX, _posY), *_path->getCurrent());
} else {
if (_afterWalkDir != DI_NONE) {
@@ -858,7 +858,7 @@ void AdActor::getNextStep() {
}
_currentSprite->getCurrentFrame(_zoomable ? ((AdGame *)_gameRef)->_scene->getZoomAt(_posX, _posY) : 100, _zoomable ? ((AdGame *)_gameRef)->_scene->getZoomAt(_posX, _posY) : 100);
- if (!_currentSprite->_changed) {
+ if (!_currentSprite->isChanged()) {
return;
}
@@ -1075,27 +1075,27 @@ bool AdActor::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack,
//////////////////////////////////////////////////////////////////////////
-ScValue *AdActor::scGetProperty(const char *name) {
+ScValue *AdActor::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Direction
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Direction") == 0) {
+ if (name == "Direction") {
_scValue->setInt(_dir);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Type") == 0) {
+ else if (name == "Type") {
_scValue->setString("actor");
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// TalkAnimName
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "TalkAnimName") == 0) {
+ else if (name == "TalkAnimName") {
_scValue->setString(_talkAnimName);
return _scValue;
}
@@ -1103,7 +1103,7 @@ ScValue *AdActor::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// WalkAnimName
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "WalkAnimName") == 0) {
+ else if (name == "WalkAnimName") {
_scValue->setString(_walkAnimName);
return _scValue;
}
@@ -1111,7 +1111,7 @@ ScValue *AdActor::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// IdleAnimName
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "IdleAnimName") == 0) {
+ else if (name == "IdleAnimName") {
_scValue->setString(_idleAnimName);
return _scValue;
}
@@ -1119,7 +1119,7 @@ ScValue *AdActor::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// TurnLeftAnimName
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "TurnLeftAnimName") == 0) {
+ else if (name == "TurnLeftAnimName") {
_scValue->setString(_turnLeftAnimName);
return _scValue;
}
@@ -1127,7 +1127,7 @@ ScValue *AdActor::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// TurnRightAnimName
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "TurnRightAnimName") == 0) {
+ else if (name == "TurnRightAnimName") {
_scValue->setString(_turnRightAnimName);
return _scValue;
} else {
@@ -1351,7 +1351,7 @@ bool AdActor::persist(BasePersistenceManager *persistMgr) {
//////////////////////////////////////////////////////////////////////////
TDirection AdActor::angleToDirection(int angle) {
- TDirection ret = DI_DOWN;;
+ TDirection ret = DI_DOWN;
if (angle > -112 && angle <= -67) {
ret = DI_UP;
diff --git a/engines/wintermute/ad/ad_actor.h b/engines/wintermute/ad/ad_actor.h
index 271e57cb85..543c9d063a 100644
--- a/engines/wintermute/ad/ad_actor.h
+++ b/engines/wintermute/ad/ad_actor.h
@@ -83,7 +83,7 @@ private:
AdSpriteSet *getAnimByName(const Common::String &animName);
// scripting interface
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scSetProperty(const char *name, ScValue *value);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
diff --git a/engines/wintermute/ad/ad_entity.cpp b/engines/wintermute/ad/ad_entity.cpp
index 234af1fffa..9af7e034ca 100644
--- a/engines/wintermute/ad/ad_entity.cpp
+++ b/engines/wintermute/ad/ad_entity.cpp
@@ -28,28 +28,29 @@
#include "engines/wintermute/ad/ad_entity.h"
-#include "engines/wintermute/base/base_parser.h"
-#include "engines/wintermute/base/base_dynamic_buffer.h"
-#include "engines/wintermute/base/base_active_rect.h"
-#include "engines/wintermute/base/base_surface_storage.h"
-#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/ad/ad_game.h"
#include "engines/wintermute/ad/ad_scene.h"
-#include "engines/wintermute/base/sound/base_sound.h"
#include "engines/wintermute/ad/ad_waypoint_group.h"
-#include "engines/wintermute/base/font/base_font_storage.h"
-#include "engines/wintermute/base/font/base_font.h"
#include "engines/wintermute/ad/ad_sentence.h"
+#include "engines/wintermute/base/base_active_rect.h"
+#include "engines/wintermute/base/base_dynamic_buffer.h"
+#include "engines/wintermute/base/base_file_manager.h"
+#include "engines/wintermute/base/base_game.h"
+#include "engines/wintermute/base/base_parser.h"
#include "engines/wintermute/base/base_region.h"
#include "engines/wintermute/base/base_sprite.h"
-#include "engines/wintermute/base/base_file_manager.h"
-#include "engines/wintermute/platform_osystem.h"
-#include "engines/wintermute/utils/utils.h"
+#include "engines/wintermute/base/base_surface_storage.h"
+#include "engines/wintermute/base/font/base_font_storage.h"
+#include "engines/wintermute/base/font/base_font.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
+#include "engines/wintermute/base/particles/part_emitter.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
+#include "engines/wintermute/base/sound/base_sound.h"
#include "engines/wintermute/video/video_theora_player.h"
-#include "engines/wintermute/base/particles/part_emitter.h"
+#include "engines/wintermute/utils/utils.h"
+#include "engines/wintermute/platform_osystem.h"
#include "common/str.h"
namespace Wintermute {
@@ -577,7 +578,7 @@ bool AdEntity::update() {
}
// finished playing animation?
- if (_state == STATE_PLAYING_ANIM && _animSprite != NULL && _animSprite->_finished) {
+ if (_state == STATE_PLAYING_ANIM && _animSprite != NULL && _animSprite->isFinished()) {
_state = STATE_READY;
_currentSprite = _animSprite;
}
@@ -612,7 +613,7 @@ bool AdEntity::update() {
}
bool timeIsUp = (_sentence->_sound && _sentence->_soundStarted && (!_sentence->_sound->isPlaying() && !_sentence->_sound->isPaused())) || (!_sentence->_sound && _sentence->_duration <= _gameRef->_timer - _sentence->_startTime);
- if (_tempSprite2 == NULL || _tempSprite2->_finished || (/*_tempSprite2->_looping &&*/ timeIsUp)) {
+ if (_tempSprite2 == NULL || _tempSprite2->isFinished() || (/*_tempSprite2->_looping &&*/ timeIsUp)) {
if (timeIsUp) {
_sentence->finish();
_tempSprite2 = NULL;
@@ -638,7 +639,7 @@ bool AdEntity::update() {
if (_currentSprite) {
_currentSprite->getCurrentFrame(_zoomable ? ((AdGame *)_gameRef)->_scene->getZoomAt(_posX, _posY) : 100);
- if (_currentSprite->_changed) {
+ if (_currentSprite->isChanged()) {
_posX += _currentSprite->_moveX;
_posY += _currentSprite->_moveY;
}
@@ -828,13 +829,13 @@ bool AdEntity::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack
//////////////////////////////////////////////////////////////////////////
-ScValue *AdEntity::scGetProperty(const char *name) {
+ScValue *AdEntity::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type (RO)
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("entity");
return _scValue;
}
@@ -842,7 +843,7 @@ ScValue *AdEntity::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Item
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Item") == 0) {
+ else if (name == "Item") {
if (_item) {
_scValue->setString(_item);
} else {
@@ -855,7 +856,7 @@ ScValue *AdEntity::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Subtype (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Subtype") == 0) {
+ else if (name == "Subtype") {
if (_subtype == ENTITY_SOUND) {
_scValue->setString("sound");
} else {
@@ -868,7 +869,7 @@ ScValue *AdEntity::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// WalkToX
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "WalkToX") == 0) {
+ else if (name == "WalkToX") {
_scValue->setInt(_walkToX);
return _scValue;
}
@@ -876,7 +877,7 @@ ScValue *AdEntity::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// WalkToY
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "WalkToY") == 0) {
+ else if (name == "WalkToY") {
_scValue->setInt(_walkToY);
return _scValue;
}
@@ -884,7 +885,7 @@ ScValue *AdEntity::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// WalkToDirection
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "WalkToDirection") == 0) {
+ else if (name == "WalkToDirection") {
_scValue->setInt((int)_walkToDir);
return _scValue;
}
@@ -892,7 +893,7 @@ ScValue *AdEntity::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Region (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Region") == 0) {
+ else if (name == "Region") {
if (_region) {
_scValue->setNative(_region, true);
} else {
diff --git a/engines/wintermute/ad/ad_entity.h b/engines/wintermute/ad/ad_entity.h
index 39dc133eef..415987e50a 100644
--- a/engines/wintermute/ad/ad_entity.h
+++ b/engines/wintermute/ad/ad_entity.h
@@ -56,7 +56,7 @@ public:
TEntityType _subtype;
// scripting interface
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scSetProperty(const char *name, ScValue *value);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
diff --git a/engines/wintermute/ad/ad_game.cpp b/engines/wintermute/ad/ad_game.cpp
index fe8a5991e2..4481b774c1 100644
--- a/engines/wintermute/ad/ad_game.cpp
+++ b/engines/wintermute/ad/ad_game.cpp
@@ -50,6 +50,7 @@
#include "engines/wintermute/base/base_viewport.h"
#include "engines/wintermute/base/particles/part_emitter.h"
#include "engines/wintermute/base/saveload.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/scriptables/script_engine.h"
#include "engines/wintermute/base/scriptables/script.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
@@ -875,20 +876,20 @@ bool AdGame::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack,
//////////////////////////////////////////////////////////////////////////
-ScValue *AdGame::scGetProperty(const char *name) {
+ScValue *AdGame::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("game");
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Scene
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Scene") == 0) {
+ else if (name == "Scene") {
if (_scene) {
_scValue->setNative(_scene, true);
} else {
@@ -900,7 +901,7 @@ ScValue *AdGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// SelectedItem
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "SelectedItem") == 0) {
+ else if (name == "SelectedItem") {
//if (_selectedItem) _scValue->setString(_selectedItem->_name);
if (_selectedItem) {
_scValue->setNative(_selectedItem, true);
@@ -913,14 +914,14 @@ ScValue *AdGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// NumItems
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "NumItems") == 0) {
+ else if (name == "NumItems") {
return _invObject->scGetProperty(name);
}
//////////////////////////////////////////////////////////////////////////
// SmartItemCursor
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "SmartItemCursor") == 0) {
+ else if (name == "SmartItemCursor") {
_scValue->setBool(_smartItemCursor);
return _scValue;
}
@@ -928,7 +929,7 @@ ScValue *AdGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// InventoryVisible
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "InventoryVisible") == 0) {
+ else if (name == "InventoryVisible") {
_scValue->setBool(_inventoryBox && _inventoryBox->_visible);
return _scValue;
}
@@ -936,7 +937,7 @@ ScValue *AdGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// InventoryScrollOffset
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "InventoryScrollOffset") == 0) {
+ else if (name == "InventoryScrollOffset") {
if (_inventoryBox) {
_scValue->setInt(_inventoryBox->_scrollOffset);
} else {
@@ -949,7 +950,7 @@ ScValue *AdGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// ResponsesVisible (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "ResponsesVisible") == 0) {
+ else if (name == "ResponsesVisible") {
_scValue->setBool(_stateEx == GAME_WAITING_RESPONSE);
return _scValue;
}
@@ -957,7 +958,7 @@ ScValue *AdGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// PrevScene / PreviousScene (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "PrevScene") == 0 || strcmp(name, "PreviousScene") == 0) {
+ else if (name == "PrevScene" || name == "PreviousScene") {
if (!_prevSceneName) {
_scValue->setString("");
} else {
@@ -969,7 +970,7 @@ ScValue *AdGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// PrevSceneFilename / PreviousSceneFilename (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "PrevSceneFilename") == 0 || strcmp(name, "PreviousSceneFilename") == 0) {
+ else if (name == "PrevSceneFilename" || name == "PreviousSceneFilename") {
if (!_prevSceneFilename) {
_scValue->setString("");
} else {
@@ -981,7 +982,7 @@ ScValue *AdGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// LastResponse (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "LastResponse") == 0) {
+ else if (name == "LastResponse") {
if (!_responseBox || !_responseBox->_lastResponseText) {
_scValue->setString("");
} else {
@@ -993,7 +994,7 @@ ScValue *AdGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// LastResponseOrig (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "LastResponseOrig") == 0) {
+ else if (name == "LastResponseOrig") {
if (!_responseBox || !_responseBox->_lastResponseTextOrig) {
_scValue->setString("");
} else {
@@ -1005,7 +1006,7 @@ ScValue *AdGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// InventoryObject
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "InventoryObject") == 0) {
+ else if (name == "InventoryObject") {
if (_inventoryOwner == _invObject) {
_scValue->setNative(this, true);
} else {
@@ -1018,7 +1019,7 @@ ScValue *AdGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// TotalNumItems
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "TotalNumItems") == 0) {
+ else if (name == "TotalNumItems") {
_scValue->setInt(_items.size());
return _scValue;
}
@@ -1026,7 +1027,7 @@ ScValue *AdGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// TalkSkipButton
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "TalkSkipButton") == 0) {
+ else if (name == "TalkSkipButton") {
_scValue->setInt(_talkSkipButton);
return _scValue;
}
@@ -1034,7 +1035,7 @@ ScValue *AdGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// ChangingScene
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "ChangingScene") == 0) {
+ else if (name == "ChangingScene") {
_scValue->setBool(_scheduledScene != NULL);
return _scValue;
}
@@ -1042,7 +1043,7 @@ ScValue *AdGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// StartupScene
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "StartupScene") == 0) {
+ else if (name == "StartupScene") {
if (!_startupScene) {
_scValue->setNULL();
} else {
diff --git a/engines/wintermute/ad/ad_game.h b/engines/wintermute/ad/ad_game.h
index 46427331bf..81c79a3da8 100644
--- a/engines/wintermute/ad/ad_game.h
+++ b/engines/wintermute/ad/ad_game.h
@@ -126,7 +126,7 @@ public:
bool loadItemsBuffer(byte *buffer, bool merge = false);
// scripting interface
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scSetProperty(const char *name, ScValue *value);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
bool validMouse();
diff --git a/engines/wintermute/ad/ad_inventory_box.cpp b/engines/wintermute/ad/ad_inventory_box.cpp
index 16b8e01ff3..7ae8ff8d69 100644
--- a/engines/wintermute/ad/ad_inventory_box.cpp
+++ b/engines/wintermute/ad/ad_inventory_box.cpp
@@ -35,6 +35,7 @@
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/base_viewport.h"
#include "engines/wintermute/base/base_dynamic_buffer.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/ui/ui_button.h"
#include "engines/wintermute/ui/ui_window.h"
#include "engines/wintermute/platform_osystem.h"
diff --git a/engines/wintermute/ad/ad_item.cpp b/engines/wintermute/ad/ad_item.cpp
index afd813933b..427b1c7db4 100644
--- a/engines/wintermute/ad/ad_item.cpp
+++ b/engines/wintermute/ad/ad_item.cpp
@@ -36,11 +36,11 @@
#include "engines/wintermute/base/base_parser.h"
#include "engines/wintermute/base/sound/base_sound.h"
#include "engines/wintermute/base/base_sprite.h"
-#include "engines/wintermute/utils/utils.h"
-#include "engines/wintermute/platform_osystem.h"
#include "engines/wintermute/base/scriptables/script.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "engines/wintermute/base/scriptables/script_value.h"
+#include "engines/wintermute/utils/utils.h"
+#include "engines/wintermute/platform_osystem.h"
#include "common/str.h"
namespace Wintermute {
@@ -340,7 +340,7 @@ bool AdItem::update() {
}
// finished playing animation?
- if (_state == STATE_PLAYING_ANIM && _animSprite != NULL && _animSprite->_finished) {
+ if (_state == STATE_PLAYING_ANIM && _animSprite != NULL && _animSprite->isFinished()) {
_state = STATE_READY;
_currentSprite = _animSprite;
}
@@ -379,7 +379,7 @@ bool AdItem::update() {
}
bool timeIsUp = (_sentence->_sound && _sentence->_soundStarted && (!_sentence->_sound->isPlaying() && !_sentence->_sound->isPaused())) || (!_sentence->_sound && _sentence->_duration <= _gameRef->_timer - _sentence->_startTime);
- if (_tempSprite2 == NULL || _tempSprite2->_finished || (/*_tempSprite2->_looping &&*/ timeIsUp)) {
+ if (_tempSprite2 == NULL || _tempSprite2->isFinished() || (/*_tempSprite2->_looping &&*/ timeIsUp)) {
if (timeIsUp) {
_sentence->finish();
_tempSprite2 = NULL;
@@ -614,13 +614,13 @@ bool AdItem::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack,
//////////////////////////////////////////////////////////////////////////
-ScValue *AdItem::scGetProperty(const char *name) {
+ScValue *AdItem::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("item");
return _scValue;
}
@@ -628,7 +628,7 @@ ScValue *AdItem::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Name
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Name") == 0) {
+ else if (name == "Name") {
_scValue->setString(getName());
return _scValue;
}
@@ -636,7 +636,7 @@ ScValue *AdItem::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// DisplayAmount
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "DisplayAmount") == 0) {
+ else if (name == "DisplayAmount") {
_scValue->setBool(_displayAmount);
return _scValue;
}
@@ -644,7 +644,7 @@ ScValue *AdItem::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Amount
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Amount") == 0) {
+ else if (name == "Amount") {
_scValue->setInt(_amount);
return _scValue;
}
@@ -652,7 +652,7 @@ ScValue *AdItem::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// AmountOffsetX
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "AmountOffsetX") == 0) {
+ else if (name == "AmountOffsetX") {
_scValue->setInt(_amountOffsetX);
return _scValue;
}
@@ -660,7 +660,7 @@ ScValue *AdItem::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// AmountOffsetY
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "AmountOffsetY") == 0) {
+ else if (name == "AmountOffsetY") {
_scValue->setInt(_amountOffsetY);
return _scValue;
}
@@ -668,7 +668,7 @@ ScValue *AdItem::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// AmountAlign
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "AmountAlign") == 0) {
+ else if (name == "AmountAlign") {
_scValue->setInt(_amountAlign);
return _scValue;
}
@@ -676,7 +676,7 @@ ScValue *AdItem::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// AmountString
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "AmountString") == 0) {
+ else if (name == "AmountString") {
if (!_amountString) {
_scValue->setNULL();
} else {
@@ -688,7 +688,7 @@ ScValue *AdItem::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// CursorCombined
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "CursorCombined") == 0) {
+ else if (name == "CursorCombined") {
_scValue->setBool(_cursorCombined);
return _scValue;
} else {
diff --git a/engines/wintermute/ad/ad_item.h b/engines/wintermute/ad/ad_item.h
index 6047c542c1..79978f9f72 100644
--- a/engines/wintermute/ad/ad_item.h
+++ b/engines/wintermute/ad/ad_item.h
@@ -51,7 +51,7 @@ public:
bool loadBuffer(byte *buffer, bool complete = true);
// scripting interface
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scSetProperty(const char *name, ScValue *value);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
diff --git a/engines/wintermute/ad/ad_layer.cpp b/engines/wintermute/ad/ad_layer.cpp
index 46b75b8b21..209c12b7a2 100644
--- a/engines/wintermute/ad/ad_layer.cpp
+++ b/engines/wintermute/ad/ad_layer.cpp
@@ -29,12 +29,12 @@
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/ad/ad_layer.h"
#include "engines/wintermute/ad/ad_scene_node.h"
-#include "engines/wintermute/base/base_parser.h"
#include "engines/wintermute/base/base_dynamic_buffer.h"
+#include "engines/wintermute/base/base_file_manager.h"
+#include "engines/wintermute/base/base_parser.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
-#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/platform_osystem.h"
#include "common/str.h"
@@ -376,13 +376,13 @@ bool AdLayer::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack,
//////////////////////////////////////////////////////////////////////////
-ScValue *AdLayer::scGetProperty(const char *name) {
+ScValue *AdLayer::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("layer");
return _scValue;
}
@@ -390,7 +390,7 @@ ScValue *AdLayer::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// NumNodes (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "NumNodes") == 0) {
+ else if (name == "NumNodes") {
_scValue->setInt(_nodes.size());
return _scValue;
}
@@ -398,7 +398,7 @@ ScValue *AdLayer::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Width
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Width") == 0) {
+ else if (name == "Width") {
_scValue->setInt(_width);
return _scValue;
}
@@ -406,7 +406,7 @@ ScValue *AdLayer::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Height
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Height") == 0) {
+ else if (name == "Height") {
_scValue->setInt(_height);
return _scValue;
}
@@ -414,7 +414,7 @@ ScValue *AdLayer::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Main (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Main") == 0) {
+ else if (name == "Main") {
_scValue->setBool(_main);
return _scValue;
}
@@ -422,7 +422,7 @@ ScValue *AdLayer::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// CloseUp
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "CloseUp") == 0) {
+ else if (name == "CloseUp") {
_scValue->setBool(_closeUp);
return _scValue;
}
@@ -430,7 +430,7 @@ ScValue *AdLayer::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Active
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Active") == 0) {
+ else if (name == "Active") {
_scValue->setBool(_active);
return _scValue;
} else {
diff --git a/engines/wintermute/ad/ad_layer.h b/engines/wintermute/ad/ad_layer.h
index bb5f73b13a..de65e2822f 100644
--- a/engines/wintermute/ad/ad_layer.h
+++ b/engines/wintermute/ad/ad_layer.h
@@ -47,7 +47,7 @@ public:
virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent);
// scripting interface
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scSetProperty(const char *name, ScValue *value);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
diff --git a/engines/wintermute/ad/ad_object.cpp b/engines/wintermute/ad/ad_object.cpp
index 6c77917979..7b91daab2e 100644
--- a/engines/wintermute/ad/ad_object.cpp
+++ b/engines/wintermute/ad/ad_object.cpp
@@ -37,18 +37,19 @@
#include "engines/wintermute/ad/ad_waypoint_group.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_frame.h"
-#include "engines/wintermute/base/sound/base_sound.h"
-#include "engines/wintermute/base/base_surface_storage.h"
+#include "engines/wintermute/base/base_sprite.h"
+#include "engines/wintermute/base/base_string_table.h"
#include "engines/wintermute/base/base_sub_frame.h"
+#include "engines/wintermute/base/base_surface_storage.h"
#include "engines/wintermute/base/font/base_font.h"
#include "engines/wintermute/base/font/base_font_storage.h"
-#include "engines/wintermute/base/base_sprite.h"
-#include "engines/wintermute/base/base_string_table.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
+#include "engines/wintermute/base/particles/part_emitter.h"
#include "engines/wintermute/base/scriptables/script_engine.h"
#include "engines/wintermute/base/scriptables/script.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "engines/wintermute/base/scriptables/script_value.h"
-#include "engines/wintermute/base/particles/part_emitter.h"
+#include "engines/wintermute/base/sound/base_sound.h"
#include "common/str.h"
#include "common/util.h"
@@ -658,13 +659,13 @@ bool AdObject::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack
//////////////////////////////////////////////////////////////////////////
-ScValue *AdObject::scGetProperty(const char *name) {
+ScValue *AdObject::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("object");
return _scValue;
}
@@ -672,7 +673,7 @@ ScValue *AdObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Active
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Active") == 0) {
+ else if (name == "Active") {
_scValue->setBool(_active);
return _scValue;
}
@@ -680,7 +681,7 @@ ScValue *AdObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// IgnoreItems
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "IgnoreItems") == 0) {
+ else if (name == "IgnoreItems") {
_scValue->setBool(_ignoreItems);
return _scValue;
}
@@ -688,7 +689,7 @@ ScValue *AdObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// SceneIndependent
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "SceneIndependent") == 0) {
+ else if (name == "SceneIndependent") {
_scValue->setBool(_sceneIndependent);
return _scValue;
}
@@ -696,7 +697,7 @@ ScValue *AdObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// SubtitlesWidth
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "SubtitlesWidth") == 0) {
+ else if (name == "SubtitlesWidth") {
_scValue->setInt(_subtitlesWidth);
return _scValue;
}
@@ -704,7 +705,7 @@ ScValue *AdObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// SubtitlesPosRelative
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "SubtitlesPosRelative") == 0) {
+ else if (name == "SubtitlesPosRelative") {
_scValue->setBool(_subtitlesModRelative);
return _scValue;
}
@@ -712,7 +713,7 @@ ScValue *AdObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// SubtitlesPosX
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "SubtitlesPosX") == 0) {
+ else if (name == "SubtitlesPosX") {
_scValue->setInt(_subtitlesModX);
return _scValue;
}
@@ -720,7 +721,7 @@ ScValue *AdObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// SubtitlesPosY
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "SubtitlesPosY") == 0) {
+ else if (name == "SubtitlesPosY") {
_scValue->setInt(_subtitlesModY);
return _scValue;
}
@@ -728,7 +729,7 @@ ScValue *AdObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// SubtitlesPosXCenter
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "SubtitlesPosXCenter") == 0) {
+ else if (name == "SubtitlesPosXCenter") {
_scValue->setBool(_subtitlesModXCenter);
return _scValue;
}
@@ -736,7 +737,7 @@ ScValue *AdObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// NumItems (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "NumItems") == 0) {
+ else if (name == "NumItems") {
_scValue->setInt(getInventory()->_takenItems.size());
return _scValue;
}
@@ -744,7 +745,7 @@ ScValue *AdObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// ParticleEmitter (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "ParticleEmitter") == 0) {
+ else if (name == "ParticleEmitter") {
if (_partEmitter) {
_scValue->setNative(_partEmitter, true);
} else {
@@ -757,7 +758,7 @@ ScValue *AdObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// NumAttachments (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "NumAttachments") == 0) {
+ else if (name == "NumAttachments") {
_scValue->setInt(_attachmentsPre.size() + _attachmentsPost.size());
return _scValue;
} else {
diff --git a/engines/wintermute/ad/ad_object.h b/engines/wintermute/ad/ad_object.h
index 8395f58cff..d1a20908e1 100644
--- a/engines/wintermute/ad/ad_object.h
+++ b/engines/wintermute/ad/ad_object.h
@@ -100,7 +100,7 @@ public:
AdRegion *_currentRegions[MAX_NUM_REGIONS];
// scripting interface
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scSetProperty(const char *name, ScValue *value);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
diff --git a/engines/wintermute/ad/ad_region.cpp b/engines/wintermute/ad/ad_region.cpp
index 88bd8201a2..c9f1553c9a 100644
--- a/engines/wintermute/ad/ad_region.cpp
+++ b/engines/wintermute/ad/ad_region.cpp
@@ -27,12 +27,12 @@
*/
#include "engines/wintermute/ad/ad_region.h"
-#include "engines/wintermute/base/base_parser.h"
#include "engines/wintermute/base/base_dynamic_buffer.h"
-#include "engines/wintermute/base/scriptables/script_value.h"
-#include "engines/wintermute/base/scriptables/script.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_file_manager.h"
+#include "engines/wintermute/base/base_parser.h"
+#include "engines/wintermute/base/scriptables/script_value.h"
+#include "engines/wintermute/base/scriptables/script.h"
namespace Wintermute {
@@ -242,13 +242,13 @@ bool AdRegion::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack
//////////////////////////////////////////////////////////////////////////
-ScValue *AdRegion::scGetProperty(const char *name) {
+ScValue *AdRegion::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("ad region");
return _scValue;
}
@@ -256,7 +256,7 @@ ScValue *AdRegion::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Name
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Name") == 0) {
+ else if (name == "Name") {
_scValue->setString(getName());
return _scValue;
}
@@ -264,7 +264,7 @@ ScValue *AdRegion::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Blocked
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Blocked") == 0) {
+ else if (name == "Blocked") {
_scValue->setBool(_blocked);
return _scValue;
}
@@ -272,7 +272,7 @@ ScValue *AdRegion::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Decoration
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Decoration") == 0) {
+ else if (name == "Decoration") {
_scValue->setBool(_decoration);
return _scValue;
}
@@ -280,7 +280,7 @@ ScValue *AdRegion::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Scale
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Scale") == 0) {
+ else if (name == "Scale") {
_scValue->setFloat(_zoom);
return _scValue;
}
@@ -288,7 +288,7 @@ ScValue *AdRegion::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// AlphaColor
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "AlphaColor") == 0) {
+ else if (name == "AlphaColor") {
_scValue->setInt((int)_alpha);
return _scValue;
} else {
diff --git a/engines/wintermute/ad/ad_region.h b/engines/wintermute/ad/ad_region.h
index a60cb9a3f2..6112900361 100644
--- a/engines/wintermute/ad/ad_region.h
+++ b/engines/wintermute/ad/ad_region.h
@@ -47,7 +47,7 @@ public:
virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent);
// scripting interface
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scSetProperty(const char *name, ScValue *value);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
diff --git a/engines/wintermute/ad/ad_response.cpp b/engines/wintermute/ad/ad_response.cpp
index 37f46118bf..a2225f2632 100644
--- a/engines/wintermute/ad/ad_response.cpp
+++ b/engines/wintermute/ad/ad_response.cpp
@@ -28,8 +28,8 @@
#include "engines/wintermute/ad/ad_response.h"
#include "engines/wintermute/base/base_game.h"
-#include "engines/wintermute/base/font/base_font_storage.h"
#include "engines/wintermute/base/base_sprite.h"
+#include "engines/wintermute/base/font/base_font_storage.h"
#include "engines/wintermute/utils/utils.h"
namespace Wintermute {
diff --git a/engines/wintermute/ad/ad_response_box.cpp b/engines/wintermute/ad/ad_response_box.cpp
index a27f1ca54b..fb31aa0bb8 100644
--- a/engines/wintermute/ad/ad_response_box.cpp
+++ b/engines/wintermute/ad/ad_response_box.cpp
@@ -27,19 +27,20 @@
*/
#include "engines/wintermute/ad/ad_game.h"
+#include "engines/wintermute/ad/ad_response.h"
#include "engines/wintermute/ad/ad_response_box.h"
+#include "engines/wintermute/base/base_dynamic_buffer.h"
+#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/base_parser.h"
+#include "engines/wintermute/base/base_sprite.h"
#include "engines/wintermute/base/base_surface_storage.h"
-#include "engines/wintermute/ui/ui_button.h"
-#include "engines/wintermute/ui/ui_window.h"
-#include "engines/wintermute/base/base_dynamic_buffer.h"
#include "engines/wintermute/base/font/base_font_storage.h"
#include "engines/wintermute/base/font/base_font.h"
-#include "engines/wintermute/ad/ad_response.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/scriptables/script.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
-#include "engines/wintermute/base/base_sprite.h"
-#include "engines/wintermute/base/base_file_manager.h"
+#include "engines/wintermute/ui/ui_button.h"
+#include "engines/wintermute/ui/ui_window.h"
#include "engines/wintermute/utils/utils.h"
#include "engines/wintermute/platform_osystem.h"
#include "engines/wintermute/wintermute.h"
diff --git a/engines/wintermute/ad/ad_rot_level.cpp b/engines/wintermute/ad/ad_rot_level.cpp
index ca7ed693ad..fb9a4a47b9 100644
--- a/engines/wintermute/ad/ad_rot_level.cpp
+++ b/engines/wintermute/ad/ad_rot_level.cpp
@@ -27,11 +27,11 @@
*/
#include "engines/wintermute/ad/ad_rot_level.h"
-#include "engines/wintermute/base/base_parser.h"
#include "engines/wintermute/base/base_dynamic_buffer.h"
+#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/base_game.h"
+#include "engines/wintermute/base/base_parser.h"
#include "engines/wintermute/base/base_sprite.h"
-#include "engines/wintermute/base/base_file_manager.h"
namespace Wintermute {
diff --git a/engines/wintermute/ad/ad_scale_level.cpp b/engines/wintermute/ad/ad_scale_level.cpp
index 8b68cc5d32..4e9293d875 100644
--- a/engines/wintermute/ad/ad_scale_level.cpp
+++ b/engines/wintermute/ad/ad_scale_level.cpp
@@ -28,9 +28,9 @@
#include "engines/wintermute/ad/ad_scale_level.h"
#include "engines/wintermute/base/base_parser.h"
-#include "engines/wintermute/base/base_dynamic_buffer.h"
-#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_file_manager.h"
+#include "engines/wintermute/base/base_game.h"
+#include "engines/wintermute/base/base_dynamic_buffer.h"
namespace Wintermute {
diff --git a/engines/wintermute/ad/ad_scene.cpp b/engines/wintermute/ad/ad_scene.cpp
index e47acc63c9..8e9beca0c0 100644
--- a/engines/wintermute/ad/ad_scene.cpp
+++ b/engines/wintermute/ad/ad_scene.cpp
@@ -52,6 +52,7 @@
#include "engines/wintermute/base/base_scriptable.h"
#include "engines/wintermute/base/base_sprite.h"
#include "engines/wintermute/base/base_viewport.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script.h"
@@ -1808,13 +1809,13 @@ bool AdScene::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack,
//////////////////////////////////////////////////////////////////////////
-ScValue *AdScene::scGetProperty(const char *name) {
+ScValue *AdScene::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("scene");
return _scValue;
}
@@ -1822,7 +1823,7 @@ ScValue *AdScene::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// NumLayers (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "NumLayers") == 0) {
+ else if (name == "NumLayers") {
_scValue->setInt(_layers.size());
return _scValue;
}
@@ -1830,7 +1831,7 @@ ScValue *AdScene::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// NumWaypointGroups (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "NumWaypointGroups") == 0) {
+ else if (name == "NumWaypointGroups") {
_scValue->setInt(_waypointGroups.size());
return _scValue;
}
@@ -1838,7 +1839,7 @@ ScValue *AdScene::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// MainLayer (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "MainLayer") == 0) {
+ else if (name == "MainLayer") {
if (_mainLayer) {
_scValue->setNative(_mainLayer, true);
} else {
@@ -1851,7 +1852,7 @@ ScValue *AdScene::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// NumFreeNodes (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "NumFreeNodes") == 0) {
+ else if (name == "NumFreeNodes") {
_scValue->setInt(_objects.size());
return _scValue;
}
@@ -1859,7 +1860,7 @@ ScValue *AdScene::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// MouseX (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "MouseX") == 0) {
+ else if (name == "MouseX") {
int viewportX;
getViewportOffset(&viewportX);
@@ -1870,7 +1871,7 @@ ScValue *AdScene::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// MouseY (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "MouseY") == 0) {
+ else if (name == "MouseY") {
int viewportY;
getViewportOffset(NULL, &viewportY);
@@ -1881,7 +1882,7 @@ ScValue *AdScene::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// AutoScroll
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "AutoScroll") == 0) {
+ else if (name == "AutoScroll") {
_scValue->setBool(_autoScroll);
return _scValue;
}
@@ -1889,7 +1890,7 @@ ScValue *AdScene::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// PersistentState
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "PersistentState") == 0) {
+ else if (name == "PersistentState") {
_scValue->setBool(_persistentState);
return _scValue;
}
@@ -1897,7 +1898,7 @@ ScValue *AdScene::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// PersistentStateSprites
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "PersistentStateSprites") == 0) {
+ else if (name == "PersistentStateSprites") {
_scValue->setBool(_persistentStateSprites);
return _scValue;
}
@@ -1905,7 +1906,7 @@ ScValue *AdScene::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// ScrollPixelsX
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "ScrollPixelsX") == 0) {
+ else if (name == "ScrollPixelsX") {
_scValue->setInt(_scrollPixelsH);
return _scValue;
}
@@ -1913,7 +1914,7 @@ ScValue *AdScene::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// ScrollPixelsY
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "ScrollPixelsY") == 0) {
+ else if (name == "ScrollPixelsY") {
_scValue->setInt(_scrollPixelsV);
return _scValue;
}
@@ -1922,7 +1923,7 @@ ScValue *AdScene::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// ScrollSpeedX
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "ScrollSpeedX") == 0) {
+ else if (name == "ScrollSpeedX") {
_scValue->setInt(_scrollTimeH);
return _scValue;
}
@@ -1930,7 +1931,7 @@ ScValue *AdScene::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// ScrollSpeedY
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "ScrollSpeedY") == 0) {
+ else if (name == "ScrollSpeedY") {
_scValue->setInt(_scrollTimeV);
return _scValue;
}
@@ -1938,7 +1939,7 @@ ScValue *AdScene::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// OffsetX
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "OffsetX") == 0) {
+ else if (name == "OffsetX") {
_scValue->setInt(_offsetLeft);
return _scValue;
}
@@ -1946,7 +1947,7 @@ ScValue *AdScene::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// OffsetY
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "OffsetY") == 0) {
+ else if (name == "OffsetY") {
_scValue->setInt(_offsetTop);
return _scValue;
}
@@ -1954,7 +1955,7 @@ ScValue *AdScene::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Width (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Width") == 0) {
+ else if (name == "Width") {
if (_mainLayer) {
_scValue->setInt(_mainLayer->_width);
} else {
@@ -1966,7 +1967,7 @@ ScValue *AdScene::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Height (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Height") == 0) {
+ else if (name == "Height") {
if (_mainLayer) {
_scValue->setInt(_mainLayer->_height);
} else {
diff --git a/engines/wintermute/ad/ad_scene.h b/engines/wintermute/ad/ad_scene.h
index c9c0e413bf..3b482403b5 100644
--- a/engines/wintermute/ad/ad_scene.h
+++ b/engines/wintermute/ad/ad_scene.h
@@ -156,7 +156,7 @@ public:
int getPointsDist(BasePoint p1, BasePoint p2, BaseObject *requester = NULL);
// scripting interface
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scSetProperty(const char *name, ScValue *value);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
diff --git a/engines/wintermute/ad/ad_scene_state.cpp b/engines/wintermute/ad/ad_scene_state.cpp
index c09e6a259c..6b34f1af53 100644
--- a/engines/wintermute/ad/ad_scene_state.cpp
+++ b/engines/wintermute/ad/ad_scene_state.cpp
@@ -26,9 +26,9 @@
* Copyright (c) 2011 Jan Nedoma
*/
-#include "engines/wintermute/persistent.h"
#include "engines/wintermute/ad/ad_scene_state.h"
#include "engines/wintermute/ad/ad_node_state.h"
+#include "engines/wintermute/persistent.h"
#include "engines/wintermute/platform_osystem.h"
#include "common/str.h"
diff --git a/engines/wintermute/ad/ad_sentence.cpp b/engines/wintermute/ad/ad_sentence.cpp
index 1f09d3ae0f..cfe4191b07 100644
--- a/engines/wintermute/ad/ad_sentence.cpp
+++ b/engines/wintermute/ad/ad_sentence.cpp
@@ -26,17 +26,18 @@
* Copyright (c) 2011 Jan Nedoma
*/
+#include "engines/wintermute/ad/ad_game.h"
+#include "engines/wintermute/ad/ad_scene.h"
#include "engines/wintermute/ad/ad_sentence.h"
#include "engines/wintermute/ad/ad_talk_def.h"
#include "engines/wintermute/ad/ad_talk_node.h"
-#include "engines/wintermute/ad/ad_game.h"
#include "engines/wintermute/utils/path_util.h"
#include "engines/wintermute/base/base_game.h"
-#include "engines/wintermute/base/sound/base_sound.h"
-#include "engines/wintermute/ad/ad_scene.h"
-#include "engines/wintermute/base/font/base_font.h"
#include "engines/wintermute/base/base_sprite.h"
#include "engines/wintermute/base/base_file_manager.h"
+#include "engines/wintermute/base/font/base_font.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
+#include "engines/wintermute/base/sound/base_sound.h"
namespace Wintermute {
diff --git a/engines/wintermute/ad/ad_sprite_set.cpp b/engines/wintermute/ad/ad_sprite_set.cpp
index c8cdec03c3..345b483a8f 100644
--- a/engines/wintermute/ad/ad_sprite_set.cpp
+++ b/engines/wintermute/ad/ad_sprite_set.cpp
@@ -27,10 +27,10 @@
*/
#include "engines/wintermute/ad/ad_sprite_set.h"
-#include "engines/wintermute/base/base_parser.h"
#include "engines/wintermute/base/base_dynamic_buffer.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_file_manager.h"
+#include "engines/wintermute/base/base_parser.h"
#include "engines/wintermute/base/base_sprite.h"
namespace Wintermute {
diff --git a/engines/wintermute/ad/ad_talk_def.cpp b/engines/wintermute/ad/ad_talk_def.cpp
index 8cb489509b..a85cd7f986 100644
--- a/engines/wintermute/ad/ad_talk_def.cpp
+++ b/engines/wintermute/ad/ad_talk_def.cpp
@@ -26,13 +26,13 @@
* Copyright (c) 2011 Jan Nedoma
*/
+#include "engines/wintermute/ad/ad_sprite_set.h"
#include "engines/wintermute/ad/ad_talk_def.h"
#include "engines/wintermute/ad/ad_talk_node.h"
#include "engines/wintermute/base/base_parser.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_dynamic_buffer.h"
#include "engines/wintermute/base/base_sprite.h"
-#include "engines/wintermute/ad/ad_sprite_set.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/utils/utils.h"
diff --git a/engines/wintermute/ad/ad_talk_holder.cpp b/engines/wintermute/ad/ad_talk_holder.cpp
index 1e4ec26459..cca4fdc2cb 100644
--- a/engines/wintermute/ad/ad_talk_holder.cpp
+++ b/engines/wintermute/ad/ad_talk_holder.cpp
@@ -28,13 +28,13 @@
#include "engines/wintermute/ad/ad_talk_holder.h"
#include "engines/wintermute/base/base_dynamic_buffer.h"
+#include "engines/wintermute/base/base_engine.h"
+#include "engines/wintermute/base/base_game.h"
+#include "engines/wintermute/base/base_sprite.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
-#include "engines/wintermute/base/base_game.h"
-#include "engines/wintermute/base/base_sprite.h"
#include "engines/wintermute/platform_osystem.h"
-#include "engines/wintermute/base/base_engine.h"
#include "common/str.h"
namespace Wintermute {
@@ -334,13 +334,13 @@ bool AdTalkHolder::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisS
//////////////////////////////////////////////////////////////////////////
-ScValue *AdTalkHolder::scGetProperty(const char *name) {
+ScValue *AdTalkHolder::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type (RO)
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("talk-holder");
return _scValue;
} else {
diff --git a/engines/wintermute/ad/ad_talk_holder.h b/engines/wintermute/ad/ad_talk_holder.h
index ce10364b3d..d52ebf63c0 100644
--- a/engines/wintermute/ad/ad_talk_holder.h
+++ b/engines/wintermute/ad/ad_talk_holder.h
@@ -45,7 +45,7 @@ public:
virtual ~AdTalkHolder();
// scripting interface
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scSetProperty(const char *name, ScValue *value);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
diff --git a/engines/wintermute/ad/ad_talk_node.cpp b/engines/wintermute/ad/ad_talk_node.cpp
index b43a2b288e..c909ee27ff 100644
--- a/engines/wintermute/ad/ad_talk_node.cpp
+++ b/engines/wintermute/ad/ad_talk_node.cpp
@@ -26,12 +26,12 @@
* Copyright (c) 2011 Jan Nedoma
*/
+#include "engines/wintermute/ad/ad_sprite_set.h"
#include "engines/wintermute/ad/ad_talk_node.h"
#include "engines/wintermute/base/base_parser.h"
#include "engines/wintermute/base/base_dynamic_buffer.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_sprite.h"
-#include "engines/wintermute/ad/ad_sprite_set.h"
#include "engines/wintermute/utils/utils.h"
namespace Wintermute {
@@ -264,9 +264,9 @@ bool AdTalkNode::loadSprite() {
bool AdTalkNode::isInTimeInterval(uint32 time, TDirection dir) {
if (time >= _startTime) {
if (_playToEnd) {
- if ((_spriteFilename && _sprite == NULL) || (_sprite && _sprite->_finished == false)) {
+ if ((_spriteFilename && _sprite == NULL) || (_sprite && _sprite->isFinished() == false)) {
return true;
- } else if ((_spriteSetFilename && _spriteSet == NULL) || (_spriteSet && _spriteSet->getSprite(dir) && _spriteSet->getSprite(dir)->_finished == false)) {
+ } else if ((_spriteSetFilename && _spriteSet == NULL) || (_spriteSet && _spriteSet->getSprite(dir) && _spriteSet->getSprite(dir)->isFinished() == false)) {
return true;
} else {
return false;
diff --git a/engines/wintermute/ad/ad_waypoint_group.cpp b/engines/wintermute/ad/ad_waypoint_group.cpp
index 984ed75aeb..81493ce769 100644
--- a/engines/wintermute/ad/ad_waypoint_group.cpp
+++ b/engines/wintermute/ad/ad_waypoint_group.cpp
@@ -27,12 +27,12 @@
*/
#include "engines/wintermute/ad/ad_waypoint_group.h"
-#include "engines/wintermute/base/base_parser.h"
#include "engines/wintermute/base/base_dynamic_buffer.h"
-#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/base_game.h"
-#include "engines/wintermute/base/base_region.h"
#include "engines/wintermute/base/base_file_manager.h"
+#include "engines/wintermute/base/base_parser.h"
+#include "engines/wintermute/base/base_region.h"
+#include "engines/wintermute/base/scriptables/script_value.h"
#include <limits.h>
namespace Wintermute {
@@ -206,13 +206,13 @@ bool AdWaypointGroup::persist(BasePersistenceManager *persistMgr) {
//////////////////////////////////////////////////////////////////////////
-ScValue *AdWaypointGroup::scGetProperty(const char *name) {
+ScValue *AdWaypointGroup::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("waypoint-group");
return _scValue;
}
@@ -220,7 +220,7 @@ ScValue *AdWaypointGroup::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Active
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Active") == 0) {
+ else if (name == "Active") {
_scValue->setBool(_active);
return _scValue;
} else {
diff --git a/engines/wintermute/ad/ad_waypoint_group.h b/engines/wintermute/ad/ad_waypoint_group.h
index 5cf6da1d1a..13d6bbadd7 100644
--- a/engines/wintermute/ad/ad_waypoint_group.h
+++ b/engines/wintermute/ad/ad_waypoint_group.h
@@ -49,7 +49,7 @@ public:
virtual ~AdWaypointGroup();
BaseArray<BasePoint *> _points;
int _editorSelectedPoint;
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scSetProperty(const char *name, ScValue *value);
};
diff --git a/engines/wintermute/base/base_active_rect.cpp b/engines/wintermute/base/base_active_rect.cpp
index d754cf0114..4addf15be8 100644
--- a/engines/wintermute/base/base_active_rect.cpp
+++ b/engines/wintermute/base/base_active_rect.cpp
@@ -29,6 +29,7 @@
#include "engines/wintermute/base/base_active_rect.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_region.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/platform_osystem.h"
namespace Wintermute {
diff --git a/engines/wintermute/base/base_dynamic_buffer.h b/engines/wintermute/base/base_dynamic_buffer.h
index b6f3e12b9c..2d1a7fbe48 100644
--- a/engines/wintermute/base/base_dynamic_buffer.h
+++ b/engines/wintermute/base/base_dynamic_buffer.h
@@ -29,14 +29,12 @@
#ifndef WINTERMUTE_BASE_DYNAMIC_BUFFER_H
#define WINTERMUTE_BASE_DYNAMIC_BUFFER_H
-
#include "engines/wintermute/base/base.h"
namespace Wintermute {
class BaseDynamicBuffer {
public:
- bool _initialized;
void putText(const char *fmt, ...);
void putTextIndent(int indent, const char *fmt, ...);
uint32 getDWORD();
@@ -48,12 +46,13 @@ public:
uint32 getSize();
bool init(uint32 initSize = 0);
void cleanup();
- uint32 _size;
- byte *_buffer;
BaseDynamicBuffer(BaseGame *inGame, uint32 initSize = 1000, uint32 growBy = 1000);
virtual ~BaseDynamicBuffer();
private:
+ uint32 _size;
+ byte *_buffer;
+ bool _initialized;
uint32 _realSize;
uint32 _growBy;
uint32 _initSize;
diff --git a/engines/wintermute/base/base_engine.cpp b/engines/wintermute/base/base_engine.cpp
index 2368f8b106..8146d14beb 100644
--- a/engines/wintermute/base/base_engine.cpp
+++ b/engines/wintermute/base/base_engine.cpp
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -25,7 +25,7 @@
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
-
+
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_engine.h"
@@ -71,10 +71,10 @@ void BaseEngine::LOG(bool res, const char *fmt, ...) {
secs = secs % 3600;
uint32 mins = secs / 60;
secs = secs % 60;
-
+
char buff[512];
va_list va;
-
+
va_start(va, fmt);
vsprintf(buff, fmt, va);
va_end(va);
@@ -82,7 +82,7 @@ void BaseEngine::LOG(bool res, const char *fmt, ...) {
if (instance()._gameRef) {
instance()._gameRef->LOG("%s", buff);
} else {
- debugCN(kWintermuteDebugLog, "%02d:%02d:%02d: %s\n", hours, mins, secs, buff);
+ debugCN(kWintermuteDebugLog, "%02d:%02d:%02d: %s\n", hours, mins, secs, buff);
}
}
diff --git a/engines/wintermute/base/base_engine.h b/engines/wintermute/base/base_engine.h
index 1cef7b33ba..1ed0e3ab01 100644
--- a/engines/wintermute/base/base_engine.h
+++ b/engines/wintermute/base/base_engine.h
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -25,7 +25,7 @@
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
-
+
#ifndef WINTERMUTE_BASE_ENGINE_H
#define WINTERMUTE_BASE_ENGINE_H
diff --git a/engines/wintermute/base/base_fader.cpp b/engines/wintermute/base/base_fader.cpp
index 08e6f689ba..985718fcab 100644
--- a/engines/wintermute/base/base_fader.cpp
+++ b/engines/wintermute/base/base_fader.cpp
@@ -28,6 +28,7 @@
#include "engines/wintermute/base/base_fader.h"
#include "engines/wintermute/base/base_game.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
#include "common/util.h"
namespace Wintermute {
diff --git a/engines/wintermute/base/base_fader.h b/engines/wintermute/base/base_fader.h
index d3ced4aacc..116c8c963d 100644
--- a/engines/wintermute/base/base_fader.h
+++ b/engines/wintermute/base/base_fader.h
@@ -36,7 +36,6 @@ namespace Wintermute {
class BaseFader : public BaseObject {
public:
- bool _system;
uint32 getCurrentColor();
bool fadeOut(uint32 targetColor, uint32 duration, bool system = false);
bool fadeIn(uint32 sourceColor, uint32 duration, bool system = false);
@@ -47,6 +46,7 @@ public:
BaseFader(BaseGame *inGame);
virtual ~BaseFader();
private:
+ bool _system;
bool _active;
byte _red;
byte _green;
diff --git a/engines/wintermute/base/base_frame.cpp b/engines/wintermute/base/base_frame.cpp
index e1b29a3a5c..7c64144480 100644
--- a/engines/wintermute/base/base_frame.cpp
+++ b/engines/wintermute/base/base_frame.cpp
@@ -87,6 +87,12 @@ bool BaseFrame::draw(int x, int y, BaseObject *registerOwner, float zoomX, float
return STATUS_OK;
}
+void BaseFrame::stopSound() {
+ if (_sound) {
+ _sound->stop();
+ }
+}
+
//////////////////////////////////////////////////////////////////////////
bool BaseFrame::oneTimeDisplay(BaseObject *owner, bool muted) {
@@ -618,7 +624,7 @@ bool BaseFrame::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStac
//////////////////////////////////////////////////////////////////////////
-ScValue *BaseFrame::scGetProperty(const char *name) {
+ScValue *BaseFrame::scGetProperty(const Common::String &name) {
if (!_scValue) {
_scValue = new ScValue(_gameRef);
}
@@ -627,7 +633,7 @@ ScValue *BaseFrame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Type (RO)
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("frame");
return _scValue;
}
@@ -635,7 +641,7 @@ ScValue *BaseFrame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Delay
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Delay") == 0) {
+ else if (name == "Delay") {
_scValue->setInt(_delay);
return _scValue;
}
@@ -643,7 +649,7 @@ ScValue *BaseFrame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Keyframe
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Keyframe") == 0) {
+ else if (name == "Keyframe") {
_scValue->setBool(_keyframe);
return _scValue;
}
@@ -651,7 +657,7 @@ ScValue *BaseFrame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// KillSounds
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "KillSounds") == 0) {
+ else if (name == "KillSounds") {
_scValue->setBool(_killSound);
return _scValue;
}
@@ -659,7 +665,7 @@ ScValue *BaseFrame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// MoveX
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "MoveX") == 0) {
+ else if (name == "MoveX") {
_scValue->setInt(_moveX);
return _scValue;
}
@@ -667,7 +673,7 @@ ScValue *BaseFrame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// MoveY
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "MoveY") == 0) {
+ else if (name == "MoveY") {
_scValue->setInt(_moveY);
return _scValue;
}
@@ -675,7 +681,7 @@ ScValue *BaseFrame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// NumSubframes (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "NumSubframes") == 0) {
+ else if (name == "NumSubframes") {
_scValue->setInt(_subframes.size());
return _scValue;
}
@@ -683,7 +689,7 @@ ScValue *BaseFrame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// NumEvents (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "NumEvents") == 0) {
+ else if (name == "NumEvents") {
_scValue->setInt(_applyEvent.size());
return _scValue;
}
diff --git a/engines/wintermute/base/base_frame.h b/engines/wintermute/base/base_frame.h
index ea5467b6fe..7c5d893e70 100644
--- a/engines/wintermute/base/base_frame.h
+++ b/engines/wintermute/base/base_frame.h
@@ -41,11 +41,10 @@ class ScStack;
class BaseFrame: public BaseScriptable {
public:
bool _killSound;
- bool _keyframe;
+ void stopSound();
bool oneTimeDisplay(BaseObject *owner, bool muted = false);
DECLARE_PERSISTENT(BaseFrame, BaseScriptable)
- BaseSound *_sound;
- bool _editorExpanded;
+
bool getBoundingRect(Rect32 *rect, int x, int y, float scaleX = 100, float scaleY = 100);
bool saveAsText(BaseDynamicBuffer *buffer, int indent);
int _moveY;
@@ -61,11 +60,14 @@ public:
BaseArray<const char *> _applyEvent;
// scripting interface
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scSetProperty(const char *name, ScValue *value);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
-
+private:
+ bool _keyframe;
+ bool _editorExpanded;
+ BaseSound *_sound;
};
} // end of namespace Wintermute
diff --git a/engines/wintermute/base/base_game.cpp b/engines/wintermute/base/base_game.cpp
index 622e85cc11..b6886b7a33 100644
--- a/engines/wintermute/base/base_game.cpp
+++ b/engines/wintermute/base/base_game.cpp
@@ -64,6 +64,7 @@
#include "engines/wintermute/ui/ui_window.h"
#include "engines/wintermute/wintermute.h"
#include "engines/wintermute/platform_osystem.h"
+#include "base/version.h"
#include "common/config-manager.h"
#include "common/savefile.h"
#include "common/textconsole.h"
@@ -489,7 +490,7 @@ void BaseGame::DEBUG_DebugEnable(const char *filename) {
LOG(0, "********** DEBUG LOG OPENED %02d-%02d-%02d (Release Build) *****************", hours, mins, secs);
#endif
- LOG(0, "%s ver %d.%d.%d%s, Compiled on " __DATE__ ", " __TIME__, DCGF_NAME, DCGF_VER_MAJOR, DCGF_VER_MINOR, DCGF_VER_BUILD, DCGF_VER_SUFFIX);
+ LOG(0, "%s - %s ver %d.%d.%d%s ", gScummVMFullVersion, DCGF_NAME, DCGF_VER_MAJOR, DCGF_VER_MINOR, DCGF_VER_BUILD, DCGF_VER_SUFFIX);
AnsiString platform = BasePlatform::getPlatformName();
LOG(0, "Platform: %s", platform.c_str());
@@ -740,7 +741,7 @@ bool BaseGame::loadBuffer(byte *buffer, bool complete) {
TOKEN_TABLE(LOCAL_SAVE_DIR)
TOKEN_TABLE(COMPAT_KILL_METHOD_THREADS)
TOKEN_TABLE_END
-
+
// Declare a few variables necessary for moving data from these settings over to the renderer:
// The values are the same as the defaults set in BaseRenderer.
int loadImageX = 0;
@@ -2241,27 +2242,27 @@ bool BaseGame::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack
//////////////////////////////////////////////////////////////////////////
-ScValue *BaseGame::scGetProperty(const char *name) {
+ScValue *BaseGame::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("game");
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Name
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Name") == 0) {
+ else if (name == "Name") {
_scValue->setString(getName());
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Hwnd (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Hwnd") == 0) {
+ else if (name == "Hwnd") {
_scValue->setInt((int)_renderer->_window);
return _scValue;
}
@@ -2269,7 +2270,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// CurrentTime (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "CurrentTime") == 0) {
+ else if (name == "CurrentTime") {
_scValue->setInt((int)_timer);
return _scValue;
}
@@ -2277,7 +2278,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// WindowsTime (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "WindowsTime") == 0) {
+ else if (name == "WindowsTime") {
_scValue->setInt((int)g_system->getMillis());
return _scValue;
}
@@ -2285,7 +2286,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// WindowedMode (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "WindowedMode") == 0) {
+ else if (name == "WindowedMode") {
_scValue->setBool(_renderer->_windowed);
return _scValue;
}
@@ -2293,7 +2294,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// MouseX
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "MouseX") == 0) {
+ else if (name == "MouseX") {
_scValue->setInt(_mousePos.x);
return _scValue;
}
@@ -2301,7 +2302,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// MouseY
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "MouseY") == 0) {
+ else if (name == "MouseY") {
_scValue->setInt(_mousePos.y);
return _scValue;
}
@@ -2309,7 +2310,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// MainObject
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "MainObject") == 0) {
+ else if (name == "MainObject") {
_scValue->setNative(_mainObject, true);
return _scValue;
}
@@ -2317,7 +2318,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// ActiveObject (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "ActiveObject") == 0) {
+ else if (name == "ActiveObject") {
_scValue->setNative(_activeObject, true);
return _scValue;
}
@@ -2325,7 +2326,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// ScreenWidth (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "ScreenWidth") == 0) {
+ else if (name == "ScreenWidth") {
_scValue->setInt(_renderer->_width);
return _scValue;
}
@@ -2333,7 +2334,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// ScreenHeight (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "ScreenHeight") == 0) {
+ else if (name == "ScreenHeight") {
_scValue->setInt(_renderer->_height);
return _scValue;
}
@@ -2341,7 +2342,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Interactive
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Interactive") == 0) {
+ else if (name == "Interactive") {
_scValue->setBool(_interactive);
return _scValue;
}
@@ -2349,7 +2350,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// DebugMode (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "DebugMode") == 0) {
+ else if (name == "DebugMode") {
_scValue->setBool(_debugDebugMode);
return _scValue;
}
@@ -2357,7 +2358,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// SoundAvailable (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "SoundAvailable") == 0) {
+ else if (name == "SoundAvailable") {
_scValue->setBool(_soundMgr->_soundAvailable);
return _scValue;
}
@@ -2365,7 +2366,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// SFXVolume
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "SFXVolume") == 0) {
+ else if (name == "SFXVolume") {
_gameRef->LOG(0, "**Warning** The SFXVolume attribute is obsolete");
_scValue->setInt(_soundMgr->getVolumePercent(Audio::Mixer::kSFXSoundType));
return _scValue;
@@ -2374,7 +2375,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// SpeechVolume
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "SpeechVolume") == 0) {
+ else if (name == "SpeechVolume") {
_gameRef->LOG(0, "**Warning** The SpeechVolume attribute is obsolete");
_scValue->setInt(_soundMgr->getVolumePercent(Audio::Mixer::kSpeechSoundType));
return _scValue;
@@ -2383,7 +2384,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// MusicVolume
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "MusicVolume") == 0) {
+ else if (name == "MusicVolume") {
_gameRef->LOG(0, "**Warning** The MusicVolume attribute is obsolete");
_scValue->setInt(_soundMgr->getVolumePercent(Audio::Mixer::kMusicSoundType));
return _scValue;
@@ -2392,7 +2393,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// MasterVolume
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "MasterVolume") == 0) {
+ else if (name == "MasterVolume") {
_gameRef->LOG(0, "**Warning** The MasterVolume attribute is obsolete");
_scValue->setInt(_soundMgr->getMasterVolumePercent());
return _scValue;
@@ -2401,7 +2402,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Keyboard (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Keyboard") == 0) {
+ else if (name == "Keyboard") {
if (_keyboardState) {
_scValue->setNative(_keyboardState, true);
} else {
@@ -2414,7 +2415,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Subtitles
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Subtitles") == 0) {
+ else if (name == "Subtitles") {
_scValue->setBool(_subtitles);
return _scValue;
}
@@ -2422,14 +2423,14 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// SubtitlesSpeed
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "SubtitlesSpeed") == 0) {
+ else if (name == "SubtitlesSpeed") {
_scValue->setInt(_subtitlesSpeed);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// VideoSubtitles
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "VideoSubtitles") == 0) {
+ else if (name == "VideoSubtitles") {
_scValue->setBool(_videoSubtitles);
return _scValue;
}
@@ -2437,7 +2438,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// FPS (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "FPS") == 0) {
+ else if (name == "FPS") {
_scValue->setInt(_fps);
return _scValue;
}
@@ -2445,7 +2446,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// AcceleratedMode / Accelerated (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "AcceleratedMode") == 0 || strcmp(name, "Accelerated") == 0) {
+ else if (name == "AcceleratedMode" || name == "Accelerated") {
_scValue->setBool(_useD3D);
return _scValue;
}
@@ -2453,7 +2454,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// TextEncoding
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "TextEncoding") == 0) {
+ else if (name == "TextEncoding") {
_scValue->setInt(_textEncoding);
return _scValue;
}
@@ -2461,7 +2462,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// TextRTL
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "TextRTL") == 0) {
+ else if (name == "TextRTL") {
_scValue->setBool(_textRTL);
return _scValue;
}
@@ -2469,7 +2470,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// SoundBufferSize
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "SoundBufferSize") == 0) {
+ else if (name == "SoundBufferSize") {
_scValue->setInt(_soundBufferSizeSec);
return _scValue;
}
@@ -2477,7 +2478,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// SuspendedRendering
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "SuspendedRendering") == 0) {
+ else if (name == "SuspendedRendering") {
_scValue->setBool(_suspendedRendering);
return _scValue;
}
@@ -2485,7 +2486,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// SuppressScriptErrors
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "SuppressScriptErrors") == 0) {
+ else if (name == "SuppressScriptErrors") {
_scValue->setBool(_suppressScriptErrors);
return _scValue;
}
@@ -2494,7 +2495,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Frozen
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Frozen") == 0) {
+ else if (name == "Frozen") {
_scValue->setBool(_state == GAME_FROZEN);
return _scValue;
}
@@ -2502,7 +2503,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// AccTTSEnabled
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "AccTTSEnabled") == 0) {
+ else if (name == "AccTTSEnabled") {
_scValue->setBool(false);
return _scValue;
}
@@ -2510,7 +2511,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// AccTTSTalk
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "AccTTSTalk") == 0) {
+ else if (name == "AccTTSTalk") {
_scValue->setBool(false);
return _scValue;
}
@@ -2518,7 +2519,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// AccTTSCaptions
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "AccTTSCaptions") == 0) {
+ else if (name == "AccTTSCaptions") {
_scValue->setBool(false);
return _scValue;
}
@@ -2526,7 +2527,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// AccTTSKeypress
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "AccTTSKeypress") == 0) {
+ else if (name == "AccTTSKeypress") {
_scValue->setBool(false);
return _scValue;
}
@@ -2534,7 +2535,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// AccKeyboardEnabled
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "AccKeyboardEnabled") == 0) {
+ else if (name == "AccKeyboardEnabled") {
_scValue->setBool(false);
return _scValue;
}
@@ -2542,7 +2543,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// AccKeyboardCursorSkip
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "AccKeyboardCursorSkip") == 0) {
+ else if (name == "AccKeyboardCursorSkip") {
_scValue->setBool(false);
return _scValue;
}
@@ -2550,7 +2551,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// AccKeyboardPause
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "AccKeyboardPause") == 0) {
+ else if (name == "AccKeyboardPause") {
_scValue->setBool(false);
return _scValue;
}
@@ -2558,7 +2559,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// AutorunDisabled
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "AutorunDisabled") == 0) {
+ else if (name == "AutorunDisabled") {
_scValue->setBool(_autorunDisabled);
return _scValue;
}
@@ -2566,7 +2567,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// SaveDirectory (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "SaveDirectory") == 0) {
+ else if (name == "SaveDirectory") {
AnsiString dataDir = "saves/"; // TODO: This is just to avoid telling the engine actual paths.
_scValue->setString(dataDir.c_str());
return _scValue;
@@ -2575,7 +2576,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// AutoSaveOnExit
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "AutoSaveOnExit") == 0) {
+ else if (name == "AutoSaveOnExit") {
_scValue->setBool(_autoSaveOnExit);
return _scValue;
}
@@ -2583,7 +2584,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// AutoSaveSlot
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "AutoSaveSlot") == 0) {
+ else if (name == "AutoSaveSlot") {
_scValue->setInt(_autoSaveSlot);
return _scValue;
}
@@ -2591,7 +2592,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// CursorHidden
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "CursorHidden") == 0) {
+ else if (name == "CursorHidden") {
_scValue->setBool(_cursorHidden);
return _scValue;
}
@@ -2599,7 +2600,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Platform (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Platform") == 0) {
+ else if (name == "Platform") {
_scValue->setString(BasePlatform::getPlatformName().c_str());
return _scValue;
}
@@ -2607,7 +2608,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// DeviceType (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "DeviceType") == 0) {
+ else if (name == "DeviceType") {
_scValue->setString(getDeviceType().c_str());
return _scValue;
}
@@ -2615,7 +2616,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// MostRecentSaveSlot (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "MostRecentSaveSlot") == 0) {
+ else if (name == "MostRecentSaveSlot") {
if (!ConfMan.hasKey("most_recent_saveslot")) {
_scValue->setInt(-1);
} else {
@@ -2627,7 +2628,7 @@ ScValue *BaseGame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Store (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Store") == 0) {
+ else if (name == "Store") {
_scValue->setNULL();
error("Request for a SXStore-object, which is not supported by ScummVM");
@@ -3624,7 +3625,7 @@ bool BaseGame::persist(BasePersistenceManager *persistMgr) {
persistMgr->transfer(TMEMBER(_musicCrossfadeChannel1));
persistMgr->transfer(TMEMBER(_musicCrossfadeChannel2));
persistMgr->transfer(TMEMBER(_musicCrossfadeSwap));
-
+
_renderer->persistSaveLoadImages(persistMgr);
persistMgr->transfer(TMEMBER_INT(_textEncoding));
diff --git a/engines/wintermute/base/base_game.h b/engines/wintermute/base/base_game.h
index 93cbc4536b..0f764b3d03 100644
--- a/engines/wintermute/base/base_game.h
+++ b/engines/wintermute/base/base_game.h
@@ -29,7 +29,6 @@
#ifndef WINTERMUTE_BASE_GAME_H
#define WINTERMUTE_BASE_GAME_H
-#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/base_object.h"
#include "engines/wintermute/persistent.h"
#include "engines/wintermute/coll_templ.h"
@@ -165,7 +164,7 @@ public:
virtual bool externalCall(ScScript *script, ScStack *stack, ScStack *thisStack, char *name);
// scripting interface
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scSetProperty(const char *name, ScValue *value);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
diff --git a/engines/wintermute/base/base_keyboard_state.cpp b/engines/wintermute/base/base_keyboard_state.cpp
index fd5f2b0e1d..da7baafd2d 100644
--- a/engines/wintermute/base/base_keyboard_state.cpp
+++ b/engines/wintermute/base/base_keyboard_state.cpp
@@ -103,13 +103,13 @@ bool BaseKeyboardState::scCallMethod(ScScript *script, ScStack *stack, ScStack *
//////////////////////////////////////////////////////////////////////////
-ScValue *BaseKeyboardState::scGetProperty(const char *name) {
+ScValue *BaseKeyboardState::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("keyboard");
return _scValue;
}
@@ -117,7 +117,7 @@ ScValue *BaseKeyboardState::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Key
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Key") == 0) {
+ else if (name == "Key") {
if (_currentPrintable) {
char key[2];
key[0] = (char)_currentCharCode;
@@ -133,7 +133,7 @@ ScValue *BaseKeyboardState::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Printable
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Printable") == 0) {
+ else if (name == "Printable") {
_scValue->setBool(_currentPrintable);
return _scValue;
}
@@ -141,7 +141,7 @@ ScValue *BaseKeyboardState::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// KeyCode
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "KeyCode") == 0) {
+ else if (name == "KeyCode") {
_scValue->setInt(_currentCharCode);
return _scValue;
}
@@ -149,7 +149,7 @@ ScValue *BaseKeyboardState::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// IsShift
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "IsShift") == 0) {
+ else if (name == "IsShift") {
_scValue->setBool(_currentShift);
return _scValue;
}
@@ -157,7 +157,7 @@ ScValue *BaseKeyboardState::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// IsAlt
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "IsAlt") == 0) {
+ else if (name == "IsAlt") {
_scValue->setBool(_currentAlt);
return _scValue;
}
@@ -165,7 +165,7 @@ ScValue *BaseKeyboardState::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// IsControl
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "IsControl") == 0) {
+ else if (name == "IsControl") {
_scValue->setBool(_currentControl);
return _scValue;
} else {
diff --git a/engines/wintermute/base/base_keyboard_state.h b/engines/wintermute/base/base_keyboard_state.h
index ebc0c83ee1..dfd0efdec0 100644
--- a/engines/wintermute/base/base_keyboard_state.h
+++ b/engines/wintermute/base/base_keyboard_state.h
@@ -59,7 +59,7 @@ public:
static bool isAltDown();
// scripting interface
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scSetProperty(const char *name, ScValue *value);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
diff --git a/engines/wintermute/base/base_object.cpp b/engines/wintermute/base/base_object.cpp
index b6a6887624..eba8416485 100644
--- a/engines/wintermute/base/base_object.cpp
+++ b/engines/wintermute/base/base_object.cpp
@@ -531,13 +531,13 @@ bool BaseObject::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisSta
//////////////////////////////////////////////////////////////////////////
-ScValue *BaseObject::scGetProperty(const char *name) {
+ScValue *BaseObject::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("object");
return _scValue;
}
@@ -545,7 +545,7 @@ ScValue *BaseObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Caption
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Caption") == 0) {
+ else if (name == "Caption") {
_scValue->setString(getCaption(1));
return _scValue;
}
@@ -553,7 +553,7 @@ ScValue *BaseObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// X
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "X") == 0) {
+ else if (name == "X") {
_scValue->setInt(_posX);
return _scValue;
}
@@ -561,7 +561,7 @@ ScValue *BaseObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Y
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Y") == 0) {
+ else if (name == "Y") {
_scValue->setInt(_posY);
return _scValue;
}
@@ -569,7 +569,7 @@ ScValue *BaseObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Height (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Height") == 0) {
+ else if (name == "Height") {
_scValue->setInt(getHeight());
return _scValue;
}
@@ -577,7 +577,7 @@ ScValue *BaseObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Ready (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Ready") == 0) {
+ else if (name == "Ready") {
_scValue->setBool(_ready);
return _scValue;
}
@@ -585,7 +585,7 @@ ScValue *BaseObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Movable
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Movable") == 0) {
+ else if (name == "Movable") {
_scValue->setBool(_movable);
return _scValue;
}
@@ -593,7 +593,7 @@ ScValue *BaseObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Registrable/Interactive
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Registrable") == 0 || strcmp(name, "Interactive") == 0) {
+ else if (name == "Registrable" || name == "Interactive") {
_scValue->setBool(_registrable);
return _scValue;
}
@@ -601,21 +601,21 @@ ScValue *BaseObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Zoomable/Scalable
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Zoomable") == 0 || strcmp(name, "Scalable") == 0) {
+ else if (name == "Zoomable" || name == "Scalable") {
_scValue->setBool(_zoomable);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Rotatable
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Rotatable") == 0) {
+ else if (name == "Rotatable") {
_scValue->setBool(_rotatable);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// AlphaColor
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "AlphaColor") == 0) {
+ else if (name == "AlphaColor") {
_scValue->setInt((int)_alphaColor);
return _scValue;
}
@@ -623,7 +623,7 @@ ScValue *BaseObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// BlendMode
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "BlendMode") == 0) {
+ else if (name == "BlendMode") {
_scValue->setInt((int)_blendMode);
return _scValue;
}
@@ -631,7 +631,7 @@ ScValue *BaseObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Scale
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Scale") == 0) {
+ else if (name == "Scale") {
if (_scale < 0) {
_scValue->setNULL();
} else {
@@ -643,7 +643,7 @@ ScValue *BaseObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// ScaleX
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "ScaleX") == 0) {
+ else if (name == "ScaleX") {
if (_scaleX < 0) {
_scValue->setNULL();
} else {
@@ -655,7 +655,7 @@ ScValue *BaseObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// ScaleY
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "ScaleY") == 0) {
+ else if (name == "ScaleY") {
if (_scaleY < 0) {
_scValue->setNULL();
} else {
@@ -667,7 +667,7 @@ ScValue *BaseObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// RelativeScale
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "RelativeScale") == 0) {
+ else if (name == "RelativeScale") {
_scValue->setFloat((double)_relativeScale);
return _scValue;
}
@@ -675,7 +675,7 @@ ScValue *BaseObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Rotate
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Rotate") == 0) {
+ else if (name == "Rotate") {
if (!_rotateValid) {
_scValue->setNULL();
} else {
@@ -687,7 +687,7 @@ ScValue *BaseObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// RelativeRotate
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "RelativeRotate") == 0) {
+ else if (name == "RelativeRotate") {
_scValue->setFloat((double)_relativeRotate);
return _scValue;
}
@@ -695,14 +695,14 @@ ScValue *BaseObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Colorable
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Colorable") == 0) {
+ else if (name == "Colorable") {
_scValue->setBool(_shadowable);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// SoundPanning
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "SoundPanning") == 0) {
+ else if (name == "SoundPanning") {
_scValue->setBool(_autoSoundPanning);
return _scValue;
}
@@ -710,7 +710,7 @@ ScValue *BaseObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// SaveState
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "SaveState") == 0) {
+ else if (name == "SaveState") {
_scValue->setBool(_saveState);
return _scValue;
}
@@ -718,7 +718,7 @@ ScValue *BaseObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// NonIntMouseEvents
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "NonIntMouseEvents") == 0) {
+ else if (name == "NonIntMouseEvents") {
_scValue->setBool(_nonIntMouseEvents);
return _scValue;
}
@@ -726,7 +726,7 @@ ScValue *BaseObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// AccCaption
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "AccCaption") == 0) {
+ else if (name == "AccCaption") {
_scValue->setNULL();
return _scValue;
} else {
diff --git a/engines/wintermute/base/base_object.h b/engines/wintermute/base/base_object.h
index 34adbdb585..d7d91a25f6 100644
--- a/engines/wintermute/base/base_object.h
+++ b/engines/wintermute/base/base_object.h
@@ -136,7 +136,7 @@ public:
public:
// scripting interface
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scSetProperty(const char *name, ScValue *value);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
diff --git a/engines/wintermute/base/base_quick_msg.h b/engines/wintermute/base/base_quick_msg.h
index 4fed5ffc2e..67f9613461 100644
--- a/engines/wintermute/base/base_quick_msg.h
+++ b/engines/wintermute/base/base_quick_msg.h
@@ -37,10 +37,10 @@ class BaseQuickMsg : public BaseClass {
public:
char *getText();
uint32 _startTime;
- char *_text;
- BaseQuickMsg(BaseGame *inGame, const char *Text);
+ BaseQuickMsg(BaseGame *inGame, const char *text);
virtual ~BaseQuickMsg();
-
+private:
+ char *_text;
};
} // end of namespace Wintermute
diff --git a/engines/wintermute/base/base_region.cpp b/engines/wintermute/base/base_region.cpp
index e332ffe9ff..0bc5975e51 100644
--- a/engines/wintermute/base/base_region.cpp
+++ b/engines/wintermute/base/base_region.cpp
@@ -327,13 +327,13 @@ bool BaseRegion::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisSta
//////////////////////////////////////////////////////////////////////////
-ScValue *BaseRegion::scGetProperty(const char *name) {
+ScValue *BaseRegion::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("region");
return _scValue;
}
@@ -341,7 +341,7 @@ ScValue *BaseRegion::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Name
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Name") == 0) {
+ else if (name == "Name") {
_scValue->setString(getName());
return _scValue;
}
@@ -349,7 +349,7 @@ ScValue *BaseRegion::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Active
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Active") == 0) {
+ else if (name == "Active") {
_scValue->setBool(_active);
return _scValue;
}
@@ -357,7 +357,7 @@ ScValue *BaseRegion::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// NumPoints
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "NumPoints") == 0) {
+ else if (name == "NumPoints") {
_scValue->setInt(_points.size());
return _scValue;
} else {
diff --git a/engines/wintermute/base/base_region.h b/engines/wintermute/base/base_region.h
index 8dd02fe928..464f25be2f 100644
--- a/engines/wintermute/base/base_region.h
+++ b/engines/wintermute/base/base_region.h
@@ -36,9 +36,6 @@ namespace Wintermute {
class BaseRegion : public BaseObject {
public:
- float _lastMimicScale;
- int _lastMimicX;
- int _lastMimicY;
void cleanup();
bool mimic(BaseRegion *region, float scale = 100.0f, int x = 0, int y = 0);
bool getBoundingRect(Rect32 *rect);
@@ -58,10 +55,14 @@ public:
virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent, const char *nameOverride);
// scripting interface
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scSetProperty(const char *name, ScValue *value);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
+private:
+ float _lastMimicScale;
+ int _lastMimicX;
+ int _lastMimicY;
};
} // end of namespace Wintermute
diff --git a/engines/wintermute/base/base_save_thumb_helper.cpp b/engines/wintermute/base/base_save_thumb_helper.cpp
index 186e1234a8..b4205c21c4 100644
--- a/engines/wintermute/base/base_save_thumb_helper.cpp
+++ b/engines/wintermute/base/base_save_thumb_helper.cpp
@@ -28,6 +28,7 @@
#include "engines/wintermute/base/base_save_thumb_helper.h"
#include "engines/wintermute/base/gfx/base_image.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/base_game.h"
namespace Wintermute {
diff --git a/engines/wintermute/base/base_script_holder.cpp b/engines/wintermute/base/base_script_holder.cpp
index d3e6078d43..c5d5e82f76 100644
--- a/engines/wintermute/base/base_script_holder.cpp
+++ b/engines/wintermute/base/base_script_holder.cpp
@@ -219,13 +219,13 @@ bool BaseScriptHolder::scCallMethod(ScScript *script, ScStack *stack, ScStack *t
//////////////////////////////////////////////////////////////////////////
-ScValue *BaseScriptHolder::scGetProperty(const char *name) {
+ScValue *BaseScriptHolder::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("script_holder");
return _scValue;
}
@@ -233,7 +233,7 @@ ScValue *BaseScriptHolder::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Name
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Name") == 0) {
+ else if (name == "Name") {
_scValue->setString(getName());
return _scValue;
}
@@ -241,7 +241,7 @@ ScValue *BaseScriptHolder::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Filename (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Filename") == 0) {
+ else if (name == "Filename") {
_scValue->setString(_filename);
return _scValue;
} else {
diff --git a/engines/wintermute/base/base_script_holder.h b/engines/wintermute/base/base_script_holder.h
index 0c3d7a1a70..5fd0dbec9c 100644
--- a/engines/wintermute/base/base_script_holder.h
+++ b/engines/wintermute/base/base_script_holder.h
@@ -59,7 +59,7 @@ public:
BaseArray<ScScript *> _scripts;
// scripting interface
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scSetProperty(const char *name, ScValue *value);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
diff --git a/engines/wintermute/base/base_scriptable.cpp b/engines/wintermute/base/base_scriptable.cpp
index 143934402b..a2dd8b00e7 100644
--- a/engines/wintermute/base/base_scriptable.cpp
+++ b/engines/wintermute/base/base_scriptable.cpp
@@ -76,12 +76,12 @@ bool BaseScriptable::scCallMethod(ScScript *script, ScStack *stack, ScStack *thi
//////////////////////////////////////////////////////////////////////////
-ScValue *BaseScriptable::scGetProperty(const char *name) {
+ScValue *BaseScriptable::scGetProperty(const Common::String &name) {
if (!_scProp) {
_scProp = new ScValue(_gameRef);
}
if (_scProp) {
- return _scProp->getProp(name);
+ return _scProp->getProp(name.c_str()); // TODO: Change to Common::String
} else {
return NULL;
}
diff --git a/engines/wintermute/base/base_scriptable.h b/engines/wintermute/base/base_scriptable.h
index b006e6e07c..fbe14fc299 100644
--- a/engines/wintermute/base/base_scriptable.h
+++ b/engines/wintermute/base/base_scriptable.h
@@ -50,7 +50,7 @@ public:
// high level scripting interface
virtual bool canHandleMethod(const char *eventMethod);
virtual bool scSetProperty(const char *name, ScValue *value);
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
virtual void *scToMemBuffer();
diff --git a/engines/wintermute/base/base_sprite.cpp b/engines/wintermute/base/base_sprite.cpp
index e2dd8bbd39..468af1bd75 100644
--- a/engines/wintermute/base/base_sprite.cpp
+++ b/engines/wintermute/base/base_sprite.cpp
@@ -121,6 +121,13 @@ bool BaseSprite::draw(int x, int y, BaseObject *registerOwner, float zoomX, floa
return display(x, y, registerOwner, zoomX, zoomY, alpha);
}
+bool BaseSprite::isChanged() {
+ return _changed;
+}
+
+bool BaseSprite::isFinished() {
+ return _finished;
+}
//////////////////////////////////////////////////////////////////////
bool BaseSprite::loadFile(const Common::String &filename, int lifeTime, TSpriteCacheType cacheType) {
@@ -686,13 +693,13 @@ bool BaseSprite::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisSta
//////////////////////////////////////////////////////////////////////////
-ScValue *BaseSprite::scGetProperty(const char *name) {
+ScValue *BaseSprite::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("sprite");
return _scValue;
}
@@ -700,7 +707,7 @@ ScValue *BaseSprite::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// NumFrames (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "NumFrames") == 0) {
+ else if (name == "NumFrames") {
_scValue->setInt(_frames.size());
return _scValue;
}
@@ -708,7 +715,7 @@ ScValue *BaseSprite::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// CurrentFrame
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "CurrentFrame") == 0) {
+ else if (name == "CurrentFrame") {
_scValue->setInt(_currentFrame);
return _scValue;
}
@@ -716,7 +723,7 @@ ScValue *BaseSprite::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// PixelPerfect
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "PixelPerfect") == 0) {
+ else if (name == "PixelPerfect") {
_scValue->setBool(_precise);
return _scValue;
}
@@ -724,7 +731,7 @@ ScValue *BaseSprite::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Looping
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Looping") == 0) {
+ else if (name == "Looping") {
_scValue->setBool(_looping);
return _scValue;
}
@@ -732,7 +739,7 @@ ScValue *BaseSprite::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Owner (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Owner") == 0) {
+ else if (name == "Owner") {
if (_owner == NULL) {
_scValue->setNULL();
} else {
@@ -744,7 +751,7 @@ ScValue *BaseSprite::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Finished (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Finished") == 0) {
+ else if (name == "Finished") {
_scValue->setBool(_finished);
return _scValue;
}
@@ -752,7 +759,7 @@ ScValue *BaseSprite::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Paused (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Paused") == 0) {
+ else if (name == "Paused") {
_scValue->setBool(_paused);
return _scValue;
} else {
@@ -804,9 +811,7 @@ const char *BaseSprite::scToString() {
//////////////////////////////////////////////////////////////////////////
bool BaseSprite::killAllSounds() {
for (uint32 i = 0; i < _frames.size(); i++) {
- if (_frames[i]->_sound) {
- _frames[i]->_sound->stop();
- }
+ _frames[i]->stopSound();
}
return STATUS_OK;
}
diff --git a/engines/wintermute/base/base_sprite.h b/engines/wintermute/base/base_sprite.h
index c861ca9930..1d244c3a52 100644
--- a/engines/wintermute/base/base_sprite.h
+++ b/engines/wintermute/base/base_sprite.h
@@ -39,36 +39,21 @@ class BaseSurface;
class BaseObject;
class BaseSprite: public BaseScriptHolder {
public:
- bool killAllSounds();
BaseSurface *getSurface();
- char *_editorBgFile;
- int _editorBgOffsetX;
- int _editorBgOffsetY;
- int _editorBgAlpha;
- bool _streamed;
- bool _streamedKeepLoaded;
void cleanup();
void setDefaults();
- bool _precise;
DECLARE_PERSISTENT(BaseSprite, BaseScriptHolder)
- bool _editorAllFrames;
bool getBoundingRect(Rect32 *rect, int x, int y, float scaleX = 100, float scaleY = 100);
int _moveY;
int _moveX;
bool display(int x, int y, BaseObject *registerOwner = NULL, float zoomX = 100, float zoomY = 100, uint32 alpha = 0xFFFFFFFF, float rotate = 0.0f, TSpriteBlendMode blendMode = BLEND_NORMAL);
bool getCurrentFrame(float zoomX = 100, float zoomY = 100);
- bool _canBreak;
- bool _editorMuted;
- bool _continuous;
void reset();
- BaseObject *_owner;
- bool _changed;
- bool _paused;
- bool _finished;
+ bool isChanged();
+ bool isFinished();
bool loadBuffer(byte *buffer, bool compete = true, int lifeTime = -1, TSpriteCacheType cacheType = CACHE_ALL);
bool loadFile(const Common::String &filename, int lifeTime = -1, TSpriteCacheType cacheType = CACHE_ALL);
- uint32 _lastFrameTime;
bool draw(int x, int y, BaseObject *Register = NULL, float zoomX = 100, float zoomY = 100, uint32 alpha = 0xFFFFFFFF);
bool _looping;
int _currentFrame;
@@ -79,10 +64,28 @@ public:
bool saveAsText(BaseDynamicBuffer *buffer, int indent);
// scripting interface
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scSetProperty(const char *name, ScValue *value);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
+private:
+ BaseObject *_owner;
+ bool _canBreak;
+ bool _changed;
+ bool _editorAllFrames;
+ char *_editorBgFile;
+ int _editorBgOffsetX;
+ int _editorBgOffsetY;
+ int _editorBgAlpha;
+ bool _editorMuted;
+ bool _finished;
+ bool _continuous;
+ uint32 _lastFrameTime;
+ bool _precise;
+ bool _paused;
+ bool _streamed;
+ bool _streamedKeepLoaded;
+ bool killAllSounds();
};
} // end of namespace Wintermute
diff --git a/engines/wintermute/base/base_sub_frame.cpp b/engines/wintermute/base/base_sub_frame.cpp
index 6a9246efd4..77cc522ae7 100644
--- a/engines/wintermute/base/base_sub_frame.cpp
+++ b/engines/wintermute/base/base_sub_frame.cpp
@@ -34,6 +34,7 @@
#include "engines/wintermute/base/base_surface_storage.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/platform_osystem.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
@@ -225,6 +226,9 @@ void BaseSubFrame::setRect(Rect32 rect) {
_rect = rect;
}
+const char* BaseSubFrame::getSurfaceFilename() {
+ return _surfaceFilename;
+}
//////////////////////////////////////////////////////////////////////
bool BaseSubFrame::draw(int x, int y, BaseObject *registerOwner, float zoomX, float zoomY, bool precise, uint32 alpha, float rotate, TSpriteBlendMode blendMode) {
@@ -442,7 +446,7 @@ bool BaseSubFrame::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisS
//////////////////////////////////////////////////////////////////////////
-ScValue *BaseSubFrame::scGetProperty(const char *name) {
+ScValue *BaseSubFrame::scGetProperty(const Common::String &name) {
if (!_scValue) {
_scValue = new ScValue(_gameRef);
}
@@ -451,7 +455,7 @@ ScValue *BaseSubFrame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Type (RO)
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("subframe");
return _scValue;
}
@@ -459,7 +463,7 @@ ScValue *BaseSubFrame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// AlphaColor
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "AlphaColor") == 0) {
+ else if (name == "AlphaColor") {
_scValue->setInt((int)_alpha);
return _scValue;
@@ -468,7 +472,7 @@ ScValue *BaseSubFrame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// TransparentColor (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "TransparentColor") == 0) {
+ else if (name == "TransparentColor") {
_scValue->setInt((int)_transparent);
return _scValue;
}
@@ -476,7 +480,7 @@ ScValue *BaseSubFrame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Is2DOnly
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Is2DOnly") == 0) {
+ else if (name == "Is2DOnly") {
_scValue->setBool(_2DOnly);
return _scValue;
}
@@ -484,7 +488,7 @@ ScValue *BaseSubFrame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Is3DOnly
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Is3DOnly") == 0) {
+ else if (name == "Is3DOnly") {
_scValue->setBool(_3DOnly);
return _scValue;
}
@@ -492,7 +496,7 @@ ScValue *BaseSubFrame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// MirrorX
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "MirrorX") == 0) {
+ else if (name == "MirrorX") {
_scValue->setBool(_mirrorX);
return _scValue;
}
@@ -500,7 +504,7 @@ ScValue *BaseSubFrame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// MirrorY
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "MirrorY") == 0) {
+ else if (name == "MirrorY") {
_scValue->setBool(_mirrorY);
return _scValue;
}
@@ -508,7 +512,7 @@ ScValue *BaseSubFrame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Decoration
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Decoration") == 0) {
+ else if (name == "Decoration") {
_scValue->setBool(_decoration);
return _scValue;
}
@@ -516,7 +520,7 @@ ScValue *BaseSubFrame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// HotspotX
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "HotspotX") == 0) {
+ else if (name == "HotspotX") {
_scValue->setInt(_hotspotX);
return _scValue;
}
@@ -524,7 +528,7 @@ ScValue *BaseSubFrame::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// HotspotY
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "HotspotY") == 0) {
+ else if (name == "HotspotY") {
_scValue->setInt(_hotspotY);
return _scValue;
} else {
diff --git a/engines/wintermute/base/base_sub_frame.h b/engines/wintermute/base/base_sub_frame.h
index b174c6e5f0..c173ae69d1 100644
--- a/engines/wintermute/base/base_sub_frame.h
+++ b/engines/wintermute/base/base_sub_frame.h
@@ -54,6 +54,7 @@ public:
bool loadBuffer(byte *buffer, int lifeTime, bool keepLoaded);
bool draw(int x, int y, BaseObject *registerOwner = NULL, float zoomX = 100, float zoomY = 100, bool precise = true, uint32 alpha = 0xFFFFFFFF, float rotate = 0.0f, TSpriteBlendMode blendMode = BLEND_NORMAL);
bool getBoundingRect(Rect32 *rect, int x, int y, float scaleX = 100, float scaleY = 100);
+ const char* getSurfaceFilename();
int _hotspotX;
int _hotspotY;
@@ -65,6 +66,7 @@ public:
private:
bool _wantsDefaultRect;
Rect32 _rect;
+ char *_surfaceFilename;
public:
bool _cKDefault;
byte _cKRed;
@@ -72,7 +74,6 @@ public:
byte _cKBlue;
int _lifeTime;
bool _keepLoaded;
- char *_surfaceFilename;
bool _2DOnly;
bool _3DOnly;
@@ -80,7 +81,7 @@ public:
BaseSurface *_surface;
// scripting interface
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scSetProperty(const char *name, ScValue *value);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
diff --git a/engines/wintermute/base/base_surface_storage.cpp b/engines/wintermute/base/base_surface_storage.cpp
index 1dcebb0595..4e795ca813 100644
--- a/engines/wintermute/base/base_surface_storage.cpp
+++ b/engines/wintermute/base/base_surface_storage.cpp
@@ -28,6 +28,7 @@
#include "engines/wintermute/base/base_surface_storage.h"
#include "engines/wintermute/base/gfx/base_surface.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/platform_osystem.h"
diff --git a/engines/wintermute/base/base_transition_manager.cpp b/engines/wintermute/base/base_transition_manager.cpp
index 5c28f36d30..7785f3d5af 100644
--- a/engines/wintermute/base/base_transition_manager.cpp
+++ b/engines/wintermute/base/base_transition_manager.cpp
@@ -28,6 +28,7 @@
#include "engines/wintermute/base/base_transition_manager.h"
#include "engines/wintermute/base/base_game.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
namespace Wintermute {
diff --git a/engines/wintermute/base/base_viewport.cpp b/engines/wintermute/base/base_viewport.cpp
index 3b003e1c49..7ec995449f 100644
--- a/engines/wintermute/base/base_viewport.cpp
+++ b/engines/wintermute/base/base_viewport.cpp
@@ -29,6 +29,7 @@
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/platform_osystem.h"
#include "engines/wintermute/base/base_viewport.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
namespace Wintermute {
diff --git a/engines/wintermute/base/file/base_disk_file.cpp b/engines/wintermute/base/file/base_disk_file.cpp
index 2d3951b026..25be3dad2d 100644
--- a/engines/wintermute/base/file/base_disk_file.cpp
+++ b/engines/wintermute/base/file/base_disk_file.cpp
@@ -178,10 +178,8 @@ Common::SeekableReadStream *openDiskFile(const Common::String &filename) {
}
delete[] compBuffer;
-
- return new Common::MemoryReadStream(data, uncompSize, DisposeAfterUse::YES);
delete file;
- file = NULL;
+ return new Common::MemoryReadStream(data, uncompSize, DisposeAfterUse::YES);
} else {
file->seek(0, SEEK_SET);
return file;
diff --git a/engines/wintermute/base/file/base_package.cpp b/engines/wintermute/base/file/base_package.cpp
index 9780992652..51a1558a7c 100644
--- a/engines/wintermute/base/file/base_package.cpp
+++ b/engines/wintermute/base/file/base_package.cpp
@@ -86,16 +86,16 @@ void TPackageHeader::readFromStream(Common::ReadStream *stream) {
_magic1 = stream->readUint32LE();
_magic2 = stream->readUint32LE();
_packageVersion = stream->readUint32LE();
-
+
_gameVersion = stream->readUint32LE();
-
+
_priority = stream->readByte();
_cd = stream->readByte();
_masterIndex = stream->readByte();
stream->readByte(); // To align the next byte...
-
+
_creationTime = stream->readUint32LE();
-
+
stream->read(_desc, 100);
_numDirs = stream->readUint32LE();
}
diff --git a/engines/wintermute/base/file/base_save_thumb_file.cpp b/engines/wintermute/base/file/base_save_thumb_file.cpp
index 5bdab0853e..94d3e5a94e 100644
--- a/engines/wintermute/base/file/base_save_thumb_file.cpp
+++ b/engines/wintermute/base/file/base_save_thumb_file.cpp
@@ -28,7 +28,6 @@
#include "engines/wintermute/base/base_persistence_manager.h"
#include "engines/wintermute/base/file/base_save_thumb_file.h"
-#include "engines/wintermute/platform_osystem.h"
namespace Wintermute {
diff --git a/engines/wintermute/base/font/base_font_bitmap.cpp b/engines/wintermute/base/font/base_font_bitmap.cpp
index fced08c7e2..55f46c476b 100644
--- a/engines/wintermute/base/font/base_font_bitmap.cpp
+++ b/engines/wintermute/base/font/base_font_bitmap.cpp
@@ -31,6 +31,7 @@
#include "engines/wintermute/base/base_parser.h"
#include "engines/wintermute/base/base_frame.h"
#include "engines/wintermute/base/gfx/base_surface.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_sub_frame.h"
#include "engines/wintermute/base/base_frame.h"
diff --git a/engines/wintermute/base/font/base_font_storage.cpp b/engines/wintermute/base/font/base_font_storage.cpp
index d26fa1d593..8128ffe897 100644
--- a/engines/wintermute/base/font/base_font_storage.cpp
+++ b/engines/wintermute/base/font/base_font_storage.cpp
@@ -29,7 +29,6 @@
#include "engines/wintermute/base/font/base_font_storage.h"
#include "engines/wintermute/base/font/base_font.h"
#include "engines/wintermute/base/base_game.h"
-#include "engines/wintermute/platform_osystem.h"
#include "common/str.h"
namespace Wintermute {
diff --git a/engines/wintermute/base/font/base_font_truetype.cpp b/engines/wintermute/base/font/base_font_truetype.cpp
index 599010bbd5..f236329fcd 100644
--- a/engines/wintermute/base/font/base_font_truetype.cpp
+++ b/engines/wintermute/base/font/base_font_truetype.cpp
@@ -26,11 +26,8 @@
* Copyright (c) 2011 Jan Nedoma
*/
-#include "engines/wintermute/base/file/base_file.h"
#include "engines/wintermute/base/font/base_font_truetype.h"
-#include "engines/wintermute/utils/path_util.h"
#include "engines/wintermute/utils/string_util.h"
-#include "engines/wintermute/math/math_util.h"
#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/gfx/base_surface.h"
#include "engines/wintermute/base/base_parser.h"
@@ -162,6 +159,11 @@ void BaseFontTT::drawText(const byte *text, int x, int y, int width, TTextAlign
// TODO: Why do we still insist on Widestrings everywhere?
/* if (_gameRef->_textEncoding == TEXT_UTF8) text = StringUtil::Utf8ToWide((char *)Text);
else text = StringUtil::AnsiToWide((char *)Text);*/
+ // HACK: J.U.L.I.A. uses CP1252, we need to fix that,
+ // And we still don't have any UTF8-support.
+ if (_gameRef->_textEncoding != TEXT_UTF8) {
+ textStr = StringUtil::ansiToWide((char *)text);
+ }
if (maxLength >= 0 && textStr.size() > (uint32)maxLength) {
textStr = Common::String(textStr.c_str(), (uint32)maxLength);
diff --git a/engines/wintermute/base/gfx/base_renderer.cpp b/engines/wintermute/base/gfx/base_renderer.cpp
index 9205438a5b..e7ffc14c25 100644
--- a/engines/wintermute/base/gfx/base_renderer.cpp
+++ b/engines/wintermute/base/gfx/base_renderer.cpp
@@ -129,13 +129,13 @@ void BaseRenderer::initSaveLoad(bool isSaving, bool quickSave) {
_indicatorDisplay = true;
_indicatorProgress = 0;
_hasDrawnSaveLoadImage = false;
-
+
if (isSaving && !quickSave) {
delete _saveLoadImage;
_saveLoadImage = NULL;
if (_saveImageName.size()) {
_saveLoadImage = createSurface();
-
+
if (!_saveLoadImage || DID_FAIL(_saveLoadImage->create(_saveImageName, true, 0, 0, 0))) {
delete _saveLoadImage;
_saveLoadImage = NULL;
@@ -146,7 +146,7 @@ void BaseRenderer::initSaveLoad(bool isSaving, bool quickSave) {
_saveLoadImage = NULL;
if (_loadImageName.size()) {
_saveLoadImage = createSurface();
-
+
if (!_saveLoadImage || DID_FAIL(_saveLoadImage->create(_loadImageName, true, 0, 0, 0))) {
delete _saveLoadImage;
_saveLoadImage = NULL;
@@ -360,7 +360,7 @@ bool BaseRenderer::displayIndicator() {
flip();
_hasDrawnSaveLoadImage = true;
}
-
+
if ((!_indicatorDisplay && _indicatorWidth <= 0) || _indicatorHeight <= 0) {
return STATUS_OK;
}
@@ -369,7 +369,7 @@ bool BaseRenderer::displayIndicator() {
for (int i = 0; i < _indicatorHeight; i++) {
drawLine(_indicatorX, _indicatorY + i, _indicatorX + curWidth, _indicatorY + i, _indicatorColor);
}
-
+
setup2D();
_indicatorWidthDrawn = curWidth;
if (_indicatorWidthDrawn) {
diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp
index 6d67253038..7970a25300 100644
--- a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp
+++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp
@@ -261,7 +261,7 @@ void BaseRenderOSystem::fade(uint16 alpha) {
void BaseRenderOSystem::fadeToColor(byte r, byte g, byte b, byte a, Common::Rect *rect) {
// This particular warning is rather messy, as this function is called a ton,
// thus we avoid printing it more than once.
-
+
// TODO: Add fading with dirty rects.
if (!_disableDirtyRects) {
warning("BaseRenderOSystem::FadeToColor - Breaks when using dirty rects");
@@ -573,6 +573,11 @@ Rect32 BaseRenderOSystem::getViewPort() {
//////////////////////////////////////////////////////////////////////////
void BaseRenderOSystem::modTargetRect(Common::Rect *rect) {
+ // FIXME: This is wrong in quite a few ways right now, and ends up
+ // breaking the notebook in Dirty Split, so we disable the correction
+ // for now, this will need fixing when a game with odd aspect-ratios
+ // show up.
+ return;
rect->left = (int16)MathUtil::round(rect->left * _ratioX + _borderLeft - _renderRect.left);
rect->top = (int16)MathUtil::round(rect->top * _ratioY + _borderTop - _renderRect.top);
rect->setWidth((int16)MathUtil::roundUp(rect->width() * _ratioX));
diff --git a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp
index d5464782a3..bee876bb65 100644
--- a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp
+++ b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp
@@ -26,7 +26,6 @@
* Copyright (c) 2011 Jan Nedoma
*/
-#include "engines/wintermute/base/file/base_file.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/gfx/osystem/base_surface_osystem.h"
diff --git a/engines/wintermute/base/particles/part_emitter.cpp b/engines/wintermute/base/particles/part_emitter.cpp
index 3655b89131..bab4d4609e 100644
--- a/engines/wintermute/base/particles/part_emitter.cpp
+++ b/engines/wintermute/base/particles/part_emitter.cpp
@@ -35,6 +35,7 @@
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_region.h"
#include "engines/wintermute/base/base_file_manager.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/utils/utils.h"
#include "engines/wintermute/platform_osystem.h"
#include "common/str.h"
@@ -603,41 +604,41 @@ bool PartEmitter::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisSt
}
//////////////////////////////////////////////////////////////////////////
-ScValue *PartEmitter::scGetProperty(const char *name) {
+ScValue *PartEmitter::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("particle-emitter");
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// X
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "X") == 0) {
+ else if (name == "X") {
_scValue->setInt(_posX);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Y
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Y") == 0) {
+ else if (name == "Y") {
_scValue->setInt(_posY);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Width
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Width") == 0) {
+ else if (name == "Width") {
_scValue->setInt(_width);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Height
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Height") == 0) {
+ else if (name == "Height") {
_scValue->setInt(_height);
return _scValue;
}
@@ -645,21 +646,21 @@ ScValue *PartEmitter::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Scale1
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Scale1") == 0) {
+ else if (name == "Scale1") {
_scValue->setFloat(_scale1);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Scale2
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Scale2") == 0) {
+ else if (name == "Scale2") {
_scValue->setFloat(_scale2);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// ScaleZBased
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "ScaleZBased") == 0) {
+ else if (name == "ScaleZBased") {
_scValue->setBool(_scaleZBased);
return _scValue;
}
@@ -667,21 +668,21 @@ ScValue *PartEmitter::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Velocity1
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Velocity1") == 0) {
+ else if (name == "Velocity1") {
_scValue->setFloat(_velocity1);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Velocity2
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Velocity2") == 0) {
+ else if (name == "Velocity2") {
_scValue->setFloat(_velocity2);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// VelocityZBased
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "VelocityZBased") == 0) {
+ else if (name == "VelocityZBased") {
_scValue->setBool(_velocityZBased);
return _scValue;
}
@@ -689,21 +690,21 @@ ScValue *PartEmitter::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// LifeTime1
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "LifeTime1") == 0) {
+ else if (name == "LifeTime1") {
_scValue->setInt(_lifeTime1);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// LifeTime2
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "LifeTime2") == 0) {
+ else if (name == "LifeTime2") {
_scValue->setInt(_lifeTime2);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// LifeTimeZBased
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "LifeTimeZBased") == 0) {
+ else if (name == "LifeTimeZBased") {
_scValue->setBool(_lifeTimeZBased);
return _scValue;
}
@@ -711,14 +712,14 @@ ScValue *PartEmitter::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Angle1
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Angle1") == 0) {
+ else if (name == "Angle1") {
_scValue->setInt(_angle1);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Angle2
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Angle2") == 0) {
+ else if (name == "Angle2") {
_scValue->setInt(_angle2);
return _scValue;
}
@@ -726,14 +727,14 @@ ScValue *PartEmitter::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// AngVelocity1
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "AngVelocity1") == 0) {
+ else if (name == "AngVelocity1") {
_scValue->setFloat(_angVelocity1);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// AngVelocity2
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "AngVelocity2") == 0) {
+ else if (name == "AngVelocity2") {
_scValue->setFloat(_angVelocity2);
return _scValue;
}
@@ -741,14 +742,14 @@ ScValue *PartEmitter::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Rotation1
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Rotation1") == 0) {
+ else if (name == "Rotation1") {
_scValue->setFloat(_rotation1);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Rotation2
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Rotation2") == 0) {
+ else if (name == "Rotation2") {
_scValue->setFloat(_rotation2);
return _scValue;
}
@@ -756,21 +757,21 @@ ScValue *PartEmitter::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Alpha1
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Alpha1") == 0) {
+ else if (name == "Alpha1") {
_scValue->setInt(_alpha1);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Alpha2
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Alpha2") == 0) {
+ else if (name == "Alpha2") {
_scValue->setInt(_alpha2);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// AlphaTimeBased
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "AlphaTimeBased") == 0) {
+ else if (name == "AlphaTimeBased") {
_scValue->setBool(_alphaTimeBased);
return _scValue;
}
@@ -778,14 +779,14 @@ ScValue *PartEmitter::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// MaxParticles
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "MaxParticles") == 0) {
+ else if (name == "MaxParticles") {
_scValue->setInt(_maxParticles);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// NumLiveParticles (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "NumLiveParticles") == 0) {
+ else if (name == "NumLiveParticles") {
int numAlive = 0;
for (uint32 i = 0; i < _particles.size(); i++) {
if (_particles[i] && !_particles[i]->_isDead) {
@@ -799,21 +800,21 @@ ScValue *PartEmitter::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// GenerationInterval
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "GenerationInterval") == 0) {
+ else if (name == "GenerationInterval") {
_scValue->setInt(_genInterval);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// GenerationAmount
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "GenerationAmount") == 0) {
+ else if (name == "GenerationAmount") {
_scValue->setInt(_genAmount);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// MaxBatches
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "MaxBatches") == 0) {
+ else if (name == "MaxBatches") {
_scValue->setInt(_maxBatches);
return _scValue;
}
@@ -821,14 +822,14 @@ ScValue *PartEmitter::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// FadeInTime
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "FadeInTime") == 0) {
+ else if (name == "FadeInTime") {
_scValue->setInt(_fadeInTime);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// FadeOutTime
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "FadeOutTime") == 0) {
+ else if (name == "FadeOutTime") {
_scValue->setInt(_fadeOutTime);
return _scValue;
}
@@ -836,21 +837,21 @@ ScValue *PartEmitter::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// GrowthRate1
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "GrowthRate1") == 0) {
+ else if (name == "GrowthRate1") {
_scValue->setFloat(_growthRate1);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// GrowthRate2
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "GrowthRate2") == 0) {
+ else if (name == "GrowthRate2") {
_scValue->setFloat(_growthRate2);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// ExponentialGrowth
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "ExponentialGrowth") == 0) {
+ else if (name == "ExponentialGrowth") {
_scValue->setBool(_exponentialGrowth);
return _scValue;
}
@@ -858,7 +859,7 @@ ScValue *PartEmitter::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// UseRegion
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "UseRegion") == 0) {
+ else if (name == "UseRegion") {
_scValue->setBool(_useRegion);
return _scValue;
}
@@ -866,7 +867,7 @@ ScValue *PartEmitter::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// EmitEvent
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "EmitEvent") == 0) {
+ else if (name == "EmitEvent") {
if (!_emitEvent) {
_scValue->setNULL();
} else {
diff --git a/engines/wintermute/base/particles/part_emitter.h b/engines/wintermute/base/particles/part_emitter.h
index 9a35cd9bbc..f2c8f139f1 100644
--- a/engines/wintermute/base/particles/part_emitter.h
+++ b/engines/wintermute/base/particles/part_emitter.h
@@ -63,7 +63,7 @@ public:
BaseArray<PartForce *> _forces;
// scripting interface
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scSetProperty(const char *name, ScValue *value);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
diff --git a/engines/wintermute/base/saveload.cpp b/engines/wintermute/base/saveload.cpp
index 06e9fd2565..12204e1b35 100644
--- a/engines/wintermute/base/saveload.cpp
+++ b/engines/wintermute/base/saveload.cpp
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -35,6 +35,7 @@
#include "engines/wintermute/base/base_region.h"
#include "engines/wintermute/base/base_sub_frame.h"
#include "engines/wintermute/base/font/base_font.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/sound/base_sound.h"
#include "engines/wintermute/base/scriptables/script.h"
#include "common/savefile.h"
@@ -44,11 +45,11 @@ namespace Wintermute {
bool SaveLoad::loadGame(const Common::String &filename, BaseGame *gameRef) {
gameRef->LOG(0, "Loading game '%s'...", filename.c_str());
-
+
bool ret;
-
+
gameRef->_renderer->initSaveLoad(false);
-
+
gameRef->_loadInProgress = true;
BasePersistenceManager *pm = new BasePersistenceManager();
if (DID_SUCCEED(ret = pm->initLoad(filename))) {
@@ -60,20 +61,20 @@ bool SaveLoad::loadGame(const Common::String &filename, BaseGame *gameRef) {
// data initialization after load
SaveLoad::initAfterLoad();
-
+
gameRef->applyEvent("AfterLoad", true);
-
+
gameRef->displayContent(true, false);
//_renderer->flip();
}
}
}
-
+
delete pm;
gameRef->_loadInProgress = false;
-
+
gameRef->_renderer->endSaveLoad();
-
+
//_gameRef->LOG(0, "Load end %d", BaseUtils::GetUsedMemMB());
// AdGame:
if (DID_SUCCEED(ret)) {
@@ -84,13 +85,13 @@ bool SaveLoad::loadGame(const Common::String &filename, BaseGame *gameRef) {
bool SaveLoad::saveGame(int slot, const char *desc, bool quickSave, BaseGame *gameRef) {
Common::String filename = SaveLoad::getSaveSlotFilename(slot);
-
+
gameRef->LOG(0, "Saving game '%s'...", filename.c_str());
-
+
gameRef->applyEvent("BeforeSave", true);
-
+
bool ret;
-
+
BasePersistenceManager *pm = new BasePersistenceManager();
if (DID_SUCCEED(ret = pm->initSave(desc))) {
gameRef->_renderer->initSaveLoad(true, quickSave); // TODO: The original code inited the indicator before the conditionals
@@ -103,11 +104,11 @@ bool SaveLoad::saveGame(int slot, const char *desc, bool quickSave, BaseGame *ga
}
}
}
-
+
delete pm;
-
+
gameRef->_renderer->endSaveLoad();
-
+
return ret;
}
@@ -165,21 +166,21 @@ Common::String SaveLoad::getSaveSlotFilename(int slot) {
bool SaveLoad::getSaveSlotDescription(int slot, char *buffer) {
buffer[0] = '\0';
-
+
Common::String filename = getSaveSlotFilename(slot);
BasePersistenceManager *pm = new BasePersistenceManager();
if (!pm) {
return false;
}
-
+
if (!(pm->initLoad(filename))) {
delete pm;
return false;
}
-
+
strcpy(buffer, pm->_savedDescription);
delete pm;
-
+
return true;
}
@@ -198,6 +199,6 @@ bool SaveLoad::emptySaveSlot(int slot) {
delete pm;
return true;
}
-
-
+
+
} // end of namespace Wintermute
diff --git a/engines/wintermute/base/saveload.h b/engines/wintermute/base/saveload.h
index e448cc8814..722f7a89b6 100644
--- a/engines/wintermute/base/saveload.h
+++ b/engines/wintermute/base/saveload.h
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -25,7 +25,7 @@
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
-
+
#ifndef WINTERMUTE_SAVEGAME_H
#define WINTERMUTE_SAVEGAME_H
@@ -39,7 +39,7 @@ public:
static bool isSaveSlotUsed(int slot);
static bool getSaveSlotDescription(int slot, char *buffer);
static Common::String getSaveSlotFilename(int slot);
-
+
static bool loadGame(const Common::String &filename, BaseGame *gameRef);
static bool saveGame(int slot, const char *desc, bool quickSave, BaseGame *gameRef);
static bool initAfterLoad();
diff --git a/engines/wintermute/base/scriptables/script_engine.cpp b/engines/wintermute/base/scriptables/script_engine.cpp
index 20e2ccadd1..3d1863946e 100644
--- a/engines/wintermute/base/scriptables/script_engine.cpp
+++ b/engines/wintermute/base/scriptables/script_engine.cpp
@@ -33,7 +33,6 @@
#include "engines/wintermute/base/scriptables/script_ext_math.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_game.h"
-#include "engines/wintermute/base/sound/base_sound.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/utils/utils.h"
diff --git a/engines/wintermute/base/scriptables/script_ext_array.cpp b/engines/wintermute/base/scriptables/script_ext_array.cpp
index 5ed07f0da6..613cbd0758 100644
--- a/engines/wintermute/base/scriptables/script_ext_array.cpp
+++ b/engines/wintermute/base/scriptables/script_ext_array.cpp
@@ -140,13 +140,13 @@ bool SXArray::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack,
//////////////////////////////////////////////////////////////////////////
-ScValue *SXArray::scGetProperty(const char *name) {
+ScValue *SXArray::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("array");
return _scValue;
}
@@ -154,7 +154,7 @@ ScValue *SXArray::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Length
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Length") == 0) {
+ else if (name == "Length") {
_scValue->setInt(_length);
return _scValue;
}
@@ -164,7 +164,7 @@ ScValue *SXArray::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
else {
char paramName[20];
- if (validNumber(name, paramName)) {
+ if (validNumber(name.c_str(), paramName)) { // TODO: Change to Common::String
return _values->getProp(paramName);
} else {
return _scValue;
diff --git a/engines/wintermute/base/scriptables/script_ext_array.h b/engines/wintermute/base/scriptables/script_ext_array.h
index d9805ef94f..284c547a27 100644
--- a/engines/wintermute/base/scriptables/script_ext_array.h
+++ b/engines/wintermute/base/scriptables/script_ext_array.h
@@ -41,7 +41,7 @@ public:
SXArray(BaseGame *inGame, ScStack *stack);
SXArray(BaseGame *inGame);
virtual ~SXArray();
- ScValue *scGetProperty(const char *name);
+ ScValue *scGetProperty(const Common::String &name);
bool scSetProperty(const char *name, ScValue *value);
bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
const char *scToString();
diff --git a/engines/wintermute/base/scriptables/script_ext_date.cpp b/engines/wintermute/base/scriptables/script_ext_date.cpp
index 11eead3b9c..5aa069d0b2 100644
--- a/engines/wintermute/base/scriptables/script_ext_date.cpp
+++ b/engines/wintermute/base/scriptables/script_ext_date.cpp
@@ -203,13 +203,13 @@ bool SXDate::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack,
//////////////////////////////////////////////////////////////////////////
-ScValue *SXDate::scGetProperty(const char *name) {
+ScValue *SXDate::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("date");
return _scValue;
} else {
@@ -224,7 +224,7 @@ bool SXDate::scSetProperty(const char *name, ScValue *value) {
//////////////////////////////////////////////////////////////////////////
// Name
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Name")==0){
+ if (name == "Name")==0){
setName(value->getString());
return STATUS_OK;
}
diff --git a/engines/wintermute/base/scriptables/script_ext_date.h b/engines/wintermute/base/scriptables/script_ext_date.h
index f6f04dd7e6..062b7c55c7 100644
--- a/engines/wintermute/base/scriptables/script_ext_date.h
+++ b/engines/wintermute/base/scriptables/script_ext_date.h
@@ -40,7 +40,7 @@ public:
DECLARE_PERSISTENT(SXDate, BaseScriptable)
SXDate(BaseGame *inGame, ScStack *Stack);
virtual ~SXDate();
- ScValue *scGetProperty(const char *name);
+ ScValue *scGetProperty(const Common::String &name);
bool scSetProperty(const char *name, ScValue *value);
bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
const char *scToString();
diff --git a/engines/wintermute/base/scriptables/script_ext_file.cpp b/engines/wintermute/base/scriptables/script_ext_file.cpp
index ab574d464b..a1d39c5d0a 100644
--- a/engines/wintermute/base/scriptables/script_ext_file.cpp
+++ b/engines/wintermute/base/scriptables/script_ext_file.cpp
@@ -33,7 +33,6 @@
#include "engines/wintermute/base/scriptables/script.h"
#include "engines/wintermute/utils/utils.h"
#include "engines/wintermute/base/base_game.h"
-#include "engines/wintermute/base/file/base_file.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/platform_osystem.h"
#include "engines/wintermute/base/scriptables/script_ext_file.h"
@@ -641,13 +640,13 @@ bool SXFile::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack,
//////////////////////////////////////////////////////////////////////////
-ScValue *SXFile::scGetProperty(const char *name) {
+ScValue *SXFile::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type (RO)
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("file");
return _scValue;
}
@@ -655,7 +654,7 @@ ScValue *SXFile::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Filename (RO)
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Filename") == 0) {
+ if (name == "Filename") {
_scValue->setString(_filename);
return _scValue;
}
@@ -663,7 +662,7 @@ ScValue *SXFile::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Position (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Position") == 0) {
+ else if (name == "Position") {
_scValue->setInt(getPos());
return _scValue;
}
@@ -671,7 +670,7 @@ ScValue *SXFile::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Length (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Length") == 0) {
+ else if (name == "Length") {
_scValue->setInt(getLength());
return _scValue;
}
@@ -679,7 +678,7 @@ ScValue *SXFile::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// TextMode (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "TextMode") == 0) {
+ else if (name == "TextMode") {
_scValue->setBool(_textMode);
return _scValue;
}
@@ -687,7 +686,7 @@ ScValue *SXFile::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// AccessMode (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "AccessMode") == 0) {
+ else if (name == "AccessMode") {
_scValue->setInt(_mode);
return _scValue;
} else {
diff --git a/engines/wintermute/base/scriptables/script_ext_file.h b/engines/wintermute/base/scriptables/script_ext_file.h
index b91a53e695..f7c72fcfb3 100644
--- a/engines/wintermute/base/scriptables/script_ext_file.h
+++ b/engines/wintermute/base/scriptables/script_ext_file.h
@@ -40,7 +40,7 @@ class BaseFile;
class SXFile : public BaseScriptable {
public:
DECLARE_PERSISTENT(SXFile, BaseScriptable)
- ScValue *scGetProperty(const char *name);
+ ScValue *scGetProperty(const Common::String &name);
bool scSetProperty(const char *name, ScValue *value);
bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
const char *scToString();
diff --git a/engines/wintermute/base/scriptables/script_ext_math.cpp b/engines/wintermute/base/scriptables/script_ext_math.cpp
index 598b80cff3..d816fbec65 100644
--- a/engines/wintermute/base/scriptables/script_ext_math.cpp
+++ b/engines/wintermute/base/scriptables/script_ext_math.cpp
@@ -250,13 +250,13 @@ bool SXMath::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack,
//////////////////////////////////////////////////////////////////////////
-ScValue *SXMath::scGetProperty(const char *name) {
+ScValue *SXMath::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("math");
return _scValue;
}
@@ -264,7 +264,7 @@ ScValue *SXMath::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// PI
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "PI") == 0) {
+ else if (name == "PI") {
_scValue->setFloat(M_PI);
return _scValue;
} else {
diff --git a/engines/wintermute/base/scriptables/script_ext_math.h b/engines/wintermute/base/scriptables/script_ext_math.h
index f86d59fe7b..48c43ea7e8 100644
--- a/engines/wintermute/base/scriptables/script_ext_math.h
+++ b/engines/wintermute/base/scriptables/script_ext_math.h
@@ -39,7 +39,7 @@ public:
DECLARE_PERSISTENT(SXMath, BaseScriptable)
SXMath(BaseGame *inGame);
virtual ~SXMath();
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
private:
diff --git a/engines/wintermute/base/scriptables/script_ext_mem_buffer.cpp b/engines/wintermute/base/scriptables/script_ext_mem_buffer.cpp
index 5ed9bd5313..8f05b7bff6 100644
--- a/engines/wintermute/base/scriptables/script_ext_mem_buffer.cpp
+++ b/engines/wintermute/base/scriptables/script_ext_mem_buffer.cpp
@@ -447,13 +447,13 @@ bool SXMemBuffer::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisSt
//////////////////////////////////////////////////////////////////////////
-ScValue *SXMemBuffer::scGetProperty(const char *name) {
+ScValue *SXMemBuffer::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type (RO)
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("membuffer");
return _scValue;
}
@@ -461,7 +461,7 @@ ScValue *SXMemBuffer::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Size (RO)
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Size") == 0) {
+ if (name == "Size") {
_scValue->setInt(_size);
return _scValue;
} else {
diff --git a/engines/wintermute/base/scriptables/script_ext_mem_buffer.h b/engines/wintermute/base/scriptables/script_ext_mem_buffer.h
index d2662b3036..1527a323dc 100644
--- a/engines/wintermute/base/scriptables/script_ext_mem_buffer.h
+++ b/engines/wintermute/base/scriptables/script_ext_mem_buffer.h
@@ -38,7 +38,7 @@ class SXMemBuffer : public BaseScriptable {
public:
virtual int scCompare(BaseScriptable *Val);
DECLARE_PERSISTENT(SXMemBuffer, BaseScriptable)
- ScValue *scGetProperty(const char *name);
+ ScValue *scGetProperty(const Common::String &name);
bool scSetProperty(const char *name, ScValue *value);
bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
const char *scToString();
diff --git a/engines/wintermute/base/scriptables/script_ext_string.cpp b/engines/wintermute/base/scriptables/script_ext_string.cpp
index 8d87a92dc1..5f7da1c2dd 100644
--- a/engines/wintermute/base/scriptables/script_ext_string.cpp
+++ b/engines/wintermute/base/scriptables/script_ext_string.cpp
@@ -343,20 +343,20 @@ bool SXString::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack
//////////////////////////////////////////////////////////////////////////
-ScValue *SXString::scGetProperty(const char *name) {
+ScValue *SXString::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type (RO)
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("string");
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Length (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Length") == 0) {
+ else if (name == "Length") {
if (_gameRef->_textEncoding == TEXT_UTF8) {
WideString wstr = StringUtil::utf8ToWide(_string);
_scValue->setInt(wstr.size());
@@ -369,7 +369,7 @@ ScValue *SXString::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Capacity
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Capacity") == 0) {
+ else if (name == "Capacity") {
_scValue->setInt(_capacity);
return _scValue;
} else {
diff --git a/engines/wintermute/base/scriptables/script_ext_string.h b/engines/wintermute/base/scriptables/script_ext_string.h
index 255b9c57eb..00bffab3a9 100644
--- a/engines/wintermute/base/scriptables/script_ext_string.h
+++ b/engines/wintermute/base/scriptables/script_ext_string.h
@@ -38,7 +38,7 @@ class SXString : public BaseScriptable {
public:
virtual int scCompare(BaseScriptable *Val);
DECLARE_PERSISTENT(SXString, BaseScriptable)
- ScValue *scGetProperty(const char *name);
+ ScValue *scGetProperty(const Common::String &name);
bool scSetProperty(const char *name, ScValue *value);
bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
void scSetString(const char *val);
diff --git a/engines/wintermute/base/sound/base_sound_buffer.cpp b/engines/wintermute/base/sound/base_sound_buffer.cpp
index 3fd6c4d5f2..250570f2b8 100644
--- a/engines/wintermute/base/sound/base_sound_buffer.cpp
+++ b/engines/wintermute/base/sound/base_sound_buffer.cpp
@@ -26,12 +26,10 @@
* Copyright (c) 2011 Jan Nedoma
*/
-#include "engines/wintermute/base/file/base_file.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/sound/base_sound_manager.h"
#include "engines/wintermute/base/sound/base_sound_buffer.h"
#include "engines/wintermute/base/base_file_manager.h"
-#include "engines/wintermute/utils/utils.h"
#include "engines/wintermute/wintermute.h"
#include "audio/audiostream.h"
#include "audio/mixer.h"
diff --git a/engines/wintermute/base/sound/base_sound_manager.cpp b/engines/wintermute/base/sound/base_sound_manager.cpp
index f7788cd255..441793144d 100644
--- a/engines/wintermute/base/sound/base_sound_manager.cpp
+++ b/engines/wintermute/base/sound/base_sound_manager.cpp
@@ -32,6 +32,7 @@
#include "engines/wintermute/utils/string_util.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_file_manager.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/sound/base_sound_buffer.h"
#include "engines/wintermute/wintermute.h"
#include "common/config-manager.h"
diff --git a/engines/wintermute/graphics/transparent_surface.cpp b/engines/wintermute/graphics/transparent_surface.cpp
index da01259b1b..9319899495 100644
--- a/engines/wintermute/graphics/transparent_surface.cpp
+++ b/engines/wintermute/graphics/transparent_surface.cpp
@@ -52,13 +52,13 @@ TransparentSurface::TransparentSurface(const Surface &surf, bool copyData) : Sur
void doBlitOpaque(byte *ino, byte* outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) {
byte *in, *out;
-
+
#ifdef SCUMM_LITTLE_ENDIAN
const int aIndex = 3;
#else
const int aIndex = 0;
#endif
-
+
for (uint32 i = 0; i < height; i++) {
out = outo;
in = ino;
@@ -121,7 +121,7 @@ void TransparentSurface::doBlitAlpha(byte *ino, byte* outo, uint32 width, uint32
int a = (pix >> aShift) & 0xff;
int outb, outg, outr, outa;
in += inStep;
-
+
switch (a) {
case 0: // Full transparency
out += 4;
diff --git a/engines/wintermute/persistent.h b/engines/wintermute/persistent.h
index 5bcf30787d..c862df5d6b 100644
--- a/engines/wintermute/persistent.h
+++ b/engines/wintermute/persistent.h
@@ -52,7 +52,7 @@ namespace Wintermute {
virtual bool persist(BasePersistenceManager* PersistMgr);\
void* operator new (size_t size);\
void operator delete(void* p);\
-
+
#define IMPLEMENT_PERSISTENT(class_name, persistent_class)\
const char class_name::_className[] = #class_name;\
@@ -80,7 +80,7 @@ namespace Wintermute {
SystemClassRegistry::getInstance()->unregisterInstance(#class_name, p);\
::operator delete(p);\
}\
-
+
#define TMEMBER(member_name) #member_name, &member_name
#define TMEMBER_INT(member_name) #member_name, (int*)&member_name
diff --git a/engines/wintermute/readme.txt b/engines/wintermute/readme.txt
deleted file mode 100644
index 57592dac2a..0000000000
--- a/engines/wintermute/readme.txt
+++ /dev/null
@@ -1,155 +0,0 @@
-Wintermute Engine - Copyright (c) 2011 Jan Nedoma
-ScummVM port by Einar Johan Trøan Sømåen (somaen)
-
-***************************
-*** General information ***
-***************************
-The Wintermute Engine is a game engine mainly aimed at creating adventure
-games, it supports both 3D, 2.5D, 2D and First-Person games, and has numerous
-games both free, open-source and commercial created with it. This port was
-created by somaen as part of Google Summer of Code 2012.
-
-****************
-*** Features ***
-****************
-This port of the Wintermute Engine (WME) is based on WME Lite, which lacks the following functionality
-originally found in WME: (from http://res.dead-code.org/doku.php/wmelite:start)
-
-The following features of WME 1.x are NOT supported by WME Lite:
-* 3D characters. WME Lite only supports 2D games.
-* Sprite frame mirroring.
-* Sprite rotations.
-* Sprite blending modes.
-* Video playback.
-* Plugins.
-* Calling external functions from DLL libraries from scripts.
-* Game Explorer support.
-* 'Directory' script object.
-
-This port does reimplement a few of these features, currently:
-* Sprite frame mirroring - WORKS.
-* Video playback - Theora PARTIALLY WORKING. (Slow, and doesn't support seeking)
-
-In addition, this port removes a few additional features that were never/rarely used:
-* 'File' script object - ScummVM doesn't have any easy way to write/read arbitrary files.
-* Debugger/Compiler - weren't properly accessible in WME Lite anyhow.
-* CD-numbering support in .dcp-files - was never used.
-* 'SaveDirectory'-property of 'Game' will not return anything usefull to the game-scripts (saving is handled through SaveFileMan)
-
-*******************************
-*** Additional limitations: ***
-*******************************
-* Only .OGG and RAW-.WAV sounds are supported at this point
-* TTF-fonts might behave a bit differently, owing to both the change to FreeType in WME Lite
- and the change in dpi in this port of WME.
-* The window-caption-setting in-game will be ignored, for the sake of concistency with ScummVM.
-* Most VKey-combinations might still be missing (as they already were in WME Lite)
-* Since we don't use FreeImage, some games might use odd files that weren't expected when the
- image-decoders in ScummVM were written. One example here is interlaced-PNGs.
-* UTF8-support is not ported, which means only games with western charsets will work for now.
-* Games that select language by moving .dcp-files around still need a bit more handling on detection/load
- adding support for those languages on a language-by-language basis.
-* Most games assume the availability of the Windows-fonts (particularly arial.ttf)
- at this point no fallback has been put in place for using FreeFonts as replacements,
- simply for lack of having them easily accessible to the engines at this point. So, at least
- arial.ttf should be put in either the game-folder or made available through the extras-folder
- for now, otherwise kGUIBigFont will be used as a replacement.
-
-
-*********************************
-*** Advanced engine-features: ***
-*********************************
-At this point the engine implements the following "advanced engine features":
-* RTL ("Return to Launcher") support
-* Global options dialog support
-* Listing savestates via command line or Launcher
-* Loading savestates via command line or Launcher
-* Deleting savestates via the Launcher and GMM
-* Savestate metadata support
-* Loading/Saving during run time
-
-and NOT the following:
-* Enhanced debug/error messages
-
-*****************
-*** Detection ***
-*****************
-Since Wintermute has authoring tools available, there will at any point in
-time be atleast a few games that are works-in-progress, and as the authors
-of these games might want to test their games in ScummVM, the engine has
-to be able to detect arbitrary Wintermute-games, to this end the detector
-code in this engine will check any folder containing "data.dcp", and try to
-read "startup.settings" and "default.game" (or optionally any other .game-file
-defined in startup.settings), the Name/Caption fields in the .game-file will
-be used as gameid/title (prefixing the gameid with "wmefan-" to avoid confusion
-with any other WME game that might happen to have taken that id.
-
-All COMPLETED games should have their md5s and gameid's properly added, IFF
-they don't require 3D.
-
-3D games may also be added, for the purpose of giving the user feedback
-as to why their game won't run, but at this point, any such MD5 should
-be added as a comment only, to avoid confusion, as no mechanism for giving
-the user feedback about 3D-games not being supported is currently added.
-
-*************************************
-*** Games targeted by the engine: ***
-*************************************
-This engine potentially targets a very large amount of games:
-http://res.dead-code.org/doku.php/games:start
-
-Since the feature-set of WME Lite differs from that of the full Wintermute Engine,
-games will need to be targeted on a case-by-case, feature-by-feature basis, this is
-a list of the games that are currently known to work (although perhaps with minor
-issues) through to completion:
-
-* Dirty Split (dirtysplit)
-* the white chamber (twc)
-* Chivalry is NOT dead (chivalry)
-* Rosemary (rosemary)
-* The Box (thebox)
-* J.U.L.I.A. (Demo) (julia)
-* Pigeons in the park (pigeons)
-
-Untested, but starts:
-* East Side Story (Demo) (eastside)
-* Actual Destination (actualdest)
-* Ghost in the sheet (ghostsheet)
-
-********************************
-*** Games with known issues: ***
-********************************
-Certain games will work mostly fine with this engine, but can still
-be impossible to complete for various reasons, this is a list of games
-that technically qualify (as in they do not require the 3D-parts of the engine)
-but have issues that make them problematic or not completable:
-
-Won't start:
-* Five Lethal Demons (5ld) - Requires support for interlaced PNGs
-* Five Magical Amulets (5ma) - Requires support for interlaced PNGs
-* Kulivoeko - Requires support for interlaced PNGs
-* Reversion (reversion) - Requires support for Non-V1.1 JPEGs and interlaced PNGs
-* Mirage (mirage) - Tries to seek in a vorbis-stream inside a ZipStream
-* Hamlet or the last game without MMORPS features, shaders and product placement (hamlet)
- - Requires support for interlaced PNGs
-
-Gameplay broken:
-* J.U.L.I.A. (Full game) (julia) - Requires sprite-rotation for a puzzle.
-
-Non-critical:
-* Ghost in the sheet (ghostsheet) - uses Non-V1.1-JPEGs
-* East Side Story (eastside) - wants "framd.ttf"
-
-*****************************
-*** General known issues: ***
-*****************************
-
-Mostly a TODO-section, to not forget fixing outstanding general issues:
-* Save/Load-screens are not shown during save/load
- this is probably a result of reducing the amount of redrawing done
- during save/load, and I'm not sure it should be put back, if that means
- making saves slower again.
-* Font-sizes are wrong enough to allow Dirty Split to draw text that is hidden in
- the original game (most visible on the coin-interface)
-* Alpha-masks for Theora-videos are broken on big-endian platforms
-
diff --git a/engines/wintermute/system/sys_class_registry.cpp b/engines/wintermute/system/sys_class_registry.cpp
index 5e3b968c5c..7c1911c2bf 100644
--- a/engines/wintermute/system/sys_class_registry.cpp
+++ b/engines/wintermute/system/sys_class_registry.cpp
@@ -29,6 +29,7 @@
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/platform_osystem.h"
#include "engines/wintermute/base/base_engine.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/system/sys_instance.h"
#include "engines/wintermute/system/sys_class_registry.h"
#include "engines/wintermute/system/sys_class.h"
diff --git a/engines/wintermute/ui/ui_button.cpp b/engines/wintermute/ui/ui_button.cpp
index f2ac5b2fdd..7967d566f9 100644
--- a/engines/wintermute/ui/ui_button.cpp
+++ b/engines/wintermute/ui/ui_button.cpp
@@ -37,6 +37,7 @@
#include "engines/wintermute/base/base_string_table.h"
#include "engines/wintermute/base/base_sprite.h"
#include "engines/wintermute/base/base_file_manager.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
@@ -1081,13 +1082,13 @@ bool UIButton::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack
//////////////////////////////////////////////////////////////////////////
-ScValue *UIButton::scGetProperty(const char *name) {
+ScValue *UIButton::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("button");
return _scValue;
}
@@ -1095,7 +1096,7 @@ ScValue *UIButton::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// TextAlign
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "TextAlign") == 0) {
+ else if (name == "TextAlign") {
_scValue->setInt(_align);
return _scValue;
}
@@ -1103,21 +1104,21 @@ ScValue *UIButton::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Focusable
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Focusable") == 0) {
+ else if (name == "Focusable") {
_scValue->setBool(_canFocus);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Pressed
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Pressed") == 0) {
+ else if (name == "Pressed") {
_scValue->setBool(_stayPressed);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// PixelPerfect
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "PixelPerfect") == 0) {
+ else if (name == "PixelPerfect") {
_scValue->setBool(_pixelPerfect);
return _scValue;
} else {
diff --git a/engines/wintermute/ui/ui_button.h b/engines/wintermute/ui/ui_button.h
index 9342f766cc..93333a2534 100644
--- a/engines/wintermute/ui/ui_button.h
+++ b/engines/wintermute/ui/ui_button.h
@@ -69,7 +69,7 @@ public:
virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent);
// scripting interface
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scSetProperty(const char *name, ScValue *value);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
diff --git a/engines/wintermute/ui/ui_edit.cpp b/engines/wintermute/ui/ui_edit.cpp
index 94d11255ce..a3283d5a01 100644
--- a/engines/wintermute/ui/ui_edit.cpp
+++ b/engines/wintermute/ui/ui_edit.cpp
@@ -40,6 +40,7 @@
#include "engines/wintermute/base/base_sprite.h"
#include "engines/wintermute/base/base_string_table.h"
#include "engines/wintermute/base/base_game.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "engines/wintermute/base/scriptables/script.h"
@@ -397,13 +398,13 @@ bool UIEdit::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack,
//////////////////////////////////////////////////////////////////////////
-ScValue *UIEdit::scGetProperty(const char *name) {
+ScValue *UIEdit::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("editor");
return _scValue;
}
@@ -411,7 +412,7 @@ ScValue *UIEdit::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// SelStart
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "SelStart") == 0) {
+ else if (name == "SelStart") {
_scValue->setInt(_selStart);
return _scValue;
}
@@ -419,7 +420,7 @@ ScValue *UIEdit::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// SelEnd
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "SelEnd") == 0) {
+ else if (name == "SelEnd") {
_scValue->setInt(_selEnd);
return _scValue;
}
@@ -427,7 +428,7 @@ ScValue *UIEdit::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// CursorBlinkRate
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "CursorBlinkRate") == 0) {
+ else if (name == "CursorBlinkRate") {
_scValue->setInt(_cursorBlinkRate);
return _scValue;
}
@@ -435,7 +436,7 @@ ScValue *UIEdit::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// CursorChar
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "CursorChar") == 0) {
+ else if (name == "CursorChar") {
_scValue->setString(_cursorChar);
return _scValue;
}
@@ -443,7 +444,7 @@ ScValue *UIEdit::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// FrameWidth
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "FrameWidth") == 0) {
+ else if (name == "FrameWidth") {
_scValue->setInt(_frameWidth);
return _scValue;
}
@@ -451,7 +452,7 @@ ScValue *UIEdit::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// MaxLength
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "MaxLength") == 0) {
+ else if (name == "MaxLength") {
_scValue->setInt(_maxLength);
return _scValue;
}
@@ -459,7 +460,7 @@ ScValue *UIEdit::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Text
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Text") == 0) {
+ else if (name == "Text") {
if (_gameRef->_textEncoding == TEXT_UTF8) {
WideString wstr = StringUtil::ansiToWide(_text);
_scValue->setString(StringUtil::wideToUtf8(wstr).c_str());
diff --git a/engines/wintermute/ui/ui_edit.h b/engines/wintermute/ui/ui_edit.h
index 610629afb3..5bb31422b6 100644
--- a/engines/wintermute/ui/ui_edit.h
+++ b/engines/wintermute/ui/ui_edit.h
@@ -61,7 +61,7 @@ public:
virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent);
// scripting interface
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scSetProperty(const char *name, ScValue *value);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
diff --git a/engines/wintermute/ui/ui_entity.cpp b/engines/wintermute/ui/ui_entity.cpp
index c49cb5a240..1cb4e0926b 100644
--- a/engines/wintermute/ui/ui_entity.cpp
+++ b/engines/wintermute/ui/ui_entity.cpp
@@ -305,13 +305,13 @@ bool UIEntity::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack
//////////////////////////////////////////////////////////////////////////
-ScValue *UIEntity::scGetProperty(const char *name) {
+ScValue *UIEntity::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("entity container");
return _scValue;
}
@@ -319,7 +319,7 @@ ScValue *UIEntity::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Freezable
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Freezable") == 0) {
+ else if (name == "Freezable") {
if (_entity) {
_scValue->setBool(_entity->_freezable);
} else {
diff --git a/engines/wintermute/ui/ui_entity.h b/engines/wintermute/ui/ui_entity.h
index 3bf8068fd5..b5f4450071 100644
--- a/engines/wintermute/ui/ui_entity.h
+++ b/engines/wintermute/ui/ui_entity.h
@@ -48,7 +48,7 @@ public:
bool setEntity(const char *filename);
// scripting interface
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scSetProperty(const char *name, ScValue *value);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
diff --git a/engines/wintermute/ui/ui_object.cpp b/engines/wintermute/ui/ui_object.cpp
index 85e381c55b..8e5bae993c 100644
--- a/engines/wintermute/ui/ui_object.cpp
+++ b/engines/wintermute/ui/ui_object.cpp
@@ -32,6 +32,7 @@
#include "engines/wintermute/ui/ui_tiled_image.h"
#include "engines/wintermute/ui/ui_window.h"
#include "engines/wintermute/platform_osystem.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "engines/wintermute/base/font/base_font_storage.h"
@@ -359,13 +360,13 @@ bool UIObject::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack
//////////////////////////////////////////////////////////////////////////
-ScValue *UIObject::scGetProperty(const char *name) {
+ScValue *UIObject::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("ui_object");
return _scValue;
}
@@ -373,7 +374,7 @@ ScValue *UIObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Name
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Name") == 0) {
+ else if (name == "Name") {
_scValue->setString(getName());
return _scValue;
}
@@ -381,7 +382,7 @@ ScValue *UIObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Parent (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Parent") == 0) {
+ else if (name == "Parent") {
_scValue->setNative(_parent, true);
return _scValue;
}
@@ -389,7 +390,7 @@ ScValue *UIObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// ParentNotify
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "ParentNotify") == 0) {
+ else if (name == "ParentNotify") {
_scValue->setBool(_parentNotify);
return _scValue;
}
@@ -397,7 +398,7 @@ ScValue *UIObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Width
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Width") == 0) {
+ else if (name == "Width") {
_scValue->setInt(_width);
return _scValue;
}
@@ -405,7 +406,7 @@ ScValue *UIObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Height
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Height") == 0) {
+ else if (name == "Height") {
_scValue->setInt(_height);
return _scValue;
}
@@ -413,7 +414,7 @@ ScValue *UIObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Visible
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Visible") == 0) {
+ else if (name == "Visible") {
_scValue->setBool(_visible);
return _scValue;
}
@@ -421,7 +422,7 @@ ScValue *UIObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Disabled
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Disabled") == 0) {
+ else if (name == "Disabled") {
_scValue->setBool(_disable);
return _scValue;
}
@@ -429,7 +430,7 @@ ScValue *UIObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Text
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Text") == 0) {
+ else if (name == "Text") {
_scValue->setString(_text);
return _scValue;
}
@@ -437,13 +438,13 @@ ScValue *UIObject::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// NextSibling (RO) / PrevSibling (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "NextSibling") == 0 || strcmp(name, "PrevSibling") == 0) {
+ else if (name == "NextSibling" || name == "PrevSibling") {
_scValue->setNULL();
if (_parent && _parent->_type == UI_WINDOW) {
UIWindow *win = (UIWindow *)_parent;
for (uint32 i = 0; i < win->_widgets.size(); i++) {
if (win->_widgets[i] == this) {
- if (strcmp(name, "NextSibling") == 0) {
+ if (name == "NextSibling") {
if (i < win->_widgets.size() - 1) {
_scValue->setNative(win->_widgets[i + 1], true);
}
diff --git a/engines/wintermute/ui/ui_object.h b/engines/wintermute/ui/ui_object.h
index 81c025d33b..ec2ea33de1 100644
--- a/engines/wintermute/ui/ui_object.h
+++ b/engines/wintermute/ui/ui_object.h
@@ -74,7 +74,7 @@ public:
virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent);
// scripting interface
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scSetProperty(const char *name, ScValue *value);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
diff --git a/engines/wintermute/ui/ui_text.cpp b/engines/wintermute/ui/ui_text.cpp
index 1844b640d0..2c10f176c7 100644
--- a/engines/wintermute/ui/ui_text.cpp
+++ b/engines/wintermute/ui/ui_text.cpp
@@ -431,13 +431,13 @@ bool UIText::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack,
//////////////////////////////////////////////////////////////////////////
-ScValue *UIText::scGetProperty(const char *name) {
+ScValue *UIText::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("static");
return _scValue;
}
@@ -445,7 +445,7 @@ ScValue *UIText::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// TextAlign
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "TextAlign") == 0) {
+ else if (name == "TextAlign") {
_scValue->setInt(_textAlign);
return _scValue;
}
@@ -453,7 +453,7 @@ ScValue *UIText::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// VerticalAlign
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "VerticalAlign") == 0) {
+ else if (name == "VerticalAlign") {
_scValue->setInt(_verticalAlign);
return _scValue;
} else {
diff --git a/engines/wintermute/ui/ui_text.h b/engines/wintermute/ui/ui_text.h
index d2f116b44b..da4d113500 100644
--- a/engines/wintermute/ui/ui_text.h
+++ b/engines/wintermute/ui/ui_text.h
@@ -49,7 +49,7 @@ public:
virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent);
// scripting interface
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scSetProperty(const char *name, ScValue *value);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
diff --git a/engines/wintermute/ui/ui_tiled_image.cpp b/engines/wintermute/ui/ui_tiled_image.cpp
index cec23cf67e..2b337330c7 100644
--- a/engines/wintermute/ui/ui_tiled_image.cpp
+++ b/engines/wintermute/ui/ui_tiled_image.cpp
@@ -33,6 +33,7 @@
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_sub_frame.h"
#include "engines/wintermute/base/base_file_manager.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/platform_osystem.h"
namespace Wintermute {
@@ -333,8 +334,8 @@ bool UITiledImage::saveAsText(BaseDynamicBuffer *buffer, int indent) {
buffer->putTextIndent(indent, "TILED_IMAGE\n");
buffer->putTextIndent(indent, "{\n");
- if (_image && _image->_surfaceFilename) {
- buffer->putTextIndent(indent + 2, "IMAGE=\"%s\"\n", _image->_surfaceFilename);
+ if (_image && _image->getSurfaceFilename()) {
+ buffer->putTextIndent(indent + 2, "IMAGE=\"%s\"\n", _image->getSurfaceFilename());
}
int h1, h2, h3;
diff --git a/engines/wintermute/ui/ui_window.cpp b/engines/wintermute/ui/ui_window.cpp
index 65af62141d..9606486efb 100644
--- a/engines/wintermute/ui/ui_window.cpp
+++ b/engines/wintermute/ui/ui_window.cpp
@@ -41,6 +41,7 @@
#include "engines/wintermute/base/font/base_font_storage.h"
#include "engines/wintermute/base/font/base_font.h"
#include "engines/wintermute/base/base_string_table.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/scriptables/script.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "engines/wintermute/base/base_sprite.h"
@@ -1013,13 +1014,13 @@ bool UIWindow::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack
//////////////////////////////////////////////////////////////////////////
-ScValue *UIWindow::scGetProperty(const char *name) {
+ScValue *UIWindow::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
- if (strcmp(name, "Type") == 0) {
+ if (name == "Type") {
_scValue->setString("window");
return _scValue;
}
@@ -1027,7 +1028,7 @@ ScValue *UIWindow::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// NumWidgets / NumControls (RO)
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "NumWidgets") == 0 || strcmp(name, "NumControls") == 0) {
+ else if (name == "NumWidgets" || name == "NumControls") {
_scValue->setInt(_widgets.size());
return _scValue;
}
@@ -1035,7 +1036,7 @@ ScValue *UIWindow::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Exclusive
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Exclusive") == 0) {
+ else if (name == "Exclusive") {
_scValue->setBool(_mode == WINDOW_EXCLUSIVE);
return _scValue;
}
@@ -1043,7 +1044,7 @@ ScValue *UIWindow::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// SystemExclusive
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "SystemExclusive") == 0) {
+ else if (name == "SystemExclusive") {
_scValue->setBool(_mode == WINDOW_SYSTEM_EXCLUSIVE);
return _scValue;
}
@@ -1051,7 +1052,7 @@ ScValue *UIWindow::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Menu
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Menu") == 0) {
+ else if (name == "Menu") {
_scValue->setBool(_isMenu);
return _scValue;
}
@@ -1059,7 +1060,7 @@ ScValue *UIWindow::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// InGame
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "InGame") == 0) {
+ else if (name == "InGame") {
_scValue->setBool(_inGame);
return _scValue;
}
@@ -1067,7 +1068,7 @@ ScValue *UIWindow::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// PauseMusic
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "PauseMusic") == 0) {
+ else if (name == "PauseMusic") {
_scValue->setBool(_pauseMusic);
return _scValue;
}
@@ -1075,7 +1076,7 @@ ScValue *UIWindow::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// ClipContents
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "ClipContents") == 0) {
+ else if (name == "ClipContents") {
_scValue->setBool(_clipContents);
return _scValue;
}
@@ -1083,7 +1084,7 @@ ScValue *UIWindow::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// Transparent
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "Transparent") == 0) {
+ else if (name == "Transparent") {
_scValue->setBool(_transparent);
return _scValue;
}
@@ -1091,7 +1092,7 @@ ScValue *UIWindow::scGetProperty(const char *name) {
//////////////////////////////////////////////////////////////////////////
// FadeColor
//////////////////////////////////////////////////////////////////////////
- else if (strcmp(name, "FadeColor") == 0) {
+ else if (name == "FadeColor") {
_scValue->setInt((int)_fadeColor);
return _scValue;
} else {
diff --git a/engines/wintermute/ui/ui_window.h b/engines/wintermute/ui/ui_window.h
index cbd417a7d9..ae035c65c7 100644
--- a/engines/wintermute/ui/ui_window.h
+++ b/engines/wintermute/ui/ui_window.h
@@ -83,7 +83,7 @@ public:
virtual bool saveAsText(BaseDynamicBuffer *buffer, int indent);
// scripting interface
- virtual ScValue *scGetProperty(const char *name);
+ virtual ScValue *scGetProperty(const Common::String &name);
virtual bool scSetProperty(const char *name, ScValue *value);
virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name);
virtual const char *scToString();
diff --git a/engines/wintermute/utils/string_util.cpp b/engines/wintermute/utils/string_util.cpp
index 2c3be8c2f5..7b3b0e1297 100644
--- a/engines/wintermute/utils/string_util.cpp
+++ b/engines/wintermute/utils/string_util.cpp
@@ -148,11 +148,11 @@ Utf8String StringUtil::wideToUtf8(const WideString &WideStr) {
// Currently this only does Ansi->ISO 8859, and only for carets.
char simpleAnsiToWide(const AnsiString &str, uint32 &offset) {
- char c = str[offset];
+ byte c = str[offset];
- if (c == 92) {
+ if (c == 146) {
offset++;
- return '\'';
+ return 39; // Replace right-quote with apostrophe
} else {
offset++;
return c;
@@ -162,11 +162,11 @@ char simpleAnsiToWide(const AnsiString &str, uint32 &offset) {
//////////////////////////////////////////////////////////////////////////
WideString StringUtil::ansiToWide(const AnsiString &str) {
// TODO: This function gets called a lot, so warnings like these drown out the usefull information
- /*Common::String converted = "";
+ Common::String converted = "";
uint32 index = 0;
while (index != str.size()) {
converted += simpleAnsiToWide(str, index);
- }*/
+ }
// using default os locale!
/* setlocale(LC_CTYPE, "");
@@ -176,7 +176,7 @@ WideString StringUtil::ansiToWide(const AnsiString &str) {
WideString ResultString(wstr);
delete[] wstr;
return ResultString;*/
- return WideString(str);
+ return WideString(converted);
}
//////////////////////////////////////////////////////////////////////////
diff --git a/engines/wintermute/video/video_theora_player.cpp b/engines/wintermute/video/video_theora_player.cpp
index 0d23a04af4..d14c807e11 100644
--- a/engines/wintermute/video/video_theora_player.cpp
+++ b/engines/wintermute/video/video_theora_player.cpp
@@ -32,8 +32,8 @@
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/gfx/osystem/base_surface_osystem.h"
#include "engines/wintermute/base/gfx/base_image.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/sound/base_sound_manager.h"
-#include "engines/wintermute/utils/utils.h"
#include "engines/wintermute/platform_osystem.h"
#include "video/theora_decoder.h"
#include "engines/wintermute/wintermute.h"
@@ -151,7 +151,32 @@ bool VideoTheoraPlayer::initialize(const Common::String &filename, const Common:
//////////////////////////////////////////////////////////////////////////
bool VideoTheoraPlayer::resetStream() {
- warning("VidTheoraPlayer::resetStream - stubbed");
+ warning("VidTheoraPlayer::resetStream - hacked");
+ // HACK: Just reopen the same file again.
+ if (_theoraDecoder) {
+ _theoraDecoder->close();
+ }
+ delete _theoraDecoder;
+ _theoraDecoder = NULL;
+
+ _file = BaseFileManager::getEngineInstance()->openFile(_filename, true, false);
+ if (!_file) {
+ return STATUS_FAILED;
+ }
+
+#if defined (USE_THEORADEC)
+ _theoraDecoder = new Video::TheoraDecoder();
+#else
+ return STATUS_FAILED;
+#endif
+ _theoraDecoder->loadStream(_file);
+
+ if (!_theoraDecoder->isVideoLoaded()) {
+ return STATUS_FAILED;
+ }
+
+ return play(_playbackType, _posX, _posY, false, false, _looping, 0, _playZoom);
+ // End of hack.
#if 0 // Stubbed for now, as theora isn't seekable
if (_sound) {
_sound->Stop();
@@ -265,8 +290,10 @@ bool VideoTheoraPlayer::update() {
if (_theoraDecoder) {
if (_theoraDecoder->endOfVideo() && _looping) {
- warning("Should loop movie %s", _filename.c_str());
+ warning("Should loop movie %s, hacked for now", _filename.c_str());
_theoraDecoder->rewind();
+ //HACK: Just reinitialize the same video again:
+ return resetStream();
} else if (_theoraDecoder->endOfVideo() && !_looping) {
debugC(kWintermuteDebugLog, "Finished movie %s", _filename.c_str());
_state = THEORA_STATE_FINISHED;
diff --git a/engines/wintermute/wintermute.cpp b/engines/wintermute/wintermute.cpp
index 9ada07293f..c9726e150a 100644
--- a/engines/wintermute/wintermute.cpp
+++ b/engines/wintermute/wintermute.cpp
@@ -39,6 +39,7 @@
#include "engines/wintermute/base/sound/base_sound_manager.h"
#include "engines/wintermute/base/base_file_manager.h"
+#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/scriptables/script_engine.h"
namespace Wintermute {