aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
Diffstat (limited to 'engines')
-rw-r--r--engines/access/access.cpp4
-rw-r--r--engines/access/access.h8
-rw-r--r--engines/access/amazon/amazon_game.cpp2
-rw-r--r--engines/access/amazon/amazon_logic.cpp28
-rw-r--r--engines/access/asurface.cpp51
-rw-r--r--engines/access/asurface.h30
-rw-r--r--engines/access/bubble_box.cpp15
-rw-r--r--engines/access/char.cpp3
-rw-r--r--engines/access/detection.cpp2
-rw-r--r--engines/access/font.cpp4
-rw-r--r--engines/access/font.h4
-rw-r--r--engines/access/inventory.cpp1
-rw-r--r--engines/access/room.cpp4
-rw-r--r--engines/access/screen.cpp10
-rw-r--r--engines/access/screen.h4
-rw-r--r--engines/access/video.cpp6
-rw-r--r--engines/access/video.h8
-rw-r--r--engines/agi/agi.cpp8
-rw-r--r--engines/agi/agi.h6
-rw-r--r--engines/agi/global.cpp1
-rw-r--r--engines/agi/graphics.cpp12
-rw-r--r--engines/agi/op_cmd.cpp6
-rw-r--r--engines/agi/op_test.cpp4
-rw-r--r--engines/agi/preagi.cpp8
-rw-r--r--engines/agi/preagi.h3
-rw-r--r--engines/agi/preagi_mickey.cpp4
-rw-r--r--engines/agi/preagi_winnie.cpp2
-rw-r--r--engines/agi/saveload.cpp7
-rw-r--r--engines/agi/sound.cpp10
-rw-r--r--engines/agi/sound.h14
-rw-r--r--engines/agi/sound_2gs.cpp5
-rw-r--r--engines/agi/sound_pcjr.cpp5
-rw-r--r--engines/agi/sound_sarien.cpp5
-rw-r--r--engines/agi/systemui.cpp2
-rw-r--r--engines/agi/text.cpp4
-rw-r--r--engines/agos/animation.cpp1
-rw-r--r--engines/agos/detection_tables.h25
-rw-r--r--engines/agos/feeble.cpp1
-rw-r--r--engines/agos/saveload.cpp2
-rw-r--r--engines/agos/string.cpp6
-rw-r--r--engines/agos/string_pn.cpp2
-rw-r--r--engines/cge/cge.h4
-rw-r--r--engines/cge/detection.cpp2
-rw-r--r--engines/cge2/cge2.h6
-rw-r--r--engines/cge2/detection.cpp2
-rw-r--r--engines/cge2/vga13h.cpp5
-rw-r--r--engines/cine/cine.h4
-rw-r--r--engines/composer/composer.h4
-rw-r--r--engines/cruise/cell.cpp9
-rw-r--r--engines/cruise/ctp.cpp2
-rw-r--r--engines/cruise/dataLoader.cpp11
-rw-r--r--engines/draci/draci.h6
-rw-r--r--engines/drascula/actors.cpp20
-rw-r--r--engines/drascula/animation.cpp4
-rw-r--r--engines/drascula/drascula.cpp16
-rw-r--r--engines/drascula/drascula.h6
-rw-r--r--engines/drascula/graphics.cpp6
-rw-r--r--engines/drascula/interface.cpp9
-rw-r--r--engines/drascula/objects.cpp2
-rw-r--r--engines/drascula/rooms.cpp2
-rw-r--r--engines/drascula/sound.cpp25
-rw-r--r--engines/drascula/talk.cpp10
-rw-r--r--engines/dreamweb/dreamweb.h4
-rw-r--r--engines/fullpipe/fullpipe.cpp4
-rw-r--r--engines/fullpipe/fullpipe.h8
-rw-r--r--engines/fullpipe/motion.cpp4
-rw-r--r--engines/fullpipe/sound.cpp22
-rw-r--r--engines/fullpipe/sound.h8
-rw-r--r--engines/fullpipe/statics.cpp3
-rw-r--r--engines/gnap/character.cpp1415
-rw-r--r--engines/gnap/character.h146
-rw-r--r--engines/gnap/configure.engine3
-rw-r--r--engines/gnap/datarchive.cpp124
-rw-r--r--engines/gnap/datarchive.h80
-rw-r--r--engines/gnap/debugger.cpp42
-rw-r--r--engines/gnap/debugger.h (renamed from engines/scumm/he/logic/moonbase.cpp)48
-rw-r--r--engines/gnap/detection.cpp197
-rw-r--r--engines/gnap/fontdata.h849
-rw-r--r--engines/gnap/gamesys.cpp1260
-rw-r--r--engines/gnap/gamesys.h211
-rw-r--r--engines/gnap/gnap.cpp1190
-rw-r--r--engines/gnap/gnap.h477
-rw-r--r--engines/gnap/grid.cpp995
-rw-r--r--engines/gnap/menu.cpp888
-rw-r--r--engines/gnap/module.mk32
-rw-r--r--engines/gnap/music.cpp104
-rw-r--r--engines/gnap/music.h50
-rw-r--r--engines/gnap/resource.cpp121
-rw-r--r--engines/gnap/resource.h190
-rw-r--r--engines/gnap/scenes/arcade.cpp2729
-rw-r--r--engines/gnap/scenes/arcade.h290
-rw-r--r--engines/gnap/scenes/group0.cpp3570
-rw-r--r--engines/gnap/scenes/group0.h401
-rw-r--r--engines/gnap/scenes/group1.cpp4500
-rw-r--r--engines/gnap/scenes/group1.h454
-rw-r--r--engines/gnap/scenes/group2.cpp3423
-rw-r--r--engines/gnap/scenes/group2.h407
-rw-r--r--engines/gnap/scenes/group3.cpp1612
-rw-r--r--engines/gnap/scenes/group3.h240
-rw-r--r--engines/gnap/scenes/group4.cpp2799
-rw-r--r--engines/gnap/scenes/group4.h298
-rw-r--r--engines/gnap/scenes/group5.cpp381
-rw-r--r--engines/gnap/scenes/group5.h77
-rw-r--r--engines/gnap/scenes/groupcs.cpp430
-rw-r--r--engines/gnap/scenes/groupcs.h122
-rw-r--r--engines/gnap/scenes/intro.cpp182
-rw-r--r--engines/gnap/scenes/intro.h47
-rw-r--r--engines/gnap/scenes/scenecore.cpp740
-rw-r--r--engines/gnap/scenes/scenecore.h70
-rw-r--r--engines/gnap/sound.cpp96
-rw-r--r--engines/gnap/sound.h57
-rw-r--r--engines/gob/gob.cpp1
-rw-r--r--engines/gob/inter_playtoons.cpp1
-rw-r--r--engines/gob/inter_v4.cpp2
-rw-r--r--engines/gob/pregob/onceupon/onceupon.cpp2
-rw-r--r--engines/gob/pregob/pregob.h4
-rw-r--r--engines/gob/sound/bgatmosphere.cpp9
-rw-r--r--engines/gob/sound/bgatmosphere.h10
-rw-r--r--engines/gob/sound/sound.cpp3
-rw-r--r--engines/gob/sound/sound.h10
-rw-r--r--engines/gob/videoplayer.cpp2
-rw-r--r--engines/gob/videoplayer.h5
-rw-r--r--engines/groovie/cell.cpp1
-rw-r--r--engines/groovie/cursor.cpp2
-rw-r--r--engines/groovie/font.h2
-rw-r--r--engines/groovie/graphics.cpp2
-rw-r--r--engines/groovie/groovie.h6
-rw-r--r--engines/groovie/music.cpp5
-rw-r--r--engines/groovie/music.h2
-rw-r--r--engines/groovie/player.cpp3
-rw-r--r--engines/hopkins/detection.cpp2
-rw-r--r--engines/hugo/hugo.h6
-rw-r--r--engines/kyra/items_lok.cpp2
-rw-r--r--engines/kyra/resource.h1
-rw-r--r--engines/kyra/staticres.cpp14
-rw-r--r--engines/lab/anim.cpp8
-rw-r--r--engines/lab/detection.cpp2
-rw-r--r--engines/lab/processroom.cpp9
-rw-r--r--engines/lastexpress/entities/gendarmes.cpp2
-rw-r--r--engines/lastexpress/lastexpress.h6
-rw-r--r--engines/lastexpress/sound/entry.cpp2
-rw-r--r--engines/lure/game.cpp16
-rw-r--r--engines/lure/hotspots.cpp20
-rw-r--r--engines/lure/lure.h4
-rw-r--r--engines/lure/scripts.cpp6
-rw-r--r--engines/made/database.cpp1
-rw-r--r--engines/made/made.cpp15
-rw-r--r--engines/made/pmvplayer.cpp5
-rw-r--r--engines/made/redreader.cpp2
-rw-r--r--engines/made/resource.cpp4
-rw-r--r--engines/made/screen.cpp2
-rw-r--r--engines/made/sound.cpp5
-rw-r--r--engines/mads/detection.cpp2
-rw-r--r--engines/mads/dragonsphere/dragonsphere_scenes.cpp4
-rw-r--r--engines/mads/dragonsphere/dragonsphere_scenes.h4
-rw-r--r--engines/mads/font.cpp2
-rw-r--r--engines/mads/font.h2
-rw-r--r--engines/mads/mads.cpp1
-rw-r--r--engines/mads/menu_views.h8
-rw-r--r--engines/mads/messages.cpp2
-rw-r--r--engines/mads/messages.h2
-rw-r--r--engines/mads/msurface.cpp26
-rw-r--r--engines/mads/msurface.h34
-rw-r--r--engines/mads/nebular/nebular_scenes.cpp4
-rw-r--r--engines/mads/nebular/nebular_scenes.h4
-rw-r--r--engines/mads/phantom/phantom_scenes.cpp4
-rw-r--r--engines/mads/phantom/phantom_scenes.h4
-rw-r--r--engines/mads/scene_data.cpp8
-rw-r--r--engines/mads/scene_data.h12
-rw-r--r--engines/mads/screen.cpp4
-rw-r--r--engines/mads/screen.h6
-rw-r--r--engines/mads/sprites.cpp2
-rw-r--r--engines/mads/user_interface.cpp4
-rw-r--r--engines/mads/user_interface.h2
-rw-r--r--engines/mohawk/mohawk.h4
-rw-r--r--engines/mohawk/myst.cpp3
-rw-r--r--engines/mortevielle/mortevielle.cpp1
-rw-r--r--engines/neverhood/diskplayerscene.cpp1
-rw-r--r--engines/neverhood/diskplayerscene.h2
-rw-r--r--engines/neverhood/menumodule.cpp2
-rw-r--r--engines/neverhood/modules/module1300.cpp1
-rw-r--r--engines/neverhood/modules/module1300.h3
-rw-r--r--engines/neverhood/modules/module1300_sprites.h1
-rw-r--r--engines/neverhood/modules/module2800.cpp1
-rw-r--r--engines/neverhood/navigationscene.h1
-rw-r--r--engines/neverhood/neverhood.cpp2
-rw-r--r--engines/neverhood/neverhood.h6
-rw-r--r--engines/neverhood/scene.cpp1
-rw-r--r--engines/neverhood/scene.h2
-rw-r--r--engines/neverhood/screen.cpp1
-rw-r--r--engines/neverhood/screen.h5
-rw-r--r--engines/neverhood/smackerscene.cpp1
-rw-r--r--engines/neverhood/sound.cpp61
-rw-r--r--engines/neverhood/sound.h25
-rw-r--r--engines/parallaction/adlib.cpp9
-rw-r--r--engines/parallaction/balloons.cpp15
-rw-r--r--engines/parallaction/debug.cpp1
-rw-r--r--engines/parallaction/dialogue.cpp16
-rw-r--r--engines/parallaction/disk_br.cpp5
-rw-r--r--engines/parallaction/disk_ns.cpp2
-rw-r--r--engines/parallaction/exec.cpp2
-rw-r--r--engines/parallaction/font.cpp2
-rw-r--r--engines/parallaction/gfxbase.cpp3
-rw-r--r--engines/parallaction/graphics.cpp2
-rw-r--r--engines/parallaction/graphics.h2
-rw-r--r--engines/parallaction/gui_br.cpp6
-rw-r--r--engines/parallaction/gui_ns.cpp15
-rw-r--r--engines/parallaction/input.cpp3
-rw-r--r--engines/parallaction/objects.cpp7
-rw-r--r--engines/parallaction/parallaction.cpp4
-rw-r--r--engines/parallaction/parallaction.h4
-rw-r--r--engines/parallaction/parallaction_br.cpp2
-rw-r--r--engines/parallaction/parallaction_ns.cpp2
-rw-r--r--engines/parallaction/parser.cpp1
-rw-r--r--engines/parallaction/parser.h2
-rw-r--r--engines/parallaction/saveload.cpp2
-rw-r--r--engines/parallaction/sound_br.cpp7
-rw-r--r--engines/parallaction/sound_ns.cpp7
-rw-r--r--engines/pegasus/neighborhood/mars/mars.cpp2
-rw-r--r--engines/pegasus/pegasus.h4
-rw-r--r--engines/prince/prince.cpp26
-rw-r--r--engines/prince/prince.h4
-rw-r--r--engines/queen/queen.h4
-rw-r--r--engines/saga/interface.cpp5
-rw-r--r--engines/saga/isomap.cpp17
-rw-r--r--engines/saga/puzzle.cpp5
-rw-r--r--engines/saga/saga.h4
-rw-r--r--engines/saga/saveload.cpp2
-rw-r--r--engines/saga/scene.cpp27
-rw-r--r--engines/sci/console.cpp9
-rw-r--r--engines/sci/detection_tables.h131
-rw-r--r--engines/sci/engine/kernel_tables.h2
-rw-r--r--engines/sci/engine/kgraphics32.cpp3
-rw-r--r--engines/sci/engine/kscripts.cpp3
-rw-r--r--engines/sci/engine/savegame.cpp2
-rw-r--r--engines/sci/engine/script_patches.cpp97
-rw-r--r--engines/sci/engine/workarounds.cpp1
-rw-r--r--engines/sci/graphics/celobj32.cpp54
-rw-r--r--engines/sci/graphics/celobj32.h8
-rw-r--r--engines/sci/graphics/compare.cpp20
-rw-r--r--engines/sci/graphics/controls32.cpp5
-rw-r--r--engines/sci/graphics/frameout.cpp8
-rw-r--r--engines/sci/graphics/plane32.cpp14
-rw-r--r--engines/sci/graphics/plane32.h20
-rw-r--r--engines/sci/graphics/screen_item32.cpp18
-rw-r--r--engines/sci/graphics/screen_item32.h4
-rw-r--r--engines/sci/graphics/text32.cpp20
-rw-r--r--engines/sci/graphics/text32.h16
-rw-r--r--engines/sci/sci.h6
-rw-r--r--engines/scumm/actor.cpp7
-rw-r--r--engines/scumm/detection.cpp5
-rw-r--r--engines/scumm/detection_tables.h2
-rw-r--r--engines/scumm/he/intern_he.h25
-rw-r--r--engines/scumm/he/logic/moonbase_logic.cpp255
-rw-r--r--engines/scumm/he/logic_he.cpp2
-rw-r--r--engines/scumm/he/logic_he.h2
-rw-r--r--engines/scumm/he/moonbase/ai_defenseunit.cpp767
-rw-r--r--engines/scumm/he/moonbase/ai_defenseunit.h195
-rw-r--r--engines/scumm/he/moonbase/ai_main.cpp3067
-rw-r--r--engines/scumm/he/moonbase/ai_main.h211
-rw-r--r--engines/scumm/he/moonbase/ai_node.cpp153
-rw-r--r--engines/scumm/he/moonbase/ai_node.h103
-rw-r--r--engines/scumm/he/moonbase/ai_pattern.h162
-rw-r--r--engines/scumm/he/moonbase/ai_targetacquisition.cpp557
-rw-r--r--engines/scumm/he/moonbase/ai_targetacquisition.h152
-rw-r--r--engines/scumm/he/moonbase/ai_traveller.cpp277
-rw-r--r--engines/scumm/he/moonbase/ai_traveller.h123
-rw-r--r--engines/scumm/he/moonbase/ai_tree.cpp245
-rw-r--r--engines/scumm/he/moonbase/ai_tree.h84
-rw-r--r--engines/scumm/he/moonbase/ai_types.cpp176
-rw-r--r--engines/scumm/he/moonbase/ai_types.h97
-rw-r--r--engines/scumm/he/moonbase/ai_weapon.cpp88
-rw-r--r--engines/scumm/he/moonbase/ai_weapon.h59
-rw-r--r--engines/scumm/he/moonbase/moonbase.cpp223
-rw-r--r--engines/scumm/he/moonbase/moonbase.h111
-rw-r--r--engines/scumm/he/moonbase/moonbase_fow.cpp415
-rw-r--r--engines/scumm/he/script_v100he.cpp350
-rw-r--r--engines/scumm/he/script_v70he.cpp1
-rw-r--r--engines/scumm/he/script_v72he.cpp42
-rw-r--r--engines/scumm/he/script_v90he.cpp34
-rw-r--r--engines/scumm/he/sound_he.cpp6
-rw-r--r--engines/scumm/he/sound_he.h2
-rw-r--r--engines/scumm/he/sprite_he.cpp30
-rw-r--r--engines/scumm/he/sprite_he.h8
-rw-r--r--engines/scumm/he/wiz_he.cpp321
-rw-r--r--engines/scumm/he/wiz_he.h90
-rw-r--r--engines/scumm/input.cpp1
-rw-r--r--engines/scumm/module.mk14
-rw-r--r--engines/scumm/scumm-md5.h4
-rw-r--r--engines/scumm/scumm.cpp24
-rw-r--r--engines/scumm/scumm.h5
-rw-r--r--engines/scumm/scumm_v2.h2
-rw-r--r--engines/scumm/scumm_v6.h3
-rw-r--r--engines/scumm/smush/smush_player.cpp32
-rw-r--r--engines/scumm/smush/smush_player.h6
-rw-r--r--engines/scumm/sound.cpp21
-rw-r--r--engines/scumm/sound.h10
-rw-r--r--engines/scumm/string.cpp3
-rw-r--r--engines/scumm/vars.cpp13
-rw-r--r--engines/sherlock/fonts.cpp2
-rw-r--r--engines/sherlock/fonts.h4
-rw-r--r--engines/sherlock/image_file.cpp12
-rw-r--r--engines/sherlock/image_file.h3
-rw-r--r--engines/sherlock/scalpel/scalpel_inventory.cpp2
-rw-r--r--engines/sherlock/screen.cpp5
-rw-r--r--engines/sherlock/screen.h3
-rw-r--r--engines/sherlock/sherlock.h4
-rw-r--r--engines/sherlock/surface.cpp15
-rw-r--r--engines/sherlock/surface.h28
-rw-r--r--engines/sherlock/tattoo/tattoo_fixed_text.h2
-rw-r--r--engines/sherlock/tattoo/tattoo_journal.cpp46
-rw-r--r--engines/sherlock/tattoo/tattoo_people.h3
-rw-r--r--engines/sky/control.cpp35
-rw-r--r--engines/sky/control.h2
-rw-r--r--engines/sky/sky.h4
-rw-r--r--engines/sky/skydefs.h1
-rw-r--r--engines/sword1/resman.cpp13
-rw-r--r--engines/sword1/sword1.h6
-rw-r--r--engines/sword2/screen.cpp4
-rw-r--r--engines/sword2/sword2.h4
-rw-r--r--engines/sword25/gfx/image/vectorimage.cpp1
-rw-r--r--engines/sword25/gfx/renderobject.cpp29
-rw-r--r--engines/sword25/package/packagemanager.cpp2
-rw-r--r--engines/sword25/sword25.h4
-rw-r--r--engines/teenagent/music.cpp4
-rw-r--r--engines/teenagent/music.h1
-rw-r--r--engines/teenagent/objects.h4
-rw-r--r--engines/teenagent/scene.cpp27
-rw-r--r--engines/teenagent/scene.h4
-rw-r--r--engines/teenagent/teenagent.cpp7
-rw-r--r--engines/teenagent/teenagent.h4
-rw-r--r--engines/testbed/testbed.h6
-rw-r--r--engines/tinsel/bmv.cpp4
-rw-r--r--engines/tinsel/detection.cpp4
-rw-r--r--engines/tinsel/dialogs.cpp30
-rw-r--r--engines/tinsel/handle.cpp2
-rw-r--r--engines/tinsel/saveload.cpp2
-rw-r--r--engines/tinsel/tinsel.h6
-rw-r--r--engines/toltecs/movie.cpp2
-rw-r--r--engines/toltecs/resource.cpp1
-rw-r--r--engines/toltecs/sprite.cpp3
-rw-r--r--engines/toltecs/toltecs.h6
-rw-r--r--engines/tony/gfxcore.cpp14
-rw-r--r--engines/tony/mpal/loadmpc.cpp2
-rw-r--r--engines/tony/mpal/mpal.cpp41
-rw-r--r--engines/tony/tony.h6
-rw-r--r--engines/touche/touche.h4
-rw-r--r--engines/tsage/detection.cpp2
-rw-r--r--engines/tsage/graphics.cpp6
-rw-r--r--engines/tsage/graphics.h14
-rw-r--r--engines/tsage/ringworld2/ringworld2_scenes2.cpp2
-rw-r--r--engines/tsage/screen.cpp7
-rw-r--r--engines/tsage/screen.h11
-rw-r--r--engines/tsage/tsage.h4
-rw-r--r--engines/tucker/tucker.h4
-rw-r--r--engines/voyeur/detection.cpp2
-rw-r--r--engines/voyeur/files.h8
-rw-r--r--engines/wage/debugger.cpp2
-rw-r--r--engines/wage/design.cpp63
-rw-r--r--engines/wage/design.h33
-rw-r--r--engines/wage/dialog.cpp13
-rw-r--r--engines/wage/dialog.h2
-rw-r--r--engines/wage/entities.cpp25
-rw-r--r--engines/wage/entities.h6
-rw-r--r--engines/wage/gui-console.cpp169
-rw-r--r--engines/wage/gui.cpp652
-rw-r--r--engines/wage/gui.h68
-rw-r--r--engines/wage/macmenu.cpp (renamed from engines/wage/menu.cpp)358
-rw-r--r--engines/wage/macmenu.h (renamed from engines/wage/menu.h)62
-rw-r--r--engines/wage/macwindow.cpp202
-rw-r--r--engines/wage/macwindow.h85
-rw-r--r--engines/wage/macwindowmanager.cpp300
-rw-r--r--engines/wage/macwindowmanager.h72
-rw-r--r--engines/wage/module.mk2
-rw-r--r--engines/wage/wage.cpp25
-rw-r--r--engines/wage/wage.h10
-rw-r--r--engines/wage/world.cpp12
-rw-r--r--engines/wage/world.h4
-rw-r--r--engines/wintermute/base/base_engine.cpp2
-rw-r--r--engines/wintermute/base/sound/base_sound_manager.cpp15
-rw-r--r--engines/wintermute/detection.cpp2
-rw-r--r--engines/wintermute/ui/ui_window.cpp11
-rw-r--r--engines/wintermute/wintermute.h4
383 files changed, 42144 insertions, 2133 deletions
diff --git a/engines/access/access.cpp b/engines/access/access.cpp
index c12761af4a..6f91bd76dd 100644
--- a/engines/access/access.cpp
+++ b/engines/access/access.cpp
@@ -244,7 +244,7 @@ void AccessEngine::freeCells() {
}
}
-void AccessEngine::speakText(ASurface *s, const Common::String &msg) {
+void AccessEngine::speakText(BaseSurface *s, const Common::String &msg) {
Common::String lines = msg;
Common::String line;
int curPage = 0;
@@ -325,7 +325,7 @@ void AccessEngine::speakText(ASurface *s, const Common::String &msg) {
}
}
-void AccessEngine::printText(ASurface *s, const Common::String &msg) {
+void AccessEngine::printText(BaseSurface *s, const Common::String &msg) {
Common::String lines = msg;
Common::String line;
int width = 0;
diff --git a/engines/access/access.h b/engines/access/access.h
index 2ca4a3468e..972dd4c380 100644
--- a/engines/access/access.h
+++ b/engines/access/access.h
@@ -156,8 +156,8 @@ public:
MusicManager *_midi;
VideoPlayer *_video;
- ASurface *_destIn;
- ASurface *_current;
+ BaseSurface *_destIn;
+ BaseSurface *_current;
ASurface _buffer1;
ASurface _buffer2;
ASurface _vidBuf;
@@ -280,8 +280,8 @@ public:
/**
* Draw a string on a given surface and update text positioning
*/
- void printText(ASurface *s, const Common::String &msg);
- void speakText(ASurface *s, const Common::String &msg);
+ void printText(BaseSurface *s, const Common::String &msg);
+ void speakText(BaseSurface *s, const Common::String &msg);
/**
* Load a savegame
diff --git a/engines/access/amazon/amazon_game.cpp b/engines/access/amazon/amazon_game.cpp
index 0a671d23d2..8467d8b623 100644
--- a/engines/access/amazon/amazon_game.cpp
+++ b/engines/access/amazon/amazon_game.cpp
@@ -496,7 +496,7 @@ void AmazonEngine::drawHelp(const Common::String str) {
_files->loadScreen(95, 2);
if (_moreHelp == 1) {
- ASurface *oldDest = _destIn;
+ BaseSurface *oldDest = _destIn;
_destIn = _screen;
int oldClip = _screen->_clipHeight;
_screen->_clipHeight = 200;
diff --git a/engines/access/amazon/amazon_logic.cpp b/engines/access/amazon/amazon_logic.cpp
index e78f92cda7..08006fe1b7 100644
--- a/engines/access/amazon/amazon_logic.cpp
+++ b/engines/access/amazon/amazon_logic.cpp
@@ -185,16 +185,24 @@ void CampScene::mWhileDoOpen() {
_vm->_numAnimTimers = 0;
_vm->_images.clear();
- if (_vm->_conversation == 2) {
- // Cutscene at end of Chapter 6
- Resource *spriteData = _vm->_files->loadFile(28, 37);
- _vm->_objectsTable[28] = new SpriteResource(_vm, spriteData);
- delete spriteData;
-
- _vm->_animation->freeAnimationData();
- animResource = _vm->_files->loadFile(28, 38);
- _vm->_animation->loadAnimations(animResource);
- delete animResource;
+ if (_vm->isCD()) {
+ if (_vm->_conversation == 2) {
+ // Cutscene at end of Chapter 6
+ Resource *spriteData = _vm->_files->loadFile(28, 37);
+ _vm->_objectsTable[28] = new SpriteResource(_vm, spriteData);
+ delete spriteData;
+
+ _vm->_animation->freeAnimationData();
+ animResource = _vm->_files->loadFile(28, 38);
+ _vm->_animation->loadAnimations(animResource);
+ delete animResource;
+ }
+ } else {
+ _vm->freeCells();
+ _vm->_oldRects.clear();
+ _vm->_newRects.clear();
+ _vm->_numAnimTimers = 0;
+ _vm->_images.clear();
}
}
diff --git a/engines/access/asurface.cpp b/engines/access/asurface.cpp
index 2518ff6ad8..37f4c7082e 100644
--- a/engines/access/asurface.cpp
+++ b/engines/access/asurface.cpp
@@ -107,10 +107,11 @@ void ImageEntryList::addToList(ImageEntry &ie) {
/*------------------------------------------------------------------------*/
-int ASurface::_clipWidth;
-int ASurface::_clipHeight;
+int BaseSurface::_clipWidth;
+int BaseSurface::_clipHeight;
-ASurface::ASurface(): Graphics::ManagedSurface() {
+BaseSurface::BaseSurface(): Graphics::Screen(0, 0) {
+ free(); // Free the 0x0 surface allocated by Graphics::Screen
_leftSkip = _rightSkip = 0;
_topSkip = _bottomSkip = 0;
_lastBoundsX = _lastBoundsY = 0;
@@ -121,16 +122,16 @@ ASurface::ASurface(): Graphics::ManagedSurface() {
_maxChars = 0;
}
-ASurface::~ASurface() {
+BaseSurface::~BaseSurface() {
_savedBlock.free();
}
-void ASurface::clearBuffer() {
+void BaseSurface::clearBuffer() {
byte *pSrc = (byte *)getPixels();
Common::fill(pSrc, pSrc + w * h, 0);
}
-void ASurface::plotImage(SpriteResource *sprite, int frameNum, const Common::Point &pt) {
+void BaseSurface::plotImage(SpriteResource *sprite, int frameNum, const Common::Point &pt) {
SpriteFrame *frame = sprite->getFrame(frameNum);
Common::Rect r(pt.x, pt.y, pt.x + frame->w, pt.y + frame->h);
@@ -144,38 +145,38 @@ void ASurface::plotImage(SpriteResource *sprite, int frameNum, const Common::Poi
}
}
-void ASurface::copyBuffer(Graphics::ManagedSurface *src) {
+void BaseSurface::copyBuffer(Graphics::ManagedSurface *src) {
blitFrom(*src);
}
-void ASurface::plotF(SpriteFrame *frame, const Common::Point &pt) {
+void BaseSurface::plotF(SpriteFrame *frame, const Common::Point &pt) {
sPlotF(frame, Common::Rect(pt.x, pt.y, pt.x + frame->w, pt.y + frame->h));
}
-void ASurface::plotB(SpriteFrame *frame, const Common::Point &pt) {
+void BaseSurface::plotB(SpriteFrame *frame, const Common::Point &pt) {
sPlotB(frame, Common::Rect(pt.x, pt.y, pt.x + frame->w, pt.y + frame->h));
}
-void ASurface::sPlotF(SpriteFrame *frame, const Common::Rect &bounds) {
+void BaseSurface::sPlotF(SpriteFrame *frame, const Common::Rect &bounds) {
transBlitFrom(*frame, Common::Rect(0, 0, frame->w, frame->h), bounds, TRANSPARENCY, false);
}
-void ASurface::sPlotB(SpriteFrame *frame, const Common::Rect &bounds) {
+void BaseSurface::sPlotB(SpriteFrame *frame, const Common::Rect &bounds) {
transBlitFrom(*frame, Common::Rect(0, 0, frame->w, frame->h), bounds, TRANSPARENCY, true);
}
-void ASurface::copyBlock(ASurface *src, const Common::Rect &bounds) {
+void BaseSurface::copyBlock(BaseSurface *src, const Common::Rect &bounds) {
copyRectToSurface(*src, bounds.left, bounds.top, bounds);
}
-void ASurface::copyTo(ASurface *dest) {
+void BaseSurface::copyTo(BaseSurface *dest) {
if (dest->empty())
dest->create(this->w, this->h);
dest->blitFrom(*this);
}
-void ASurface::saveBlock(const Common::Rect &bounds) {
+void BaseSurface::saveBlock(const Common::Rect &bounds) {
_savedBounds = bounds;
_savedBounds.clip(Common::Rect(0, 0, this->w, this->h));
@@ -185,7 +186,7 @@ void ASurface::saveBlock(const Common::Rect &bounds) {
_savedBlock.copyRectToSurface(*this, 0, 0, _savedBounds);
}
-void ASurface::restoreBlock() {
+void BaseSurface::restoreBlock() {
if (!_savedBounds.isEmpty()) {
copyRectToSurface(_savedBlock, _savedBounds.left, _savedBounds.top,
Common::Rect(0, 0, _savedBlock.w, _savedBlock.h));
@@ -195,26 +196,26 @@ void ASurface::restoreBlock() {
}
}
-void ASurface::drawRect() {
+void BaseSurface::drawRect() {
Graphics::ManagedSurface::fillRect(Common::Rect(_orgX1, _orgY1, _orgX2, _orgY2), _lColor);
}
-void ASurface::drawLine(int x1, int y1, int x2, int y2, int col) {
+void BaseSurface::drawLine(int x1, int y1, int x2, int y2, int col) {
Graphics::ManagedSurface::drawLine(x1, y1, x2, y2, col);
}
-void ASurface::drawLine() {
+void BaseSurface::drawLine() {
Graphics::ManagedSurface::drawLine(_orgX1, _orgY1, _orgX2, _orgY1, _lColor);
}
-void ASurface::drawBox() {
+void BaseSurface::drawBox() {
Graphics::ManagedSurface::drawLine(_orgX1, _orgY1, _orgX2, _orgY1, _lColor);
Graphics::ManagedSurface::drawLine(_orgX1, _orgY2, _orgX2, _orgY2, _lColor);
Graphics::ManagedSurface::drawLine(_orgX2, _orgY1, _orgX2, _orgY1, _lColor);
Graphics::ManagedSurface::drawLine(_orgX2, _orgY2, _orgX2, _orgY2, _lColor);
}
-void ASurface::flipHorizontal(ASurface &dest) {
+void BaseSurface::flipHorizontal(BaseSurface &dest) {
dest.create(this->w, this->h);
for (int y = 0; y < h; ++y) {
const byte *pSrc = (const byte *)getBasePtr(this->w - 1, y);
@@ -225,27 +226,27 @@ void ASurface::flipHorizontal(ASurface &dest) {
}
}
-void ASurface::moveBufferLeft() {
+void BaseSurface::moveBufferLeft() {
byte *p = (byte *)getPixels();
Common::copy(p + TILE_WIDTH, p + (w * h), p);
}
-void ASurface::moveBufferRight() {
+void BaseSurface::moveBufferRight() {
byte *p = (byte *)getPixels();
Common::copy_backward(p, p + (pitch * h) - TILE_WIDTH, p + (pitch * h));
}
-void ASurface::moveBufferUp() {
+void BaseSurface::moveBufferUp() {
byte *p = (byte *)getPixels();
Common::copy(p + (pitch * TILE_HEIGHT), p + (pitch * h), p);
}
-void ASurface::moveBufferDown() {
+void BaseSurface::moveBufferDown() {
byte *p = (byte *)getPixels();
Common::copy_backward(p, p + (pitch * (h - TILE_HEIGHT)), p + (pitch * h));
}
-bool ASurface::clip(Common::Rect &r) {
+bool BaseSurface::clip(Common::Rect &r) {
int skip;
_leftSkip = _rightSkip = 0;
_topSkip = _bottomSkip = 0;
diff --git a/engines/access/asurface.h b/engines/access/asurface.h
index ec18ec09c3..64ddf3d0ee 100644
--- a/engines/access/asurface.h
+++ b/engines/access/asurface.h
@@ -27,7 +27,7 @@
#include "common/array.h"
#include "common/memstream.h"
#include "common/rect.h"
-#include "graphics/managed_surface.h"
+#include "graphics/screen.h"
#include "access/data.h"
namespace Access {
@@ -35,11 +35,16 @@ namespace Access {
class SpriteResource;
class SpriteFrame;
-class ASurface : virtual public Graphics::ManagedSurface {
+/**
+ * Base Access surface class. This derivces from Graphics::Screen
+ * because it has logic we'll need for our own Screen class that
+ * derives from this one
+ */
+class BaseSurface : virtual public Graphics::Screen {
private:
Graphics::Surface _savedBlock;
- void flipHorizontal(ASurface &dest);
+ void flipHorizontal(BaseSurface &dest);
protected:
Common::Rect _savedBounds;
public:
@@ -57,9 +62,9 @@ public:
public:
static int _clipWidth, _clipHeight;
public:
- ASurface();
+ BaseSurface();
- virtual ~ASurface();
+ virtual ~BaseSurface();
void clearBuffer();
@@ -85,7 +90,7 @@ public:
*/
void plotB(SpriteFrame *frame, const Common::Point &pt);
- virtual void copyBlock(ASurface *src, const Common::Rect &bounds);
+ virtual void copyBlock(BaseSurface *src, const Common::Rect &bounds);
virtual void restoreBlock();
@@ -99,7 +104,7 @@ public:
virtual void copyBuffer(Graphics::ManagedSurface *src);
- void copyTo(ASurface *dest);
+ void copyTo(BaseSurface *dest);
void saveBlock(const Common::Rect &bounds);
@@ -114,6 +119,17 @@ public:
bool clip(Common::Rect &r);
};
+class ASurface : public BaseSurface {
+protected:
+ /**
+ * Override the addDirtyRect from Graphics::Screen, since for standard
+ * surfaces we don't need dirty rects to be tracked
+ */
+ virtual void addDirtyRect(const Common::Rect &r) {}
+public:
+ ASurface() : BaseSurface() {}
+};
+
class SpriteFrame : public ASurface {
public:
SpriteFrame(AccessEngine *vm, Common::SeekableReadStream *stream, int frameSize);
diff --git a/engines/access/bubble_box.cpp b/engines/access/bubble_box.cpp
index ef32e96f59..29b58a3f1b 100644
--- a/engines/access/bubble_box.cpp
+++ b/engines/access/bubble_box.cpp
@@ -165,7 +165,7 @@ void BubbleBox::printBubble(const Common::String &msg) {
void BubbleBox::printBubble_v1(const Common::String &msg) {
drawBubble(_bubbles.size() - 1);
-
+
// Loop through drawing the lines
Common::String s = msg;
Common::String line;
@@ -228,7 +228,7 @@ void BubbleBox::drawBubble(int index) {
void BubbleBox::doBox(int item, int box) {
FontManager &fonts = _vm->_fonts;
- ASurface &screen = *_vm->_screen;
+ Screen &screen = *_vm->_screen;
_startItem = item;
_startBox = box;
@@ -369,7 +369,7 @@ void BubbleBox::displayBoxData() {
_vm->_screen->drawRect();
_vm->_events->showCursor();
}
-
+
_vm->_events->hideCursor();
int oldPStartY = _boxPStartY;
++_boxPStartY;
@@ -474,7 +474,7 @@ int BubbleBox::doBox_v1(int item, int box, int &btnSelected) {
--_vm->_screen->_orgX2;
--_vm->_screen->_orgY2;
_vm->_screen->_lColor = 0xF9;
-
+
// Draw the inner border
_vm->_screen->drawBox();
@@ -611,6 +611,7 @@ int BubbleBox::doBox_v1(int item, int box, int &btnSelected) {
_vm->_events->showCursor();
warning("TODO: pop values");
_vm->_screen->restoreScreen();
+ delete icons;
return retval_;
}
@@ -642,7 +643,9 @@ int BubbleBox::doBox_v1(int item, int box, int &btnSelected) {
}
}
}
-
+
+ delete icons;
+
_vm->_screen->restoreScreen();
_vm->_boxDataStart = _startItem;
_vm->_boxSelectYOld = -1;
@@ -732,7 +735,7 @@ int BubbleBox::doBox_v1(int item, int box, int &btnSelected) {
if (_type != TYPE_3)
continue;
-
+
if ((_vm->_events->_mousePos.x < tmpX) || (_vm->_events->_mousePos.x > tmpX + 144))
continue;
diff --git a/engines/access/char.cpp b/engines/access/char.cpp
index cbe1d5d3d9..f6d3033b1b 100644
--- a/engines/access/char.cpp
+++ b/engines/access/char.cpp
@@ -44,7 +44,7 @@ CharEntry::CharEntry(const byte *data, AccessEngine *vm) {
if (vm->getGameID() == GType_MartianMemorandum) {
int lastColor = s.readUint16LE();
_numColors = lastColor - _startColor;
- } else
+ } else
_numColors = s.readUint16LE();
// Load cells
@@ -131,6 +131,7 @@ void CharManager::loadChar(int charId) {
if (ce._animFile._fileNum != -1) {
Resource *data = _vm->_files->loadFile(ce._animFile);
_vm->_animation->loadAnimations(data);
+ delete data;
}
// Load script data
diff --git a/engines/access/detection.cpp b/engines/access/detection.cpp
index 2cd7e50f0f..368753f117 100644
--- a/engines/access/detection.cpp
+++ b/engines/access/detection.cpp
@@ -94,7 +94,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "Access Engine (c) 1989-1994 Access Software";
+ return "Access Engine (C) 1989-1994 Access Software";
}
virtual bool hasFeature(MetaEngineFeature f) const;
diff --git a/engines/access/font.cpp b/engines/access/font.cpp
index 6ae65e43f0..8e02f80769 100644
--- a/engines/access/font.cpp
+++ b/engines/access/font.cpp
@@ -139,7 +139,7 @@ bool Font::getLine(Common::String &s, int maxWidth, Common::String &line, int &w
return true;
}
-void Font::drawString(ASurface *s, const Common::String &msg, const Common::Point &pt) {
+void Font::drawString(BaseSurface *s, const Common::String &msg, const Common::Point &pt) {
Common::Point currPt = pt;
const char *msgP = msg.c_str();
@@ -149,7 +149,7 @@ void Font::drawString(ASurface *s, const Common::String &msg, const Common::Poin
}
}
-int Font::drawChar(ASurface *s, char c, Common::Point &pt) {
+int Font::drawChar(BaseSurface *s, char c, Common::Point &pt) {
Graphics::Surface &ch = _chars[c - ' '];
Graphics::Surface dest = s->getSubArea(Common::Rect(pt.x, pt.y, pt.x + ch.w, pt.y + ch.h));
diff --git a/engines/access/font.h b/engines/access/font.h
index 6a812051ca..9234078af2 100644
--- a/engines/access/font.h
+++ b/engines/access/font.h
@@ -78,12 +78,12 @@ public:
/**
* Draw a string on a given surface
*/
- void drawString(ASurface *s, const Common::String &msg, const Common::Point &pt);
+ void drawString(BaseSurface *s, const Common::String &msg, const Common::Point &pt);
/**
* Draw a character on a given surface
*/
- int drawChar(ASurface *s, char c, Common::Point &pt);
+ int drawChar(BaseSurface *s, char c, Common::Point &pt);
};
diff --git a/engines/access/inventory.cpp b/engines/access/inventory.cpp
index 0a962aa69a..e9874cd8d6 100644
--- a/engines/access/inventory.cpp
+++ b/engines/access/inventory.cpp
@@ -223,6 +223,7 @@ int InventoryManager::displayInv() {
else
_vm->_useItem = -1;
+ free(names);
free(inv);
return 0;
}
diff --git a/engines/access/room.cpp b/engines/access/room.cpp
index a7192d330f..a41de63bf6 100644
--- a/engines/access/room.cpp
+++ b/engines/access/room.cpp
@@ -142,7 +142,7 @@ void Room::takePicture() {
_vm->_player->_roomNumber = 7;
_vm->_room->_function = FN_CLEAR1;
return;
- } else if (result >= 0)
+ } else if (result >= 0)
_vm->_player->_move = (Direction)(result + 1);
_vm->_player->_scrollFlag = false;
@@ -715,6 +715,8 @@ void Room::executeCommand(int commandId) {
screen.plotImage(spr, _selectCommand + 2,
Common::Point(_rMouse[_selectCommand][0], (_vm->getGameID() == GType_MartianMemorandum) ? 184 : 176));
+ delete spr;
+
_vm->_screen->restoreScreen();
_vm->_boxSelect = true;
}
diff --git a/engines/access/screen.cpp b/engines/access/screen.cpp
index 9700640b71..2d29ad0718 100644
--- a/engines/access/screen.cpp
+++ b/engines/access/screen.cpp
@@ -253,7 +253,7 @@ void Screen::restoreScreen() {
_screenYOff = _screenSave._screenYOff;
}
-void Screen::copyBlock(ASurface *src, const Common::Rect &bounds) {
+void Screen::copyBlock(BaseSurface *src, const Common::Rect &bounds) {
Common::Rect destBounds = bounds;
destBounds.translate(_windowXAdd, _windowYAdd + _screenYOff);
@@ -264,22 +264,22 @@ void Screen::copyBlock(ASurface *src, const Common::Rect &bounds) {
void Screen::restoreBlock() {
if (!_savedBounds.isEmpty())
addDirtyRect(_savedBounds);
- ASurface::restoreBlock();
+ BaseSurface::restoreBlock();
}
void Screen::drawRect() {
addDirtyRect(Common::Rect(_orgX1, _orgY1, _orgX2, _orgY2));
- ASurface::drawRect();
+ BaseSurface::drawRect();
}
void Screen::drawBox() {
addDirtyRect(Common::Rect(_orgX1, _orgY1, _orgX2, _orgY2));
- ASurface::drawBox();
+ BaseSurface::drawBox();
}
void Screen::copyBuffer(Graphics::ManagedSurface *src) {
addDirtyRect(Common::Rect(0, 0, src->w, src->h));
- ASurface::copyBuffer(src);
+ BaseSurface::copyBuffer(src);
}
void Screen::setPaletteCycle(int startCycle, int endCycle, int timer) {
diff --git a/engines/access/screen.h b/engines/access/screen.h
index a022741f91..1c1932511d 100644
--- a/engines/access/screen.h
+++ b/engines/access/screen.h
@@ -45,7 +45,7 @@ struct ScreenSave {
int _screenYOff;
};
-class Screen : public virtual ASurface, public virtual Graphics::Screen {
+class Screen : public BaseSurface {
private:
AccessEngine *_vm;
byte _tempPalette[PALETTE_SIZE];
@@ -86,7 +86,7 @@ public:
*/
virtual void update();
- virtual void copyBlock(ASurface *src, const Common::Rect &bounds);
+ virtual void copyBlock(BaseSurface *src, const Common::Rect &bounds);
virtual void restoreBlock();
diff --git a/engines/access/video.cpp b/engines/access/video.cpp
index e3ff457c3b..22842a5855 100644
--- a/engines/access/video.cpp
+++ b/engines/access/video.cpp
@@ -48,7 +48,7 @@ VideoPlayer::~VideoPlayer() {
closeVideo();
}
-void VideoPlayer::setVideo(ASurface *vidSurface, const Common::Point &pt, int rate) {
+void VideoPlayer::setVideo(BaseSurface *vidSurface, const Common::Point &pt, int rate) {
_vidSurface = vidSurface;
vidSurface->_orgX1 = pt.x;
vidSurface->_orgY1 = pt.y;
@@ -87,14 +87,14 @@ void VideoPlayer::setVideo(ASurface *vidSurface, const Common::Point &pt, int ra
_videoEnd = false;
}
-void VideoPlayer::setVideo(ASurface *vidSurface, const Common::Point &pt, const Common::String filename, int rate) {
+void VideoPlayer::setVideo(BaseSurface *vidSurface, const Common::Point &pt, const Common::String filename, int rate) {
// Open up video stream
_videoData = _vm->_files->loadFile(filename);
setVideo(vidSurface, pt, rate);
}
-void VideoPlayer::setVideo(ASurface *vidSurface, const Common::Point &pt, const FileIdent &videoFile, int rate) {
+void VideoPlayer::setVideo(BaseSurface *vidSurface, const Common::Point &pt, const FileIdent &videoFile, int rate) {
// Open up video stream
_videoData = _vm->_files->loadFile(videoFile);
diff --git a/engines/access/video.h b/engines/access/video.h
index 83c8995d3e..65dff3ebea 100644
--- a/engines/access/video.h
+++ b/engines/access/video.h
@@ -40,7 +40,7 @@ class VideoPlayer : public Manager {
VideoFlags _flags;
};
private:
- ASurface *_vidSurface;
+ BaseSurface *_vidSurface;
Resource *_videoData;
VideoHeader _header;
byte *_startCoord;
@@ -51,7 +51,7 @@ private:
Common::Rect _videoBounds;
void getFrame();
- void setVideo(ASurface *vidSurface, const Common::Point &pt, int rate);
+ void setVideo(BaseSurface *vidSurface, const Common::Point &pt, int rate);
public:
int _videoFrame;
bool _soundFlag;
@@ -64,8 +64,8 @@ public:
/**
* Start up a video
*/
- void setVideo(ASurface *vidSurface, const Common::Point &pt, const FileIdent &videoFile, int rate);
- void setVideo(ASurface *vidSurface, const Common::Point &pt, const Common::String filename, int rate);
+ void setVideo(BaseSurface *vidSurface, const Common::Point &pt, const FileIdent &videoFile, int rate);
+ void setVideo(BaseSurface *vidSurface, const Common::Point &pt, const Common::String filename, int rate);
/**
* Decodes a frame of the video
diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp
index e566ad12f6..60c8d1f3ef 100644
--- a/engines/agi/agi.cpp
+++ b/engines/agi/agi.cpp
@@ -403,6 +403,11 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas
_lastSaveTime = 0;
+ _playTimeInSecondsAdjust = 0;
+ _lastUsedPlayTimeInCycles = 0;
+ _lastUsedPlayTimeInSeconds = 0;
+ _passedPlayTimeCycles = 0;
+
memset(_keyQueue, 0, sizeof(_keyQueue));
_console = nullptr;
@@ -418,6 +423,9 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas
_inventory = nullptr;
_keyHoldMode = false;
+
+ _artificialDelayCurrentRoom = 0;
+ _artificialDelayCurrentPicture = 0;
}
void AgiEngine::initialize() {
diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 1baf0d912f..79d05c4b1d 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef AGI_H
-#define AGI_H
+#ifndef AGI_AGI_H
+#define AGI_AGI_H
#include "common/scummsys.h"
#include "common/error.h"
@@ -991,4 +991,4 @@ private:
} // End of namespace Agi
-#endif /* AGI_H */
+#endif /* AGI_AGI_H */
diff --git a/engines/agi/global.cpp b/engines/agi/global.cpp
index 23256f27fb..6f83f02a4e 100644
--- a/engines/agi/global.cpp
+++ b/engines/agi/global.cpp
@@ -21,6 +21,7 @@
*/
#include "common/config-manager.h"
+#include "audio/mixer.h"
#include "agi/agi.h"
#include "agi/graphics.h"
diff --git a/engines/agi/graphics.cpp b/engines/agi/graphics.cpp
index 6d3563a451..24cd4f43d3 100644
--- a/engines/agi/graphics.cpp
+++ b/engines/agi/graphics.cpp
@@ -605,7 +605,7 @@ void GfxMgr::render_BlockEGA(int16 x, int16 y, int16 width, int16 height, bool c
switch (_upscaledHires) {
case DISPLAY_UPSCALED_640x400:
- offsetDisplay += _displayScreenWidth;;
+ offsetDisplay += _displayScreenWidth;
break;
default:
break;
@@ -660,7 +660,7 @@ void GfxMgr::render_BlockCGA(int16 x, int16 y, int16 width, int16 height, bool c
switch (_upscaledHires) {
case DISPLAY_UPSCALED_640x400:
- offsetDisplay += _displayScreenWidth;;
+ offsetDisplay += _displayScreenWidth;
break;
default:
break;
@@ -743,7 +743,7 @@ void GfxMgr::render_BlockHercules(int16 x, int16 y, int16 width, int16 height, b
offsetVisual += SCRIPT_WIDTH - width;
offsetDisplay += _displayScreenWidth - displayWidth;
- offsetDisplay += _displayScreenWidth;;
+ offsetDisplay += _displayScreenWidth;
remainingHeight--;
}
@@ -1178,13 +1178,17 @@ void GfxMgr::drawCharacterOnDisplay(int16 x, int16 y, const byte character, byte
#define SHAKE_HORIZONTAL_PIXELS 4
// Sierra used some EGA port trickery to do it, we have to do it by copying pixels around
+//
+// Shaking locations:
+// - Fanmade "Enclosure" right during the intro
+// - Space Quest 2 almost right at the start when getting captured (after walking into the space ship)
void GfxMgr::shakeScreen(int16 repeatCount) {
int shakeNr, shakeCount;
uint8 *blackSpace;
int16 shakeHorizontalPixels = SHAKE_HORIZONTAL_PIXELS * (2 + _displayWidthMulAdjust);
int16 shakeVerticalPixels = SHAKE_VERTICAL_PIXELS * (1 + _displayHeightMulAdjust);
- if ((blackSpace = (uint8 *)calloc(shakeVerticalPixels * _displayScreenWidth, 1)) == NULL)
+ if ((blackSpace = (uint8 *)calloc(shakeHorizontalPixels * _displayScreenWidth, 1)) == NULL)
return;
shakeCount = repeatCount * 8; // effectively 4 shakes per repeat
diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index fed07ea986..8a62fce86c 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -662,7 +662,7 @@ void cmdWordToString(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
uint16 stringNr = parameter[0];
uint16 wordNr = parameter[1];
- strcpy(state->strings[stringNr], state->_vm->_words->getEgoWord(wordNr));
+ Common::strlcpy(state->strings[stringNr], state->_vm->_words->getEgoWord(wordNr), MAX_STRINGLEN);
}
void cmdOpenDialogue(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
@@ -2014,7 +2014,7 @@ void cmdGetString(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
// copy string to destination
// TODO: not sure if set all the time or only when ENTER is pressed
- strcpy(&state->_vm->_game.strings[stringDestNr][0], (char *)textMgr->_inputString);
+ Common::strlcpy(&state->_vm->_game.strings[stringDestNr][0], (char *)textMgr->_inputString, MAX_STRINGLEN);
textMgr->charPos_Pop();
@@ -2102,7 +2102,7 @@ void cmdSetString(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
// CM: to avoid crash in Groza (str = 150)
if (stringNr > MAX_STRINGS)
return;
- strcpy(state->strings[stringNr], state->_curLogic->texts[textNr]);
+ Common::strlcpy(state->strings[stringNr], state->_curLogic->texts[textNr], MAX_STRINGLEN);
}
void cmdDisplay(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
diff --git a/engines/agi/op_test.cpp b/engines/agi/op_test.cpp
index 4b215edc63..4505668fd1 100644
--- a/engines/agi/op_test.cpp
+++ b/engines/agi/op_test.cpp
@@ -231,8 +231,8 @@ uint8 AgiEngine::testCompareStrings(uint8 s1, uint8 s2) {
char ms2[MAX_STRINGLEN];
int j, k, l;
- strcpy(ms1, _game.strings[s1]);
- strcpy(ms2, _game.strings[s2]);
+ Common::strlcpy(ms1, _game.strings[s1], MAX_STRINGLEN);
+ Common::strlcpy(ms2, _game.strings[s2], MAX_STRINGLEN);
l = strlen(ms1);
for (k = 0, j = 0; k < l; k++) {
diff --git a/engines/agi/preagi.cpp b/engines/agi/preagi.cpp
index 7e2e65a3eb..f8630db0b6 100644
--- a/engines/agi/preagi.cpp
+++ b/engines/agi/preagi.cpp
@@ -20,6 +20,7 @@
*
*/
+#include "audio/mixer.h"
#include "audio/softsynth/pcspk.h"
#include "common/debug-channels.h"
@@ -50,6 +51,8 @@ PreAgiEngine::PreAgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) :
memset(&_game, 0, sizeof(struct AgiGame));
memset(&_debug, 0, sizeof(struct AgiDebug));
memset(&_mouse, 0, sizeof(struct Mouse));
+
+ _speakerHandle = new Audio::SoundHandle();
}
void PreAgiEngine::initialize() {
@@ -74,7 +77,7 @@ void PreAgiEngine::initialize() {
_gfx->initVideo();
_speakerStream = new Audio::PCSpeaker(_mixer->getOutputRate());
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &_speakerHandle,
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, _speakerHandle,
_speakerStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
debugC(2, kDebugLevelMain, "Detect game");
@@ -89,8 +92,9 @@ void PreAgiEngine::initialize() {
}
PreAgiEngine::~PreAgiEngine() {
- _mixer->stopHandle(_speakerHandle);
+ _mixer->stopHandle(*_speakerHandle);
delete _speakerStream;
+ delete _speakerHandle;
delete _picture;
delete _gfx;
diff --git a/engines/agi/preagi.h b/engines/agi/preagi.h
index d6026a5d4d..6950aa30cd 100644
--- a/engines/agi/preagi.h
+++ b/engines/agi/preagi.h
@@ -26,6 +26,7 @@
#include "agi/agi.h"
namespace Audio {
+class SoundHandle;
class PCSpeaker;
}
@@ -110,7 +111,7 @@ private:
int _defaultColor;
Audio::PCSpeaker *_speakerStream;
- Audio::SoundHandle _speakerHandle;
+ Audio::SoundHandle *_speakerHandle;
};
} // End of namespace Agi
diff --git a/engines/agi/preagi_mickey.cpp b/engines/agi/preagi_mickey.cpp
index 620d5e0baf..e1545cdb68 100644
--- a/engines/agi/preagi_mickey.cpp
+++ b/engines/agi/preagi_mickey.cpp
@@ -1205,7 +1205,7 @@ void MickeyEngine::printStory() {
clearScreen(IDA_DEFAULT);
for (iRow = 0; iRow < 25; iRow++) {
- strcpy(szLine, buffer + pBuf);
+ Common::strlcpy(szLine, buffer + pBuf, 41);
drawStr(iRow, 0, IDA_DEFAULT, szLine);
pBuf += strlen(szLine) + 1;
}
@@ -1213,7 +1213,7 @@ void MickeyEngine::printStory() {
clearScreen(IDA_DEFAULT);
for (iRow = 0; iRow < 21; iRow++) {
- strcpy(szLine, buffer + pBuf);
+ Common::strlcpy(szLine, buffer + pBuf, 41);
drawStr(iRow, 0, IDA_DEFAULT, szLine);
pBuf += strlen(szLine) + 1;
}
diff --git a/engines/agi/preagi_winnie.cpp b/engines/agi/preagi_winnie.cpp
index 87ac7c19c6..8fb9daca5e 100644
--- a/engines/agi/preagi_winnie.cpp
+++ b/engines/agi/preagi_winnie.cpp
@@ -292,7 +292,7 @@ int WinnieEngine::parser(int pc, int index, uint8 *buffer) {
}
// extract menu string
- strcpy(szMenu, (char *)(buffer + pc));
+ Common::strlcpy(szMenu, (char *)(buffer + pc), 121);
XOR80(szMenu);
break;
default:
diff --git a/engines/agi/saveload.cpp b/engines/agi/saveload.cpp
index 0658609cd0..fc4aea3169 100644
--- a/engines/agi/saveload.cpp
+++ b/engines/agi/saveload.cpp
@@ -118,7 +118,7 @@ int AgiEngine::saveGame(const Common::String &fileName, const Common::String &de
out->writeByte(2); // was _game.state, 2 = STATE_RUNNING
- strcpy(gameIDstring, _game.id);
+ Common::strlcpy(gameIDstring, _game.id, 8);
out->write(gameIDstring, 8);
debugC(5, kDebugLevelMain | kDebugLevelSavegame, "Writing game id (%s, %s)", gameIDstring, _game.id);
@@ -689,9 +689,6 @@ int AgiEngine::loadGame(const Common::String &fileName, bool checkId) {
}
}
}
- for (i = vtEntries; i < SCREENOBJECTS_MAX; i++) {
- memset(&_game.screenObjTable[i], 0, sizeof(ScreenObjEntry));
- }
// Fix some pointers in screenObjTable
@@ -832,7 +829,7 @@ SavedGameSlotIdArray AgiEngine::getSavegameSlotIds() {
filenames = _saveFileMan->listSavefiles(_targetName + ".###");
Common::StringArray::iterator it;
- Common::StringArray::iterator end = filenames.end();;
+ Common::StringArray::iterator end = filenames.end();
// convert to lower-case, just to be sure
for (it = filenames.begin(); it != end; it++) {
diff --git a/engines/agi/sound.cpp b/engines/agi/sound.cpp
index edf17960ad..8834068ace 100644
--- a/engines/agi/sound.cpp
+++ b/engines/agi/sound.cpp
@@ -29,9 +29,19 @@
#include "agi/sound_pcjr.h"
#include "common/textconsole.h"
+#include "audio/mixer.h"
namespace Agi {
+SoundGen::SoundGen(AgiBase *vm, Audio::Mixer *pMixer) : _vm(vm), _mixer(pMixer) {
+ _sampleRate = pMixer->getOutputRate();
+ _soundHandle = new Audio::SoundHandle();
+}
+
+SoundGen::~SoundGen() {
+ delete _soundHandle;
+}
+
//
// TODO: add support for variable sampling rate in the output device
//
diff --git a/engines/agi/sound.h b/engines/agi/sound.h
index 4b668e8cf2..8aa7a5d1df 100644
--- a/engines/agi/sound.h
+++ b/engines/agi/sound.h
@@ -23,7 +23,10 @@
#ifndef AGI_SOUND_H
#define AGI_SOUND_H
-#include "audio/mixer.h"
+namespace Audio {
+class Mixer;
+class SoundHandle;
+}
namespace Agi {
@@ -71,11 +74,8 @@ class SoundMgr;
class SoundGen {
public:
- SoundGen(AgiBase *vm, Audio::Mixer *pMixer) : _vm(vm), _mixer(pMixer) {
- _sampleRate = pMixer->getOutputRate();
- }
-
- virtual ~SoundGen() {}
+ SoundGen(AgiBase *vm, Audio::Mixer *pMixer);
+ virtual ~SoundGen();
virtual void play(int resnum) = 0;
virtual void stop(void) = 0;
@@ -83,7 +83,7 @@ public:
AgiBase *_vm;
Audio::Mixer *_mixer;
- Audio::SoundHandle _soundHandle;
+ Audio::SoundHandle *_soundHandle;
uint32 _sampleRate;
};
diff --git a/engines/agi/sound_2gs.cpp b/engines/agi/sound_2gs.cpp
index b1bcee3920..4992b6516c 100644
--- a/engines/agi/sound_2gs.cpp
+++ b/engines/agi/sound_2gs.cpp
@@ -27,6 +27,7 @@
#include "common/memstream.h"
#include "common/str-array.h"
#include "common/textconsole.h"
+#include "audio/mixer.h"
#include "agi/agi.h"
#include "agi/sound_2gs.h"
@@ -55,11 +56,11 @@ SoundGen2GS::SoundGen2GS(AgiBase *vm, Audio::Mixer *pMixer) : SoundGen(vm, pMixe
// Load instruments
_disableMidi = !loadInstruments();
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+ _mixer->playStream(Audio::Mixer::kMusicSoundType, _soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
}
SoundGen2GS::~SoundGen2GS() {
- _mixer->stopHandle(_soundHandle);
+ _mixer->stopHandle(*_soundHandle);
delete[] _wavetable;
delete[] _out;
}
diff --git a/engines/agi/sound_pcjr.cpp b/engines/agi/sound_pcjr.cpp
index 9d556e048a..0a0c456e14 100644
--- a/engines/agi/sound_pcjr.cpp
+++ b/engines/agi/sound_pcjr.cpp
@@ -54,6 +54,7 @@
*
*/
+#include "audio/mixer.h"
#include "agi/agi.h"
#include "agi/sound.h"
#include "agi/sound_pcjr.h"
@@ -123,7 +124,7 @@ SoundGenPCJr::SoundGenPCJr(AgiBase *vm, Audio::Mixer *pMixer) : SoundGen(vm, pMi
memset(_channel, 0, sizeof(_channel));
memset(_tchannel, 0, sizeof(_tchannel));
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+ _mixer->playStream(Audio::Mixer::kMusicSoundType, _soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
_v1data = NULL;
_v1size = 0;
@@ -132,7 +133,7 @@ SoundGenPCJr::SoundGenPCJr(AgiBase *vm, Audio::Mixer *pMixer) : SoundGen(vm, pMi
SoundGenPCJr::~SoundGenPCJr() {
free(_chanData);
- _mixer->stopHandle(_soundHandle);
+ _mixer->stopHandle(*_soundHandle);
}
void SoundGenPCJr::play(int resnum) {
diff --git a/engines/agi/sound_sarien.cpp b/engines/agi/sound_sarien.cpp
index 939c3d2c77..1b3542b89c 100644
--- a/engines/agi/sound_sarien.cpp
+++ b/engines/agi/sound_sarien.cpp
@@ -21,6 +21,7 @@
*/
#include "common/random.h"
+#include "audio/mixer.h"
#include "agi/agi.h"
@@ -92,11 +93,11 @@ SoundGenSarien::SoundGenSarien(AgiBase *vm, Audio::Mixer *pMixer) : SoundGen(vm,
debug(0, "Initializing sound: envelopes disabled");
}
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+ _mixer->playStream(Audio::Mixer::kMusicSoundType, _soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
}
SoundGenSarien::~SoundGenSarien() {
- _mixer->stopHandle(_soundHandle);
+ _mixer->stopHandle(*_soundHandle);
free(_sndBuffer);
}
diff --git a/engines/agi/systemui.cpp b/engines/agi/systemui.cpp
index aeb1ded4a2..1f26267ad6 100644
--- a/engines/agi/systemui.cpp
+++ b/engines/agi/systemui.cpp
@@ -585,7 +585,7 @@ void SystemUI::readSavedGameSlots(bool filterNonexistant, bool withAutoSaveSlot)
slotIdArray.push_back(SYSTEMUI_SAVEDGAME_MAXIMUM_SLOTS); // so that the loop will process all slots
SavedGameSlotIdArray::iterator it;
- SavedGameSlotIdArray::iterator end = slotIdArray.end();;
+ SavedGameSlotIdArray::iterator end = slotIdArray.end();
for (it = slotIdArray.begin(); it != end; it++) {
curSlotId = *it;
diff --git a/engines/agi/text.cpp b/engines/agi/text.cpp
index 110ba10632..274a654547 100644
--- a/engines/agi/text.cpp
+++ b/engines/agi/text.cpp
@@ -457,7 +457,7 @@ void TextMgr::drawMessageBox(const char *textPtr, int16 forcedHeight, int16 want
// Caller wants to force specified width/height? set it
if (forcedHeight)
_messageState.textSize_Height = forcedHeight;
-
+
if (forcedWidth) {
if (wantedWidth)
_messageState.textSize_Width = wantedWidth;
@@ -1207,7 +1207,7 @@ char *TextMgr::stringPrintf(const char *originalText) {
}
assert(resultString.size() < sizeof(resultPrintfBuffer));
- strcpy(resultPrintfBuffer, resultString.c_str());
+ Common::strlcpy(resultPrintfBuffer, resultString.c_str(), 2000);
return resultPrintfBuffer;
}
diff --git a/engines/agos/animation.cpp b/engines/agos/animation.cpp
index 83682d567b..123e5805dd 100644
--- a/engines/agos/animation.cpp
+++ b/engines/agos/animation.cpp
@@ -57,6 +57,7 @@ MoviePlayer::MoviePlayer(AGOSEngine_Feeble *vm)
memset(baseName, 0, sizeof(baseName));
_ticks = 0;
+ _bgSoundStream = nullptr;
}
MoviePlayer::~MoviePlayer() {
diff --git a/engines/agos/detection_tables.h b/engines/agos/detection_tables.h
index 793d4081cf..90e5a84829 100644
--- a/engines/agos/detection_tables.h
+++ b/engines/agos/detection_tables.h
@@ -2251,6 +2251,31 @@ static const AGOSGameDescription gameDescriptions[] = {
GF_TALKIE
},
+ // Simon the Sorcerer 2 - Russian DOS CD
+ {
+ {
+ "simon2",
+ "CD",
+
+ {
+ { "gsptr30", GAME_BASEFILE, "e26d162e573587f4601b88701292212c", 58851},
+ { "icon.dat", GAME_ICONFILE, "72096a62d36e6034ea9fecc13b2dbdab", 18089},
+ { "simon2.gme", GAME_GMEFILE, "9c535d403966750ae98bdaf698375a38", 19687892},
+ { "stripped.txt", GAME_STRFILE, "e229f84d46fa83f99b4a7115679f3fb6", 171},
+ { "tbllist", GAME_TBLFILE, "2082f8d02075e590300478853a91ffd9", 513},
+ { NULL, 0, NULL, 0}
+ },
+ Common::RU_RUS,
+ Common::kPlatformDOS,
+ ADGF_CD,
+ GUIO0()
+ },
+
+ GType_SIMON2,
+ GID_SIMON2,
+ GF_TALKIE
+ },
+
// Simon the Sorcerer 2 - Czech Windows CD
{
{
diff --git a/engines/agos/feeble.cpp b/engines/agos/feeble.cpp
index bfd11fa8ea..91772621ad 100644
--- a/engines/agos/feeble.cpp
+++ b/engines/agos/feeble.cpp
@@ -39,6 +39,7 @@ AGOSEngine_Feeble::AGOSEngine_Feeble(OSystem *system, const AGOSGameDescription
_moviePlayer = 0;
_vgaCurSpritePriority = 0;
_mouseToggle = false;
+ _opcodesFeeble = nullptr;
}
AGOSEngine_Feeble::~AGOSEngine_Feeble() {
diff --git a/engines/agos/saveload.cpp b/engines/agos/saveload.cpp
index 66a7fa90b3..1ba0f56353 100644
--- a/engines/agos/saveload.cpp
+++ b/engines/agos/saveload.cpp
@@ -494,7 +494,7 @@ void AGOSEngine_Elvira2::userGame(bool load) {
i = userGameGetKey(&b, 128);
if (b) {
- if (i <= 223) {
+ if (i <= 23) {
if (!confirmOverWrite(window)) {
listSaveGames();
continue;
diff --git a/engines/agos/string.cpp b/engines/agos/string.cpp
index 4f6c62c48a..cc443f2f50 100644
--- a/engines/agos/string.cpp
+++ b/engines/agos/string.cpp
@@ -126,14 +126,14 @@ const byte *AGOSEngine::getStringPtrByID(uint16 stringId, bool upperCase) {
_awaitTwoByteToken = 0;
uncompressText(ptr);
_textBuffer[_textCount] = 0;
- strcpy((char *)dst, (const char *)_textBuffer);
+ Common::strlcpy((char *)dst, (const char *)_textBuffer, 180);
} else {
if (stringId < 0x8000) {
stringPtr = _stringTabPtr[stringId];
} else {
stringPtr = getLocalStringByID(stringId);
}
- strcpy((char *)dst, (const char *)stringPtr);
+ Common::strlcpy((char *)dst, (const char *)stringPtr, 180);
}
// WORKAROUND bug #1538873: The French version of Simon 1 and the
@@ -796,7 +796,7 @@ void AGOSEngine_Feeble::printInteractText(uint16 num, const char *string) {
if (*string2 == 0x00) {
if (w == 0xFFFF)
w = pixels;
- strcpy(convertedString2, string);
+ Common::strlcpy(convertedString2, string, 320);
break;
}
while (*string2 != ' ') {
diff --git a/engines/agos/string_pn.cpp b/engines/agos/string_pn.cpp
index 7a364f3ea9..06c8bbd98e 100644
--- a/engines/agos/string_pn.cpp
+++ b/engines/agos/string_pn.cpp
@@ -114,7 +114,7 @@ void AGOSEngine_PN::getObjectName(char *v, uint16 x) {
}
void AGOSEngine_PN::pcl(const char *s) {
- strcat(_sb, s);
+ Common::strlcat(_sb, s, 80);
if (strchr(s, '\n') == 0) {
for (char *str = _sb; *str; str++)
windowPutChar(_windowArray[_curWindow], *str);
diff --git a/engines/cge/cge.h b/engines/cge/cge.h
index c43358f252..d3f8a93c1d 100644
--- a/engines/cge/cge.h
+++ b/engines/cge/cge.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef CGE_H
-#define CGE_H
+#ifndef CGE_CGE_H
+#define CGE_CGE_H
#include "common/random.h"
#include "common/savefile.h"
diff --git a/engines/cge/detection.cpp b/engines/cge/detection.cpp
index 52168dc934..82d27f8d54 100644
--- a/engines/cge/detection.cpp
+++ b/engines/cge/detection.cpp
@@ -123,7 +123,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "Soltys (c) 1994-1996 L.K. Avalon";
+ return "Soltys (C) 1994-1996 L.K. Avalon";
}
virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
diff --git a/engines/cge2/cge2.h b/engines/cge2/cge2.h
index fbe4cb3abc..18f919b5eb 100644
--- a/engines/cge2/cge2.h
+++ b/engines/cge2/cge2.h
@@ -25,8 +25,8 @@
* Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
*/
-#ifndef CGE2_H
-#define CGE2_H
+#ifndef CGE2_CGE2_H
+#define CGE2_CGE2_H
#include "common/random.h"
#include "common/savefile.h"
@@ -335,4 +335,4 @@ public:
} // End of namespace CGE2
-#endif // CGE2_H
+#endif // CGE2_CGE2_H
diff --git a/engines/cge2/detection.cpp b/engines/cge2/detection.cpp
index 01119bb1fd..2b84d167c7 100644
--- a/engines/cge2/detection.cpp
+++ b/engines/cge2/detection.cpp
@@ -119,7 +119,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "Sfinx (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon";
+ return "Sfinx (C) 1994-1997 Janus B. Wisniewski and L.K. Avalon";
}
virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
diff --git a/engines/cge2/vga13h.cpp b/engines/cge2/vga13h.cpp
index 54f5c00d93..8b0d8b6c77 100644
--- a/engines/cge2/vga13h.cpp
+++ b/engines/cge2/vga13h.cpp
@@ -952,8 +952,9 @@ uint8 Vga::closest(Dac *pal, const uint8 colR, const uint8 colG, const uint8 col
}
uint8 Vga::closest(Dac *pal, Dac x) {
- int exp = (sizeof(long) * 8 - 1);
- long D = (1 << exp) - 1; // Maximum value of long.
+ long D = 0;
+ D = ~D;
+ D = (unsigned long)D >> 1; // Maximum value of long.
long R = x._r;
long G = x._g;
long B = x._b;
diff --git a/engines/cine/cine.h b/engines/cine/cine.h
index 7c0191b4d9..615e36d598 100644
--- a/engines/cine/cine.h
+++ b/engines/cine/cine.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef CINE_H
-#define CINE_H
+#ifndef CINE_CINE_H
+#define CINE_CINE_H
#include "common/scummsys.h"
diff --git a/engines/composer/composer.h b/engines/composer/composer.h
index 234494e655..d1a85e975a 100644
--- a/engines/composer/composer.h
+++ b/engines/composer/composer.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef COMPOSER_H
-#define COMPOSER_H
+#ifndef COMPOSER_COMPOSER_H
+#define COMPOSER_COMPOSER_H
#include "common/ini-file.h"
#include "common/random.h"
diff --git a/engines/cruise/cell.cpp b/engines/cruise/cell.cpp
index b7cef41764..46539463b8 100644
--- a/engines/cruise/cell.cpp
+++ b/engines/cruise/cell.cpp
@@ -129,15 +129,12 @@ void createTextObject(cellStruct *pObject, int overlayIdx, int messageIdx, int x
cellStruct *pNewElement;
cellStruct *si = pObject->next;
- cellStruct *var_2;
while (si) {
pObject = si;
si = si->next;
}
- var_2 = si;
-
pNewElement = (cellStruct *) MemAlloc(sizeof(cellStruct));
memset(pNewElement, 0, sizeof(cellStruct));
@@ -157,11 +154,7 @@ void createTextObject(cellStruct *pObject, int overlayIdx, int messageIdx, int x
pNewElement->parentOverlay = parentOvl;
pNewElement->gfxPtr = NULL;
- if (var_2) {
- cx = var_2;
- } else {
- cx = savePObject;
- }
+ cx = savePObject;
pNewElement->prev = cx->prev;
cx->prev = pNewElement;
diff --git a/engines/cruise/ctp.cpp b/engines/cruise/ctp.cpp
index 9515b552e1..4458e39e91 100644
--- a/engines/cruise/ctp.cpp
+++ b/engines/cruise/ctp.cpp
@@ -307,7 +307,7 @@ int initCt(const char *ctpName) {
MemFree(ptr);
if (ctpName != currentCtpName)
- strcpy(currentCtpName, ctpName);
+ Common::strlcpy(currentCtpName, ctpName, 40);
numberOfWalkboxes = segementSizeTable[6] / 2; // get the number of walkboxes
diff --git a/engines/cruise/dataLoader.cpp b/engines/cruise/dataLoader.cpp
index 7a1258dbde..2eff82bc61 100644
--- a/engines/cruise/dataLoader.cpp
+++ b/engines/cruise/dataLoader.cpp
@@ -249,12 +249,19 @@ int loadFile(const char* name, int idx, int destIdx) {
int numMaxEntriesInSet = getNumMaxEntiresInSet(ptr);
if (destIdx > numMaxEntriesInSet) {
+ MemFree(ptr);
return 0; // exit if limit is reached
}
- return loadSetEntry(name, ptr, destIdx, idx);
+ int res = loadSetEntry(name, ptr, destIdx, idx);
+ MemFree(ptr);
+
+ return res;
}
case type_FNT: {
- return loadFNTSub(ptr, idx);
+ int res = loadFNTSub(ptr, idx);
+ MemFree(ptr);
+
+ return res;
}
case type_SPL: {
// Sound file
diff --git a/engines/draci/draci.h b/engines/draci/draci.h
index 540c288d3d..90afdbcf60 100644
--- a/engines/draci/draci.h
+++ b/engines/draci/draci.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef DRACI_H
-#define DRACI_H
+#ifndef DRACI_DRACI_H
+#define DRACI_DRACI_H
#include "engines/engine.h"
#include "common/random.h"
@@ -126,4 +126,4 @@ static inline long scummvm_lround(double val) { return (long)floor(val + 0.5); }
} // End of namespace Draci
-#endif // DRACI_H
+#endif // DRACI_DRACI_H
diff --git a/engines/drascula/actors.cpp b/engines/drascula/actors.cpp
index a1f2c5386c..b459c4539b 100644
--- a/engines/drascula/actors.cpp
+++ b/engines/drascula/actors.cpp
@@ -196,10 +196,6 @@ void DrasculaEngine::moveCharacters() {
return;
}
}
-
- byte *srcSurface = extraSurface;
- if (currentChapter == 6 && _lang == kSpanish)
- srcSurface = tableSurface;
if (characterMoved == 0) {
curPos[0] = 0;
@@ -218,17 +214,17 @@ void DrasculaEngine::moveCharacters() {
curPos[1] = 0;
if (currentChapter == 2)
copyRect(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
- srcSurface, screenSurface);
+ extraSurface, screenSurface);
else
reduce_hare_chico(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
- factor_red[curY + curHeight], srcSurface, screenSurface);
+ factor_red[curY + curHeight], extraSurface, screenSurface);
} else if (trackProtagonist == 1) {
if (currentChapter == 2)
copyRect(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
- srcSurface, screenSurface);
+ extraSurface, screenSurface);
else
reduce_hare_chico(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
- factor_red[curY + curHeight], srcSurface, screenSurface);
+ factor_red[curY + curHeight], extraSurface, screenSurface);
} else if (trackProtagonist == 2) {
if (currentChapter == 2)
copyRect(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
@@ -260,17 +256,17 @@ void DrasculaEngine::moveCharacters() {
curPos[1] = 0;
if (currentChapter == 2)
copyRect(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
- srcSurface, screenSurface);
+ extraSurface, screenSurface);
else
reduce_hare_chico(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
- factor_red[curY + curHeight], srcSurface, screenSurface);
+ factor_red[curY + curHeight], extraSurface, screenSurface);
} else if (trackProtagonist == 1) {
if (currentChapter == 2)
copyRect(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
- srcSurface, screenSurface);
+ extraSurface, screenSurface);
else
reduce_hare_chico(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
- factor_red[curY + curHeight], srcSurface, screenSurface);
+ factor_red[curY + curHeight], extraSurface, screenSurface);
} else if (trackProtagonist == 2) {
if (currentChapter == 2)
copyRect(curPos[0], curPos[1], curPos[2], curPos[3], curPos[4], curPos[5],
diff --git a/engines/drascula/animation.cpp b/engines/drascula/animation.cpp
index 0ed2c61e3f..f672ad3b55 100644
--- a/engines/drascula/animation.cpp
+++ b/engines/drascula/animation.cpp
@@ -1612,7 +1612,7 @@ void DrasculaEngine::animation_6_6() {
removeObject(20);
loadPic(96, frontSurface);
loadPic(97, frontSurface);
- loadPic(97, _lang == kSpanish ? tableSurface : extraSurface);
+ loadPic(97, extraSurface);
loadPic(99, backSurface);
doBreak = 1;
objExit = 104;
@@ -2216,7 +2216,7 @@ void DrasculaEngine::activatePendulum() {
_roomNumber = 102;
loadPic(102, bgSurface, HALF_PAL);
loadPic("an_p1.alg", drawSurface3);
- loadPic("an_p2.alg", _lang == kSpanish ? tableSurface : extraSurface);
+ loadPic("an_p2.alg", extraSurface);
loadPic("an_p3.alg", frontSurface);
copyBackground(0, 171, 0, 0, OBJWIDTH, OBJHEIGHT, backSurface, drawSurface3);
diff --git a/engines/drascula/drascula.cpp b/engines/drascula/drascula.cpp
index 75a81c20b0..ab91056480 100644
--- a/engines/drascula/drascula.cpp
+++ b/engines/drascula/drascula.cpp
@@ -359,16 +359,13 @@ Common::Error DrasculaEngine::run() {
for (i = 0; i < 25; i++)
memcpy(crosshairCursor + i * 40, tableSurface + 225 + (56 + i) * 320, 40);
- if (_lang == kSpanish)
- loadPic(currentChapter == 6 ? 97 : 974, tableSurface);
+ if (_lang == kSpanish && currentChapter != 6)
+ loadPic(974, tableSurface);
if (currentChapter != 2) {
loadPic(99, cursorSurface);
loadPic(99, backSurface);
- if (currentChapter == 6 && _lang == kSpanish)
- loadPic(95, extraSurface);
- else
- loadPic(97, extraSurface);
+ loadPic(97, extraSurface);
}
memset(iconName, 0, sizeof(iconName));
@@ -598,7 +595,6 @@ bool DrasculaEngine::runCurrentChapter() {
if (_rightMouseButton == 1 && _menuScreen) {
#endif
_rightMouseButton = 0;
- delay(100);
if (currentChapter == 2) {
loadPic(menuBackground, cursorSurface);
loadPic(menuBackground, backSurface);
@@ -627,7 +623,6 @@ bool DrasculaEngine::runCurrentChapter() {
!(currentChapter == 5 && pickedObject == 16)) {
#endif
_rightMouseButton = 0;
- delay(100);
characterMoved = 0;
if (trackProtagonist == 2)
trackProtagonist = 1;
@@ -655,12 +650,11 @@ bool DrasculaEngine::runCurrentChapter() {
#endif
if (_leftMouseButton == 1 && _menuBar) {
- delay(100);
selectVerbFromBar();
} else if (_leftMouseButton == 1 && takeObject == 0) {
- delay(100);
if (verify1())
return true;
+ delay(100);
} else if (_leftMouseButton == 1 && takeObject == 1) {
if (verify2())
return true;
@@ -894,7 +888,7 @@ void DrasculaEngine::pause(int duration) {
}
int DrasculaEngine::getTime() {
- return _system->getMillis() / 20; // originally was 1
+ return _system->getMillis() / 10;
}
void DrasculaEngine::reduce_hare_chico(int xx1, int yy1, int xx2, int yy2, int width, int height, int factor, byte *dir_inicio, byte *dir_fin) {
diff --git a/engines/drascula/drascula.h b/engines/drascula/drascula.h
index acca2e5915..c879a83db7 100644
--- a/engines/drascula/drascula.h
+++ b/engines/drascula/drascula.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef DRASCULA_H
-#define DRASCULA_H
+#ifndef DRASCULA_DRASCULA_H
+#define DRASCULA_DRASCULA_H
#include "common/scummsys.h"
#include "common/archive.h"
@@ -784,4 +784,4 @@ protected:
} // End of namespace Drascula
-#endif /* DRASCULA_H */
+#endif /* DRASCULA_DRASCULA_H */
diff --git a/engines/drascula/graphics.cpp b/engines/drascula/graphics.cpp
index 01bd267158..6bfb2e1823 100644
--- a/engines/drascula/graphics.cpp
+++ b/engines/drascula/graphics.cpp
@@ -217,6 +217,10 @@ void DrasculaEngine::print_abc(const char *said, int screenX, int screenY) {
int letterY = 0, letterX = 0, i;
uint len = strlen(said);
byte c;
+
+ byte *srcSurface = tableSurface;
+ if (_lang == kSpanish && currentChapter == 6)
+ srcSurface = extraSurface;
for (uint h = 0; h < len; h++) {
c = toupper(said[h]);
@@ -241,7 +245,7 @@ void DrasculaEngine::print_abc(const char *said, int screenX, int screenY) {
} // for
copyRect(letterX, letterY, screenX, screenY,
- CHAR_WIDTH, CHAR_HEIGHT, tableSurface, screenSurface);
+ CHAR_WIDTH, CHAR_HEIGHT, srcSurface, screenSurface);
screenX = screenX + CHAR_WIDTH;
if (screenX > 317) {
diff --git a/engines/drascula/interface.cpp b/engines/drascula/interface.cpp
index a09b9da07d..07f192cd4c 100644
--- a/engines/drascula/interface.cpp
+++ b/engines/drascula/interface.cpp
@@ -123,15 +123,6 @@ void DrasculaEngine::showMenu() {
int h, n, x;
byte *srcSurface = (currentChapter == 6) ? tableSurface : frontSurface;
x = whichObject();
-
- // The original uses extraSurface to draw text in draw_abc() in the Spanish version
- // while other languages use tableSurface. Here all language use tableSurface for
- // chapter 6. However the code in ScummVM was changed to use tableSurface for all
- // labguage in draw_abc(). So instead here for the Spanish version we use extraSurface.
- // Compared to the original the use of the tableSurface and extraSurface has been swapped
- // for the Spanish language all through chapter 6.
- if (currentChapter == 6 && _lang == kSpanish)
- srcSurface = extraSurface;
for (n = 1; n < ARRAYSIZE(inventoryObjects); n++) {
h = inventoryObjects[n];
diff --git a/engines/drascula/objects.cpp b/engines/drascula/objects.cpp
index 823c073d43..02846abcc9 100644
--- a/engines/drascula/objects.cpp
+++ b/engines/drascula/objects.cpp
@@ -272,6 +272,8 @@ void DrasculaEngine::updateVisible() {
visible[2] = 0;
if (_roomNumber == 26 && flags[12] == 1)
visible[1] = 0;
+ if (_roomNumber == 31 && flags[13] == 1)
+ visible[1] = 0;
if (_roomNumber == 35 && flags[14] == 1)
visible[2] = 0;
if (_roomNumber == 35 && flags[17] == 1)
diff --git a/engines/drascula/rooms.cpp b/engines/drascula/rooms.cpp
index acfc528b0c..57d4517295 100644
--- a/engines/drascula/rooms.cpp
+++ b/engines/drascula/rooms.cpp
@@ -1501,7 +1501,7 @@ void DrasculaEngine::update_102() {
if (actorFrames[kFramePendulum] <= 4)
pendulumSurface = drawSurface3;
else if (actorFrames[kFramePendulum] <= 11)
- pendulumSurface = _lang == kSpanish ? tableSurface : extraSurface;
+ pendulumSurface = extraSurface;
else
pendulumSurface = frontSurface;
diff --git a/engines/drascula/sound.cpp b/engines/drascula/sound.cpp
index 6c0c171664..62ec796678 100644
--- a/engines/drascula/sound.cpp
+++ b/engines/drascula/sound.cpp
@@ -44,13 +44,10 @@ void DrasculaEngine::updateVolume(Audio::Mixer::SoundType soundType, int prevVol
}
void DrasculaEngine::volumeControls() {
- byte* srcSurface = tableSurface;
- if (currentChapter == 6 && _lang == kSpanish)
- srcSurface = extraSurface;
- if (_lang == kSpanish)
- loadPic(95, srcSurface);
+ if (_lang == kSpanish && currentChapter != 6)
+ loadPic(95, tableSurface);
- copyRect(1, 56, 73, 63, 177, 97, srcSurface, screenSurface);
+ copyRect(1, 56, 73, 63, 177, 97, tableSurface, screenSurface);
updateScreen(73, 63, 73, 63, 177, 97, screenSurface);
setCursor(kCursorCrosshair);
@@ -67,11 +64,11 @@ void DrasculaEngine::volumeControls() {
updateRoom();
- copyRect(1, 56, 73, 63, 177, 97, srcSurface, screenSurface);
+ copyRect(1, 56, 73, 63, 177, 97, tableSurface, screenSurface);
- copyBackground(183, 56, 82, masterVolumeY, 39, 2 + masterVolume * 4, srcSurface, screenSurface);
- copyBackground(183, 56, 138, voiceVolumeY, 39, 2 + voiceVolume * 4, srcSurface, screenSurface);
- copyBackground(183, 56, 194, musicVolumeY, 39, 2 + musicVolume * 4, srcSurface, screenSurface);
+ copyBackground(183, 56, 82, masterVolumeY, 39, 2 + masterVolume * 4, tableSurface, screenSurface);
+ copyBackground(183, 56, 138, voiceVolumeY, 39, 2 + voiceVolume * 4, tableSurface, screenSurface);
+ copyBackground(183, 56, 194, musicVolumeY, 39, 2 + musicVolume * 4, tableSurface, screenSurface);
updateScreen();
@@ -104,8 +101,8 @@ void DrasculaEngine::volumeControls() {
}
- if (_lang == kSpanish)
- loadPic(currentChapter == 6 ? 95 : 974, srcSurface);
+ if (_lang == kSpanish && currentChapter != 6)
+ loadPic(974, tableSurface);
selectVerb(kVerbNone);
@@ -169,8 +166,8 @@ void DrasculaEngine::MusicFadeout() {
void DrasculaEngine::playFile(const char *fname) {
Common::SeekableReadStream *stream = _archives.open(fname);
if (stream) {
- int startOffset = 0;
- int soundSize = stream->size() - startOffset;
+ int startOffset = 32;
+ int soundSize = stream->size() - 64;
if (!strcmp(fname, "3.als") && soundSize == 145166 && _lang != kSpanish) {
// WORKAROUND: File 3.als with English speech files has a big silence at
diff --git a/engines/drascula/talk.cpp b/engines/drascula/talk.cpp
index 3176c5e0f3..cc329b206b 100644
--- a/engines/drascula/talk.cpp
+++ b/engines/drascula/talk.cpp
@@ -440,12 +440,9 @@ void DrasculaEngine::talk(const char *said, const char *filename) {
copyRect(x_talk_izq[face], y_mask_talk, curX + 8, curY - 1, TALK_WIDTH, TALK_HEIGHT,
extraSurface, screenSurface);
else if (notTowers) {
- byte *srcSurface = extraSurface;
- if (currentChapter == 6 && _lang == kSpanish)
- srcSurface = tableSurface;
reduce_hare_chico(x_talk_izq[face], y_mask_talk, curX + (int)((8.0f / 100) * factor_red[MIN(201, curY + curHeight)]),
curY, TALK_WIDTH, TALK_HEIGHT, factor_red[MIN(201, curY + curHeight)],
- srcSurface, screenSurface);
+ extraSurface, screenSurface);
}
updateRefresh();
} else if (trackProtagonist == 1) {
@@ -453,11 +450,8 @@ void DrasculaEngine::talk(const char *said, const char *filename) {
copyRect(x_talk_dch[face], y_mask_talk, curX + 12, curY, TALK_WIDTH, TALK_HEIGHT,
extraSurface, screenSurface);
else if (notTowers) {
- byte *srcSurface = extraSurface;
- if (currentChapter == 6 && _lang == kSpanish)
- srcSurface = tableSurface;
reduce_hare_chico(x_talk_dch[face], y_mask_talk, curX + (int)((12.0f / 100) * factor_red[MIN(201, curY + curHeight)]),
- curY, TALK_WIDTH, TALK_HEIGHT, factor_red[MIN(201, curY + curHeight)], srcSurface, screenSurface);
+ curY, TALK_WIDTH, TALK_HEIGHT, factor_red[MIN(201, curY + curHeight)], extraSurface, screenSurface);
}
updateRefresh();
} else if (trackProtagonist == 2) {
diff --git a/engines/dreamweb/dreamweb.h b/engines/dreamweb/dreamweb.h
index 2e5fb424f8..45bacdba86 100644
--- a/engines/dreamweb/dreamweb.h
+++ b/engines/dreamweb/dreamweb.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef DREAMWEB_H
-#define DREAMWEB_H
+#ifndef DREAMWEB_DREAMWEB_H
+#define DREAMWEB_DREAMWEB_H
#include "common/error.h"
#include "common/keyboard.h"
diff --git a/engines/fullpipe/fullpipe.cpp b/engines/fullpipe/fullpipe.cpp
index ebaff32550..c2aae9ba88 100644
--- a/engines/fullpipe/fullpipe.cpp
+++ b/engines/fullpipe/fullpipe.cpp
@@ -24,6 +24,7 @@
#include "common/archive.h"
#include "common/config-manager.h"
+#include "audio/mixer.h"
#include "engines/util.h"
@@ -112,6 +113,8 @@ FullpipeEngine::FullpipeEngine(OSystem *syst, const ADGameDescription *gameDesc)
_musicLocal = 0;
_trackStartDelay = 0;
+ _sceneTrackHandle = new Audio::SoundHandle();
+
memset(_sceneTracks, 0, sizeof(_sceneTracks));
memset(_trackName, 0, sizeof(_trackName));
memset(_sceneTracksCurrentTrack, 0, sizeof(_sceneTracksCurrentTrack));
@@ -192,6 +195,7 @@ FullpipeEngine::~FullpipeEngine() {
delete _rnd;
delete _console;
delete _globalMessageQueueList;
+ delete _sceneTrackHandle;
}
void FullpipeEngine::initialize() {
diff --git a/engines/fullpipe/fullpipe.h b/engines/fullpipe/fullpipe.h
index 7f20a6d6af..fba61aa13b 100644
--- a/engines/fullpipe/fullpipe.h
+++ b/engines/fullpipe/fullpipe.h
@@ -30,8 +30,6 @@
#include "common/savefile.h"
#include "common/system.h"
-#include "audio/mixer.h"
-
#include "graphics/transparent_surface.h"
#include "engines/engine.h"
@@ -41,6 +39,10 @@
struct ADGameDescription;
+namespace Audio {
+class SoundHandle;
+}
+
namespace Fullpipe {
enum FullpipeGameFeatures {
@@ -312,7 +314,7 @@ public:
void lift_openLift();
GameVar *_musicGameVar;
- Audio::SoundHandle _sceneTrackHandle;
+ Audio::SoundHandle *_sceneTrackHandle;
public:
diff --git a/engines/fullpipe/motion.cpp b/engines/fullpipe/motion.cpp
index 1a61cb742a..9cf18f3cc2 100644
--- a/engines/fullpipe/motion.cpp
+++ b/engines/fullpipe/motion.cpp
@@ -855,9 +855,9 @@ Common::Array<MovItem *> *MovGraph::getPaths(StaticANIObject *ani, int x, int y,
if (sz > 0) {
for (int j = 0; j < sz; j++)
_items[idx]->movitems->push_back(movitems[j]);
-
- delete movitems;
}
+
+ delete movitems;
}
delete movarr;
diff --git a/engines/fullpipe/sound.cpp b/engines/fullpipe/sound.cpp
index 230d6c39a9..c82c2c414c 100644
--- a/engines/fullpipe/sound.cpp
+++ b/engines/fullpipe/sound.cpp
@@ -30,6 +30,7 @@
#include "fullpipe/statics.h"
#include "common/memstream.h"
+#include "audio/mixer.h"
#include "audio/audiostream.h"
#include "audio/decoders/vorbis.h"
#include "audio/decoders/wave.h"
@@ -96,12 +97,13 @@ Sound::Sound() {
memset(_directSoundBuffers, 0, sizeof(_directSoundBuffers));
_description = 0;
_volume = 100;
+ _handle = new Audio::SoundHandle();
}
Sound::~Sound() {
freeSound();
-
free(_description);
+ delete _handle;
}
bool Sound::load(MfcArchive &file, NGIArchive *archive) {
@@ -206,14 +208,14 @@ void Sound::setPanAndVolumeByStaticAni() {
}
void Sound::setPanAndVolume(int vol, int pan) {
- g_fp->_mixer->setChannelVolume(_handle, vol / 39); // 0..10000
- g_fp->_mixer->setChannelBalance(_handle, pan / 78); // -10000..10000
+ g_fp->_mixer->setChannelVolume(*_handle, vol / 39); // 0..10000
+ g_fp->_mixer->setChannelBalance(*_handle, pan / 78); // -10000..10000
}
void Sound::play(int flag) {
- Audio::SoundHandle handle = getHandle();
+ Audio::SoundHandle *handle = getHandle();
- if (g_fp->_mixer->isSoundHandleActive(handle))
+ if (g_fp->_mixer->isSoundHandleActive(*handle))
return;
byte *soundData = loadData();
@@ -221,7 +223,7 @@ void Sound::play(int flag) {
Audio::RewindableAudioStream *wav = Audio::makeWAVStream(dataStream, DisposeAfterUse::YES);
Audio::AudioStream *audioStream = new Audio::LoopingAudioStream(wav, (flag == 1) ? 0 : 1);
- g_fp->_mixer->playStream(Audio::Mixer::kSFXSoundType, &handle, audioStream);
+ g_fp->_mixer->playStream(Audio::Mixer::kSFXSoundType, handle, audioStream);
}
void Sound::freeSound() {
@@ -231,11 +233,11 @@ void Sound::freeSound() {
}
int Sound::getVolume() {
- return g_fp->_mixer->getChannelVolume(_handle) * 39; // 0..10000
+ return g_fp->_mixer->getChannelVolume(*_handle) * 39; // 0..10000
}
void Sound::stop() {
- g_fp->_mixer->stopHandle(_handle);
+ g_fp->_mixer->stopHandle(*_handle);
}
void FullpipeEngine::setSceneMusicParameters(GameVar *gvar) {
@@ -353,7 +355,7 @@ void FullpipeEngine::startSoundStream1(char *trackName) {
stopAllSoundStreams();
#ifdef USE_VORBIS
- if (_mixer->isSoundHandleActive(_sceneTrackHandle))
+ if (_mixer->isSoundHandleActive(*_sceneTrackHandle))
return;
Common::File *track = new Common::File();
@@ -363,7 +365,7 @@ void FullpipeEngine::startSoundStream1(char *trackName) {
return;
}
Audio::RewindableAudioStream *ogg = Audio::makeVorbisStream(track, DisposeAfterUse::YES);
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_sceneTrackHandle, ogg);
+ _mixer->playStream(Audio::Mixer::kMusicSoundType, _sceneTrackHandle, ogg);
#endif
}
diff --git a/engines/fullpipe/sound.h b/engines/fullpipe/sound.h
index 14e766f5bb..983f28312b 100644
--- a/engines/fullpipe/sound.h
+++ b/engines/fullpipe/sound.h
@@ -23,6 +23,10 @@
#ifndef FULLPIPE_SOUND_H
#define FULLPIPE_SOUND_H
+namespace Audio {
+class SoundHandle;
+}
+
namespace Fullpipe {
class Sound : public MemoryObject {
@@ -31,7 +35,7 @@ class Sound : public MemoryObject {
int _directSoundBuffer;
int _directSoundBuffers[7];
byte *_soundData;
- Audio::SoundHandle _handle;
+ Audio::SoundHandle *_handle;
int _volume;
public:
@@ -45,7 +49,7 @@ public:
virtual bool load(MfcArchive &file) { assert(0); return false; } // Disable base class
void updateVolume();
int getId() const { return _id; }
- Audio::SoundHandle getHandle() const { return _handle; }
+ Audio::SoundHandle *getHandle() const { return _handle; }
void play(int flag);
void freeSound();
diff --git a/engines/fullpipe/statics.cpp b/engines/fullpipe/statics.cpp
index 8ee3b14d0c..36fbb73037 100644
--- a/engines/fullpipe/statics.cpp
+++ b/engines/fullpipe/statics.cpp
@@ -1576,6 +1576,9 @@ Movement::Movement(Movement *src, int *oldIdxs, int newSize, StaticANIObject *an
_m2x = 0;
_m2y = 0;
+ _counter = 0;
+ _counterMax = 0;
+
_field_78 = 0;
_framePosOffsets = 0;
_field_84 = 0;
diff --git a/engines/gnap/character.cpp b/engines/gnap/character.cpp
new file mode 100644
index 0000000000..36d849acbf
--- /dev/null
+++ b/engines/gnap/character.cpp
@@ -0,0 +1,1415 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "gnap/gnap.h"
+#include "gnap/character.h"
+#include "gnap/gamesys.h"
+
+namespace Gnap {
+
+Character::Character(GnapEngine *vm) : _vm(vm) {
+ _pos = Common::Point(0, 0);
+ _idleFacing = kDirIdleLeft;
+ _actionStatus = 0;
+ _sequenceId = 0;
+ _sequenceDatNum = 0;
+ _id = 0;
+ _gridX = 0;
+ _gridY = 0;
+
+ _walkNodesCount = 0;
+ _walkDestX = _walkDestY = 0;
+ _walkDeltaX = _walkDeltaY = 0;
+ _walkDirX = _walkDirY = 0;
+ _walkDirXIncr = _walkDirYIncr = 0;
+
+ for(int i = 0; i < kMaxGridStructs; i++) {
+ _walkNodes[i]._id = 0;
+ _walkNodes[i]._sequenceId = 0;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = 0;
+ _walkNodes[i]._gridX1 = 0;
+ _walkNodes[i]._gridY1 = 0;
+ }
+}
+
+Character::~Character() {}
+
+void Character::walkStep() {
+ for (int i = 1; i < _vm->_gridMaxX; ++i) {
+ Common::Point checkPt = Common::Point(_pos.x + i, _pos.y);
+ if (!_vm->isPointBlocked(checkPt)) {
+ walkTo(checkPt, -1, -1, 1);
+ break;
+ }
+
+ checkPt = Common::Point(_pos.x - i, _pos.y);
+ if (!_vm->isPointBlocked(checkPt)) {
+ walkTo(checkPt, -1, -1, 1);
+ break;
+ }
+
+ checkPt = Common::Point(_pos.x, _pos.y + 1);
+ if (!_vm->isPointBlocked(checkPt)) {
+ walkTo(checkPt, -1, -1, 1);
+ break;
+ }
+
+ checkPt = Common::Point(_pos.x, _pos.y - 1);
+ if (!_vm->isPointBlocked(checkPt)) {
+ walkTo(checkPt, -1, -1, 1);
+ break;
+ }
+
+ checkPt = Common::Point(_pos.x + 1, _pos.y + 1);
+ if (!_vm->isPointBlocked(checkPt)) {
+ walkTo(checkPt, -1, -1, 1);
+ break;
+ }
+
+ checkPt = Common::Point(_pos.x - 1, _pos.y + 1);
+ if (!_vm->isPointBlocked(checkPt)) {
+ walkTo(checkPt, -1, -1, 1);
+ break;
+ }
+
+ checkPt = Common::Point(_pos.x + 1, _pos.y - 1);
+ if (!_vm->isPointBlocked(checkPt)) {
+ walkTo(checkPt, -1, -1, 1);
+ break;
+ }
+
+ checkPt = Common::Point(_pos.x - 1, _pos.y - 1);
+ if (!_vm->isPointBlocked(checkPt)) {
+ walkTo(checkPt, -1, -1, 1);
+ break;
+ }
+ }
+}
+/************************************************************************************************/
+
+PlayerGnap::PlayerGnap(GnapEngine * vm) : Character(vm) {
+ _brainPulseNum = 0;
+ _brainPulseRndValue = 0;
+}
+
+int PlayerGnap::getSequenceId(int kind, Common::Point gridPos) {
+ int sequenceId = 0;
+
+ switch (kind) {
+ case kGSPullOutDevice:
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.y > gridPos.y) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x83F;
+ _idleFacing = kDirUpLeft;
+ } else {
+ sequenceId = 0x83D;
+ _idleFacing = kDirUpRight;
+ }
+ } else {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x83B;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x839;
+ _idleFacing = kDirBottomRight;
+ }
+ }
+ } else {
+ switch (_idleFacing) {
+ case kDirBottomRight:
+ sequenceId = 0x839;
+ break;
+ case kDirBottomLeft:
+ sequenceId = 0x83B;
+ break;
+ case kDirUpRight:
+ sequenceId = 0x83D;
+ break;
+ default:
+ sequenceId = 0x83F;
+ break;
+ }
+ }
+ break;
+
+ case kGSPullOutDeviceNonWorking:
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.y > gridPos.y) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x829;
+ _idleFacing = kDirUpLeft;
+ } else {
+ sequenceId = 0x828;
+ _idleFacing = kDirUpRight;
+ }
+ } else {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x827;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x826;
+ _idleFacing = kDirBottomRight;
+ }
+ }
+ } else {
+ switch (_idleFacing) {
+ case kDirBottomRight:
+ sequenceId = 0x826;
+ break;
+ case kDirBottomLeft:
+ sequenceId = 0x827;
+ break;
+ case kDirUpRight:
+ sequenceId = 0x828;
+ break;
+ default:
+ sequenceId = 0x829;
+ break;
+ }
+ }
+ break;
+
+ case kGSScratchingHead:
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.y > gridPos.y) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x834;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x885;
+ _idleFacing = kDirUpRight;
+ }
+ } else {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x834;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x833;
+ _idleFacing = kDirBottomRight;
+ }
+ }
+ } else {
+ switch (_idleFacing) {
+ case kDirBottomRight:
+ sequenceId = 0x833;
+ _idleFacing = kDirBottomRight;
+ break;
+ case kDirBottomLeft:
+ sequenceId = 0x834;
+ _idleFacing = kDirBottomLeft;
+ break;
+ case kDirUpRight:
+ sequenceId = 0x885;
+ _idleFacing = kDirUpRight;
+ break;
+ default:
+ sequenceId = 0x834;
+ _idleFacing = kDirBottomLeft;
+ break;
+ }
+ }
+ break;
+
+ case kGSIdle:
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.y > gridPos.y) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x7BC;
+ _idleFacing = kDirUpLeft;
+ } else {
+ sequenceId = 0x7BB;
+ _idleFacing = kDirUpRight;
+ }
+ } else {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x7BA;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x7B9;
+ _idleFacing = kDirBottomRight;
+ }
+ }
+ } else {
+ switch (_idleFacing) {
+ case kDirBottomRight:
+ sequenceId = 0x7B9;
+ break;
+ case kDirBottomLeft:
+ sequenceId = 0x7BA;
+ break;
+ case kDirUpRight:
+ sequenceId = 0x7BB;
+ break;
+ default:
+ sequenceId = 0x7BC;
+ break;
+ }
+ }
+ break;
+
+ case kGSBrainPulsating:
+ _brainPulseNum = (_brainPulseNum + 1) & 1;
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.y > gridPos.y) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = _brainPulseRndValue + _brainPulseNum + 0x812;
+ _idleFacing = kDirUpLeft;
+ } else {
+ sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7FE;
+ _idleFacing = kDirUpRight;
+ }
+ } else {
+ if (_pos.x > gridPos.x) {
+ sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7D6;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7EA;
+ _idleFacing = kDirBottomRight;
+ }
+ }
+ } else {
+ switch (_idleFacing) {
+ case kDirBottomRight:
+ sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7EA;
+ break;
+ case kDirBottomLeft:
+ sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7D6;
+ break;
+ case kDirUpRight:
+ sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7FE;
+ break;
+ default:
+ sequenceId = _brainPulseRndValue + _brainPulseNum + 0x812;
+ break;
+ }
+ }
+ break;
+
+ case kGSImpossible:
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.y > gridPos.y) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x831;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x7A8;
+ _idleFacing = kDirBottomRight;
+ }
+ } else {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x831;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ if (_pos.x % 2)
+ sequenceId = 0x7A8;
+ else
+ sequenceId = 0x89A;
+ _idleFacing = kDirBottomRight;
+ }
+ }
+ } else if (_idleFacing != kDirBottomRight && _idleFacing != kDirUpRight) {
+ sequenceId = 0x831;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ if (_vm->_currentSceneNum % 2)
+ sequenceId = 0x7A8;
+ else
+ sequenceId = 0x89A;
+ _idleFacing = kDirBottomRight;
+ }
+ break;
+
+ case kGSDeflect:
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.y > gridPos.y) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x830;
+ _idleFacing = kDirUpLeft;
+ } else {
+ sequenceId = 0x82F;
+ _idleFacing = kDirUpRight;
+ }
+ } else {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x82E;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x7A7;
+ _idleFacing = kDirBottomRight;
+ }
+ }
+ } else {
+ switch (_idleFacing) {
+ case kDirBottomRight:
+ sequenceId = 0x7A7;
+ break;
+ case kDirBottomLeft:
+ sequenceId = 0x82E;
+ break;
+ case kDirUpLeft:
+ sequenceId = 0x830;
+ break;
+ case kDirUpRight:
+ sequenceId = 0x82F;
+ break;
+ case kDirIdleLeft:
+ case kDirIdleRight:
+ break;
+ }
+ }
+ break;
+
+ case kGSUseDevice:
+ switch (_idleFacing) {
+ case kDirBottomRight:
+ sequenceId = 0x83A;
+ break;
+ case kDirBottomLeft:
+ sequenceId = 0x83C;
+ break;
+ case kDirUpLeft:
+ sequenceId = 0x840;
+ break;
+ case kDirUpRight:
+ sequenceId = 0x83E;
+ break;
+ case kDirIdleLeft:
+ case kDirIdleRight:
+ break;
+ }
+ break;
+
+ case kGSMoan1:
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.y > gridPos.y) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x832;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x7AA;
+ _idleFacing = kDirBottomRight;
+ }
+ } else {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x832;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x7AA;
+ _idleFacing = kDirBottomRight;
+ }
+ }
+ } else if (_idleFacing != kDirBottomRight && _idleFacing != kDirUpRight) {
+ sequenceId = 0x832;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x7AA;
+ _idleFacing = kDirBottomRight;
+ }
+ break;
+
+ case kGSMoan2:
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x832;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x7AA;
+ _idleFacing = kDirBottomRight;
+ }
+ } else if (_idleFacing != kDirBottomRight && _idleFacing != kDirUpRight) {
+ sequenceId = 0x832;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x7AA;
+ _idleFacing = kDirBottomRight;
+ }
+ break;
+ }
+
+ return sequenceId | 0x10000;
+}
+
+void PlayerGnap::useJointOnPlatypus() {
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->setGrabCursorSprite(-1);
+ if (doPlatypusAction(1, 0, 0x107C1, 0)) {
+ _actionStatus = 100;
+ _vm->_gameSys->setAnimation(0, 0, 1);
+ _vm->_gameSys->setAnimation(0x10876, plat._id, 0);
+ _vm->_gameSys->insertSequence(0x10875, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncWait, 0, 15 * (5 * _pos.x - 30), 48 * (_pos.y - 7));
+ _sequenceDatNum = 1;
+ _sequenceId = 0x875;
+ _vm->_gameSys->insertSequence(0x10876, plat._id,
+ plat._sequenceId | (plat._sequenceDatNum << 16), plat._id,
+ kSeqSyncWait, 0, 15 * (5 * plat._pos.x - 25), 48 * (plat._pos.y - 7));
+ plat._sequenceDatNum = 1;
+ plat._sequenceId = 0x876;
+ plat._idleFacing = kDirIdleLeft;
+ playSequence(0x107B5);
+ walkStep();
+ while (_vm->_gameSys->getAnimationStatus(0) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ _vm->_gameSys->setAnimation(0, 0, 0);
+ _actionStatus = -1;
+ } else {
+ playSequence(getSequenceId(kGSScratchingHead, plat._pos) | 0x10000);
+ }
+}
+
+void PlayerGnap::kissPlatypus(int callback) {
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (doPlatypusAction(-1, 0, 0x107D1, callback)) {
+ _actionStatus = 100;
+ _vm->_gameSys->setAnimation(0, 0, 1);
+ _vm->_gameSys->setAnimation(0x10847, _id, 0);
+ _vm->_gameSys->insertSequence(0x10847, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncWait, 0, 15 * (5 * _pos.x - 20) - (21 - _vm->_gridMinX), 48 * (_pos.y - 6) - (146 - _vm->_gridMinY));
+ _sequenceDatNum = 1;
+ _sequenceId = 0x847;
+ _vm->_gameSys->insertSequence(0x107CB, plat._id,
+ makeRid(plat._sequenceDatNum, plat._sequenceId), plat._id,
+ kSeqSyncWait, _vm->getSequenceTotalDuration(0x10847), 75 * plat._pos.x - plat._gridX, 48 * plat._pos.y - plat._gridY);
+ plat._sequenceDatNum = 1;
+ plat._sequenceId = 0x7CB;
+ plat._idleFacing = kDirIdleLeft;
+ playSequence(0x107B5);
+ while (_vm->_gameSys->getAnimationStatus(0) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->doCallback(callback);
+ _vm->gameUpdateTick();
+ }
+ _vm->_gameSys->setAnimation(0, 0, 0);
+ _actionStatus = -1;
+ } else {
+ playSequence(getSequenceId(kGSScratchingHead, plat._pos) | 0x10000);
+ }
+}
+
+void PlayerGnap::useDeviceOnPlatypus() {
+ PlayerPlat& plat = *_vm->_plat;
+
+ playSequence(makeRid(1, getSequenceId(kGSPullOutDevice, plat._pos)));
+
+ if (plat._idleFacing != kDirIdleLeft) {
+ _vm->_gameSys->insertSequence(makeRid(1, 0x7D5), plat._id,
+ makeRid(plat._sequenceDatNum, plat._sequenceId), plat._id,
+ kSeqSyncWait, 0, 75 * plat._pos.x - plat._gridX, 48 * plat._pos.y - plat._gridY);
+ plat._sequenceId = 0x7D5;
+ plat._sequenceDatNum = 1;
+ } else {
+ _vm->_gameSys->insertSequence(makeRid(1, 0x7D4), plat._id,
+ makeRid(plat._sequenceDatNum, plat._sequenceId), plat._id,
+ kSeqSyncWait, 0, 75 * plat._pos.x - plat._gridX, 48 * plat._pos.y - plat._gridY);
+ plat._sequenceId = 0x7D4;
+ plat._sequenceDatNum = 1;
+ }
+
+ int newSequenceId = getSequenceId(kGSUseDevice, Common::Point(0, 0));
+ _vm->_gameSys->insertSequence(makeRid(1, newSequenceId), _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = newSequenceId;
+ _sequenceDatNum = 1;
+}
+
+void PlayerGnap::initBrainPulseRndValue() {
+ _brainPulseRndValue = 2 * _vm->getRandom(10);
+}
+
+void PlayerGnap::playSequence(int sequenceId) {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = 300;
+ idle();
+ _vm->_gameSys->insertSequence(sequenceId, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqScale | kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = ridToEntryIndex(sequenceId);
+ _sequenceDatNum = ridToDatIndex(sequenceId);
+}
+
+void PlayerGnap::updateIdleSequence() {
+ if (_actionStatus < 0) {
+ if (_vm->_timers[2] > 0) {
+ if (_vm->_timers[3] == 0) {
+ _vm->_timers[2] = 60;
+ _vm->_timers[3] = 300;
+ if (_idleFacing == kDirBottomRight) {
+ switch (_vm->getRandom(5)) {
+ case 0:
+ playSequence(0x107A6);
+ break;
+ case 1:
+ playSequence(0x107AA);
+ break;
+ case 2:
+ playSequence(0x10841);
+ break;
+ default:
+ playSequence(0x108A2);
+ break;
+ }
+ } else if (_idleFacing == kDirBottomLeft) {
+ if (_vm->getRandom(5) > 2)
+ playSequence(0x10832);
+ else
+ playSequence(0x10842);
+ }
+ }
+ } else {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ if (_idleFacing == kDirBottomRight) {
+ _vm->_gameSys->insertSequence(0x107BD, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = 0x7BD;
+ _sequenceDatNum = 1;
+ } else if (_idleFacing == kDirBottomLeft) {
+ _vm->_gameSys->insertSequence(0x107BE, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = 0x7BE;
+ _sequenceDatNum = 1;
+ }
+ }
+ } else {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = 300;
+ }
+}
+
+void PlayerGnap::updateIdleSequence2() {
+ if (_actionStatus < 0) {
+ if (_vm->_timers[2] > 0) {
+ if (_vm->_timers[3] == 0) {
+ _vm->_timers[2] = 60;
+ _vm->_timers[3] = 300;
+ if (_idleFacing == kDirBottomRight) {
+ playSequence(0x107AA);
+ } else if (_idleFacing == kDirBottomLeft) {
+ playSequence(0x10832);
+ }
+ }
+ } else {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ if (_idleFacing == kDirBottomRight) {
+ _vm->_gameSys->insertSequence(0x107BD, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = 0x7BD;
+ _sequenceDatNum = 1;
+ } else if (_idleFacing == kDirBottomLeft) {
+ _vm->_gameSys->insertSequence(0x107BE, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = 0x7BE;
+ _sequenceDatNum = 1;
+ }
+ }
+ } else {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = 300;
+ }
+}
+
+void PlayerGnap::initPos(int gridX, int gridY, Facing facing) {
+ _vm->_timers[2] = 30;
+ _vm->_timers[3] = 300;
+ _pos = Common::Point(gridX, gridY);
+ if (facing == kDirIdleLeft)
+ _idleFacing = kDirBottomRight;
+ else
+ _idleFacing = facing;
+
+ if (_idleFacing == kDirBottomLeft) {
+ _sequenceId = 0x7B8;
+ } else {
+ _sequenceId = 0x7B5;
+ _idleFacing = kDirBottomRight;
+ }
+ _id = 20 * _pos.y;
+ _sequenceDatNum = 1;
+ _vm->_gameSys->insertSequence(makeRid(1, _sequenceId), 20 * _pos.y,
+ 0, 0,
+ kSeqScale, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+}
+
+int PlayerGnap::getWalkSequenceId(int deltaX, int deltaY) {
+ static const int walkSequenceIds[9] = {
+ 0x7B2, 0x000, 0x7B4,
+ 0x7AD, 0x000, 0x7AE,
+ 0x7B1, 0x000, 0x7B3
+ };
+
+ int id = 3 * (deltaX + 1) + deltaY + 1;
+ assert(id >= 0 && id < 9);
+
+ return walkSequenceIds[id];
+}
+
+bool PlayerGnap::walkTo(Common::Point gridPos, int animationIndex, int sequenceId, int flags) {
+ PlayerPlat& plat = *_vm->_plat;
+ int datNum = flags & 3;
+
+ _vm->_timers[2] = 200;
+ _vm->_timers[3] = 300;
+
+ int gridX = gridPos.x;
+ if (gridX < 0)
+ gridX = (_vm->_leftClickMouseX - _vm->_gridMinX + 37) / 75;
+
+ int gridY = gridPos.y;
+ if (gridY < 0)
+ gridY = (_vm->_leftClickMouseY - _vm->_gridMinY + 24) / 48;
+
+ _walkDestX = CLIP(gridX, 0, _vm->_gridMaxX - 1);
+ _walkDestY = CLIP(gridY, 0, _vm->_gridMaxY - 1);
+
+ if (animationIndex >= 0 && _walkDestX == plat._pos.x && _walkDestY == plat._pos.y)
+ plat.makeRoom();
+
+ bool done = findPath1(_pos.x, _pos.y, 0);
+
+ if (!done)
+ done = findPath2(_pos.x, _pos.y, 0);
+
+ if (!done)
+ done = findPath3(_pos.x, _pos.y);
+
+ if (!done)
+ done = findPath4(_pos.x, _pos.y);
+
+ idle();
+
+ int gnapSequenceId = _sequenceId;
+ int gnapId = _id;
+ int gnapSequenceDatNum = _sequenceDatNum;
+
+ debugC(kDebugBasic, "_gnap->_walkNodesCount: %d", _walkNodesCount);
+
+ for (int index = 0; index < _walkNodesCount; ++index) {
+ _walkNodes[index]._id = index + 20 * _walkNodes[index]._gridY1;
+ if (_walkNodes[index]._deltaX == 1 && _walkNodes[index]._deltaY == 0) {
+ if (index % 2) {
+ _vm->_gameSys->insertSequence(makeRid(datNum, 0x7AB), _walkNodes[index]._id,
+ makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = 0x7AB;
+ gnapSequenceId = 0x7AB;
+ } else {
+ _vm->_gameSys->insertSequence(makeRid(datNum, 0x7AC), _walkNodes[index]._id,
+ makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = 0x7AC;
+ gnapSequenceId = 0x7AC;
+ }
+ } else if (_walkNodes[index]._deltaX == -1 && _walkNodes[index]._deltaY == 0) {
+ if (index % 2) {
+ _vm->_gameSys->insertSequence(makeRid(datNum, 0x7AF), _walkNodes[index]._id,
+ makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = 0x7AF;
+ gnapSequenceId = 0x7AF;
+ } else {
+ _vm->_gameSys->insertSequence(makeRid(datNum, 0x7B0), _walkNodes[index]._id,
+ makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = 0x7B0;
+ gnapSequenceId = 0x7B0;
+ }
+ } else {
+ if (_walkNodes[index]._deltaY == -1)
+ _walkNodes[index]._id -= 10;
+ else
+ _walkNodes[index]._id += 10;
+ int newSequenceId = getWalkSequenceId(_walkNodes[index]._deltaX, _walkNodes[index]._deltaY);
+ _vm->_gameSys->insertSequence(makeRid(datNum, newSequenceId), _walkNodes[index]._id,
+ makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = newSequenceId;
+ gnapSequenceId = newSequenceId;
+ }
+ gnapId = _walkNodes[index]._id;
+ gnapSequenceDatNum = datNum;
+ }
+
+ if (flags & 8) {
+ if (_walkNodesCount > 0) {
+ _sequenceId = gnapSequenceId;
+ _id = gnapId;
+ _idleFacing = getWalkFacing(_walkNodes[_walkNodesCount - 1]._deltaX, _walkNodes[_walkNodesCount - 1]._deltaY);
+ _sequenceDatNum = datNum;
+ if (animationIndex >= 0)
+ _vm->_gameSys->setAnimation(makeRid(_sequenceDatNum, _sequenceId), _id, animationIndex);
+ } else if (animationIndex >= 0) {
+ _vm->_gameSys->setAnimation(0x107D3, 1, animationIndex);
+ _vm->_gameSys->insertSequence(0x107D3, 1, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ } else {
+ if (sequenceId >= 0 && sequenceId != -1) {
+ _sequenceId = ridToEntryIndex(sequenceId);
+ _sequenceDatNum = ridToDatIndex(sequenceId);
+ if (_sequenceId == 0x7B9) {
+ _idleFacing = kDirBottomRight;
+ } else {
+ switch (_sequenceId) {
+ case 0x7BA:
+ _idleFacing = kDirBottomLeft;
+ break;
+ case 0x7BB:
+ _idleFacing = kDirUpRight;
+ break;
+ case 0x7BC:
+ _idleFacing = kDirUpLeft;
+ break;
+ }
+ }
+ } else {
+ if (_walkNodesCount > 0) {
+ _sequenceId = getWalkStopSequenceId(_walkNodes[_walkNodesCount - 1]._deltaX, _walkNodes[_walkNodesCount - 1]._deltaY);
+ _idleFacing = getWalkFacing(_walkNodes[_walkNodesCount - 1]._deltaX, _walkNodes[_walkNodesCount - 1]._deltaY);
+ } else if (gridX >= 0 || gridY >= 0) {
+ switch (_idleFacing) {
+ case kDirBottomRight:
+ _sequenceId = 0x7B9;
+ break;
+ case kDirBottomLeft:
+ _sequenceId = 0x7BA;
+ break;
+ case kDirUpRight:
+ _sequenceId = 0x7BB;
+ break;
+ default:
+ _sequenceId = 0x7BC;
+ break;
+ }
+ } else {
+ int dirX = _vm->_leftClickMouseX - (_vm->_gridMinX + 75 * _pos.x);
+ int dirY = _vm->_leftClickMouseY - (_vm->_gridMinY + 48 * _pos.y);
+ if (dirX == 0)
+ dirX = 1;
+ if (dirY == 0)
+ dirY = 1;
+ _sequenceId = getWalkStopSequenceId(dirX / abs(dirX), dirY / abs(dirY));
+ _idleFacing = getWalkFacing(dirX / abs(dirX), dirY / abs(dirY));
+ }
+ _sequenceDatNum = datNum;
+ }
+
+ if (animationIndex < 0) {
+ _id = 20 * _walkDestY + 1;
+ } else {
+ _id = _walkNodesCount + animationIndex + 20 * _walkDestY;
+ _vm->_gameSys->setAnimation(makeRid(_sequenceDatNum, _sequenceId), _walkNodesCount + animationIndex + 20 * _walkDestY, animationIndex);
+ }
+
+ if (flags & 4) {
+ _vm->_gameSys->insertSequence(makeRid(_sequenceDatNum, _sequenceId), _id,
+ makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId,
+ kSeqScale | kSeqSyncWait, 0, 0, 0);
+ } else {
+ _vm->_gameSys->insertSequence(makeRid(_sequenceDatNum, _sequenceId), _id,
+ makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkDestX - _gridX, 48 * _walkDestY - _gridY);
+ }
+ }
+
+ _pos = Common::Point(_walkDestX, _walkDestY);
+
+ return done;
+}
+
+int PlayerGnap::getShowSequenceId(int index, int gridX, int gridY) {
+ int sequenceId;
+ Facing facing = _idleFacing;
+
+ if (gridY > 0 && gridX > 0) {
+ if (_pos.x > gridX)
+ _idleFacing = kDirUpLeft;
+ else
+ _idleFacing = kDirUpRight;
+ } else if (_idleFacing != kDirBottomRight && _idleFacing != kDirUpRight) {
+ _idleFacing = kDirUpLeft;
+ } else {
+ _idleFacing = kDirUpRight;
+ }
+
+ switch (index) {
+ case 0:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x8A0;
+ else
+ sequenceId = 0x8A1;
+ break;
+ case 1:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x880;
+ else
+ sequenceId = 0x895;
+ break;
+ case 2:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x884;
+ else
+ sequenceId = 0x899;
+ break;
+ //Skip 3
+ case 4:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x881;
+ else
+ sequenceId = 0x896;
+ break;
+ case 5:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x883;
+ else
+ sequenceId = 0x898;
+ break;
+ case 6:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x87E;
+ else
+ sequenceId = 0x893;
+ break;
+ case 7:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x848;
+ else
+ sequenceId = 0x890;
+ break;
+ case 8:
+ case 12:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x87D;
+ else
+ sequenceId = 0x892;
+ break;
+ case 9:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x882;
+ else
+ sequenceId = 0x897;
+ break;
+ case 10:
+ case 11:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x87C;
+ else
+ sequenceId = 0x891;
+ break;
+ case 13:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x888;
+ else
+ sequenceId = 0x89D;
+ break;
+ case 14:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x87F;
+ else
+ sequenceId = 0x894;
+ break;
+ case 15:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x87B;
+ else
+ sequenceId = 0x8A3;
+ break;
+ case 16:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x877;
+ else
+ sequenceId = 0x88C;
+ break;
+ //Skip 17
+ case 18:
+ sequenceId = 0x887;
+ break;
+ case 19:
+ case 25:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x87A;
+ else
+ sequenceId = 0x88F;
+ break;
+ case 20:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x878;
+ else
+ sequenceId = 0x88D;
+ break;
+ case 21:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x879;
+ else
+ sequenceId = 0x88E;
+ break;
+ case 22:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x88A;
+ else
+ sequenceId = 0x89F;
+ break;
+ case 23:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x889;
+ else
+ sequenceId = 0x89E;
+ break;
+ case 24:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x886;
+ else
+ sequenceId = 0x89B;
+ break;
+ //Skip 26
+ //Skip 27
+ //Skip 28
+ //Skip 29
+ default:
+ _idleFacing = facing;
+ sequenceId = getSequenceId(kGSImpossible, Common::Point(0, 0));
+ break;
+ }
+
+ return sequenceId;
+}
+
+void PlayerGnap::idle() {
+ if (_sequenceDatNum == 1 &&
+ (_sequenceId == 0x7A6 || _sequenceId == 0x7AA ||
+ _sequenceId == 0x832 || _sequenceId == 0x841 ||
+ _sequenceId == 0x842 || _sequenceId == 0x8A2 ||
+ _sequenceId == 0x833 || _sequenceId == 0x834 ||
+ _sequenceId == 0x885 || _sequenceId == 0x7A8 ||
+ _sequenceId == 0x831 || _sequenceId == 0x89A)) {
+ _vm->_gameSys->insertSequence(getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncExists, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = getSequenceId(kGSIdle, Common::Point(0, 0));
+ _sequenceDatNum = 1;
+ }
+}
+
+void PlayerGnap::actionIdle(int sequenceId) {
+ if (_sequenceId != -1 && ridToDatIndex(sequenceId) == _sequenceDatNum && ridToEntryIndex(sequenceId) == _sequenceId) {
+ _vm->_gameSys->insertSequence(getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncExists, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = getSequenceId(kGSIdle, Common::Point(0, 0));
+ _sequenceDatNum = 1;
+ }
+}
+
+void PlayerGnap::playImpossible(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSImpossible, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playScratchingHead(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSScratchingHead, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playMoan1(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSMoan1, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playMoan2(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSMoan2, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playBrainPulsating(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSBrainPulsating, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playPullOutDevice(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSPullOutDevice, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playPullOutDeviceNonWorking(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSPullOutDeviceNonWorking, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playUseDevice(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSUseDevice, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playIdle(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSIdle, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playShowItem(int itemIndex, int gridLookX, int gridLookY) {
+ playSequence(getShowSequenceId(itemIndex, gridLookX, gridLookY) | 0x10000);
+}
+
+void PlayerGnap::playShowCurrItem(Common::Point destPos, int gridLookX, int gridLookY) {
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (plat._pos == destPos)
+ plat.makeRoom();
+ walkTo(destPos, -1, -1, 1);
+ playShowItem(_vm->_grabCursorSpriteIndex, gridLookX, gridLookY);
+}
+
+bool PlayerGnap::doPlatypusAction(int gridX, int gridY, int platSequenceId, int callback) {
+ PlayerPlat& plat = *_vm->_plat;
+ bool result = false;
+
+ if (_actionStatus <= -1 && plat._actionStatus <= -1) {
+ _actionStatus = 100;
+ Common::Point checkPt = plat._pos + Common::Point(gridX, gridY);
+ if (_vm->isPointBlocked(checkPt) && (_pos != checkPt)) {
+ plat.walkStep();
+ checkPt = plat._pos + Common::Point(gridX, gridY);
+ }
+
+ if (!_vm->isPointBlocked(checkPt) && (_pos != checkPt)) {
+ walkTo(checkPt, 0, 0x107B9, 1);
+ while (_vm->_gameSys->getAnimationStatus(0) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->doCallback(callback);
+ _vm->gameUpdateTick();
+ }
+ _vm->_gameSys->setAnimation(0, 0, 0);
+ if (_pos == plat._pos + Common::Point(gridX, gridY)) {
+ _vm->_gameSys->setAnimation(platSequenceId, plat._id, 1);
+ plat.playSequence(platSequenceId);
+ while (_vm->_gameSys->getAnimationStatus(1) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->doCallback(callback);
+ _vm->gameUpdateTick();
+ }
+ result = true;
+ }
+ }
+ _actionStatus = -1;
+ }
+ return result;
+}
+
+void PlayerGnap::useDisguiseOnPlatypus() {
+ _vm->_gameSys->setAnimation(0x10846, _id, 0);
+ playSequence(0x10846);
+ while (_vm->_gameSys->getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ _vm->_newSceneNum = 47;
+ _vm->_isLeavingScene = true;
+ _vm->_sceneDone = true;
+ _vm->setFlag(kGFPlatypusDisguised);
+}
+
+/************************************************************************************************/
+
+PlayerPlat::PlayerPlat(GnapEngine * vm) : Character(vm) {}
+
+int PlayerPlat::getSequenceId(int kind, Common::Point gridPos) {
+ // The original had 3 parameters, all always set to 0.
+ // The code to handle the other values has been removed.
+
+ int sequenceId = 0x7CB;
+
+ if (_idleFacing != kDirIdleLeft) {
+ sequenceId = 0x7CC;
+ _idleFacing = kDirIdleRight;
+ }
+
+ return sequenceId | 0x10000;
+}
+
+void PlayerPlat::playSequence(int sequenceId) {
+ _vm->_gameSys->insertSequence(sequenceId, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqScale | kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = ridToEntryIndex(sequenceId);
+ _sequenceDatNum = ridToDatIndex(sequenceId);
+}
+
+void PlayerPlat::updateIdleSequence() {
+ if (_actionStatus < 0 && _vm->_gnap->_actionStatus < 0) {
+ if (_vm->_timers[0] > 0) {
+ if (_vm->_timers[1] == 0) {
+ _vm->_timers[1] = _vm->getRandom(20) + 30;
+ int rnd = _vm->getRandom(10);
+ if (_idleFacing != kDirIdleLeft) {
+ if (rnd != 0 || _sequenceId != 0x7CA) {
+ if (rnd != 1 || _sequenceId != 0x7CA)
+ playSequence(0x107CA);
+ else
+ playSequence(0x10845);
+ } else {
+ playSequence(0x107CC);
+ }
+ } else if (rnd != 0 || _sequenceId != 0x7C9) {
+ if (rnd != 1 || _sequenceId != 0x7C9) {
+ if (rnd != 2 || _sequenceId != 0x7C9)
+ playSequence(0x107C9);
+ else
+ playSequence(0x108A4);
+ } else {
+ playSequence(0x10844);
+ }
+ } else {
+ playSequence(0x107CB);
+ }
+ }
+ } else {
+ _vm->_timers[0] = _vm->getRandom(75) + 75;
+ makeRoom();
+ }
+ } else {
+ _vm->_timers[0] = 100;
+ _vm->_timers[1] = 35;
+ }
+}
+
+void PlayerPlat::updateIdleSequence2() {
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (_actionStatus < 0 && gnap._actionStatus < 0) {
+ if (_vm->_timers[0]) {
+ if (!_vm->_timers[1]) {
+ _vm->_timers[1] = _vm->getRandom(20) + 30;
+ if (_idleFacing != kDirIdleLeft) {
+ if (_vm->getRandom(10) >= 2 || _sequenceId != 0x7CA)
+ playSequence(0x107CA);
+ else
+ playSequence(0x107CC);
+ } else {
+ if (_vm->getRandom(10) >= 2 || _sequenceId != 0x7C9) {
+ playSequence(0x107C9);
+ } else {
+ playSequence(0x107CB);
+ }
+ }
+ }
+ } else {
+ _vm->_timers[0] = _vm->getRandom(75) + 75;
+ makeRoom();
+ }
+ } else {
+ _vm->_timers[0] = 100;
+ _vm->_timers[1] = 35;
+ }
+}
+
+void PlayerPlat::initPos(int gridX, int gridY, Facing facing) {
+ _vm->_timers[0] = 50;
+ _vm->_timers[1] = 20;
+ _pos = Common::Point(gridX, gridY);
+ if (facing == kDirIdleLeft)
+ _idleFacing = kDirIdleLeft;
+ else
+ _idleFacing = facing;
+ if (_idleFacing == kDirIdleRight) {
+ _sequenceId = 0x7D1;
+ } else {
+ _sequenceId = 0x7C1;
+ _idleFacing = kDirIdleLeft;
+ }
+ _id = 20 * _pos.y;
+ _sequenceDatNum = 1;
+ _vm->_gameSys->insertSequence(makeRid(1, _sequenceId), 20 * _pos.y,
+ 0, 0,
+ kSeqScale, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+}
+
+int PlayerPlat::getWalkSequenceId(int deltaX, int deltaY) {
+ static const int walkSequenceIds[9] = {
+ 0x7C5, 0x000, 0x7C8,
+ 0x7C4, 0x000, 0x7C7,
+ 0x7C3, 0x000, 0x7C6
+ };
+
+ int id = 3 * (deltaX + 1) + deltaY + 1;
+ assert(id >= 0 && id < 9);
+
+ return walkSequenceIds[id];
+}
+
+bool PlayerPlat::walkTo(Common::Point gridPos, int animationIndex, int sequenceId, int flags) {
+ // Note: flags is always 1. The code could be simplified.
+
+ int datNum = flags & 3;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ _vm->_timers[1] = 60;
+
+ int gridX = gridPos.x;
+ if (gridX < 0)
+ gridX = (_vm->_leftClickMouseX - _vm->_gridMinX + 37) / 75;
+
+ int gridY = gridPos.y;
+ if (gridY < 0)
+ gridY = (_vm->_leftClickMouseY - _vm->_gridMinY + 24) / 48;
+
+ _walkDestX = CLIP(gridX, 0, _vm->_gridMaxX - 1);
+ _walkDestY = CLIP(gridY, 0, _vm->_gridMaxY - 1);
+
+ if (animationIndex >= 0 && gnap._pos == Common::Point(_walkDestX, _walkDestY))
+ gnap.walkStep();
+
+ bool done = findPath1(_pos.x, _pos.y, 0);
+
+ if (!done)
+ done = findPath2(_pos.x, _pos.y, 0);
+
+ if (!done)
+ done = findPath3(_pos.x, _pos.y);
+
+ if (!done)
+ done = findPath4(_pos.x, _pos.y);
+
+ int platSequenceId = _sequenceId;
+ int platId = _id;
+ int platSequenceDatNum = _sequenceDatNum;
+
+ for (int index = 0; index < _walkNodesCount; ++index) {
+ _walkNodes[index]._id = index + 20 * _walkNodes[index]._gridY1;
+ if (_walkNodes[index]._deltaX == 1 && _walkNodes[index]._deltaY == 0) {
+ if (index % 2) {
+ _vm->_gameSys->insertSequence(makeRid(datNum, 0x7CD), _walkNodes[index]._id,
+ makeRid(platSequenceDatNum, platSequenceId), platId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = 0x7CD;
+ platSequenceId = 0x7CD;
+ } else {
+ _vm->_gameSys->insertSequence(makeRid(datNum, 0x7CE), _walkNodes[index]._id,
+ makeRid(platSequenceDatNum, platSequenceId), platId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = 0x7CE;
+ platSequenceId = 0x7CE;
+ }
+ } else if (_walkNodes[index]._deltaX == -1 && _walkNodes[index]._deltaY == 0) {
+ if (index % 2) {
+ _vm->_gameSys->insertSequence(makeRid(datNum, 0x7CF), _walkNodes[index]._id,
+ makeRid(platSequenceDatNum, platSequenceId), platId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = 0x7CF;
+ platSequenceId = 0x7CF;
+ } else {
+ _vm->_gameSys->insertSequence(makeRid(datNum, 0x7D0), _walkNodes[index]._id,
+ makeRid(platSequenceDatNum, platSequenceId), platId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = 0x7D0;
+ platSequenceId = 0x7D0;
+ }
+ } else {
+ if (_walkNodes[index]._deltaY == -1)
+ _walkNodes[index]._id -= 10;
+ else
+ _walkNodes[index]._id += 10;
+ int newSequenceId = getWalkSequenceId(_walkNodes[index]._deltaX, _walkNodes[index]._deltaY);
+ _vm->_gameSys->insertSequence(makeRid(datNum, newSequenceId), _walkNodes[index]._id,
+ makeRid(platSequenceDatNum, platSequenceId), platId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = newSequenceId;
+ platSequenceId = newSequenceId;
+ }
+ platId = _walkNodes[index]._id;
+ platSequenceDatNum = datNum;
+ }
+
+ if (flags & 8) {
+ if (_walkNodesCount > 0) {
+ _sequenceId = platSequenceId;
+ _id = platId;
+ _sequenceDatNum = datNum;
+ if (_walkNodes[_walkNodesCount - 1]._deltaX > 0)
+ _idleFacing = kDirIdleLeft;
+ else if (_walkNodes[_walkNodesCount - 1]._deltaX < 0)
+ _idleFacing = kDirIdleRight;
+ else if (_walkNodes[_walkNodesCount - 1]._gridX1 % 2)
+ _idleFacing = kDirIdleRight;
+ else
+ _idleFacing = kDirIdleLeft;
+ if (animationIndex >= 0)
+ _vm->_gameSys->setAnimation(makeRid(_sequenceDatNum, _sequenceId), _id, animationIndex);
+ } else if (animationIndex >= 0) {
+ _vm->_gameSys->setAnimation(0x107D3, 1, animationIndex);
+ _vm->_gameSys->insertSequence(0x107D3, 1, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ } else {
+ if (sequenceId >= 0 && sequenceId != -1) {
+ _sequenceId = ridToEntryIndex(sequenceId);
+ _sequenceDatNum = ridToDatIndex(sequenceId);
+ if (_sequenceId == 0x7C2) {
+ _idleFacing = kDirIdleLeft;
+ } else if (_sequenceId == 0x7D2) {
+ _idleFacing = kDirIdleRight;
+ }
+ } else {
+ if (_walkNodesCount > 0) {
+ if (_walkNodes[_walkNodesCount - 1]._deltaX > 0) {
+ _sequenceId = 0x7C2;
+ _idleFacing = kDirIdleLeft;
+ } else if (_walkNodes[_walkNodesCount - 1]._deltaX < 0) {
+ _sequenceId = 0x7D2;
+ _idleFacing = kDirIdleRight;
+ } else if (_walkNodes[0]._deltaX > 0) {
+ _sequenceId = 0x7C2;
+ _idleFacing = kDirIdleLeft;
+ } else if (_walkNodes[0]._deltaX < 0) {
+ _sequenceId = 0x7D2;
+ _idleFacing = kDirIdleRight;
+ } else {
+ _sequenceId = 0x7D2;
+ _idleFacing = kDirIdleRight;
+ }
+ } else if (_idleFacing != kDirIdleLeft) {
+ _sequenceId = 0x7D2;
+ } else {
+ _sequenceId = 0x7C2;
+ }
+ _sequenceDatNum = datNum;
+ }
+
+ if (animationIndex < 0) {
+ _id = 20 * _walkDestY;
+ } else {
+ _id = animationIndex + 20 * _walkDestY;
+ _vm->_gameSys->setAnimation(makeRid(_sequenceDatNum, _sequenceId), animationIndex + 20 * _walkDestY, animationIndex);
+ }
+
+ if (flags & 4)
+ _vm->_gameSys->insertSequence(makeRid(_sequenceDatNum, _sequenceId), _id,
+ makeRid(platSequenceDatNum, platSequenceId), platId,
+ 9, 0, 0, 0);
+ else
+ _vm->_gameSys->insertSequence(makeRid(_sequenceDatNum, _sequenceId), _id,
+ makeRid(platSequenceDatNum, platSequenceId), platId,
+ 9, 0, 75 * _walkDestX - _gridX, 48 * _walkDestY - _gridY);
+ }
+
+ _pos = Common::Point(_walkDestX, _walkDestY);
+
+ return done;
+}
+} // End of namespace Gnap
diff --git a/engines/gnap/character.h b/engines/gnap/character.h
new file mode 100644
index 0000000000..27e98be15c
--- /dev/null
+++ b/engines/gnap/character.h
@@ -0,0 +1,146 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 GNAP_CHARACTER_H
+#define GNAP_CHARACTER_H
+
+namespace Gnap {
+
+class GnapEngine;
+
+enum Facing {
+ kDirIdleLeft = 0,
+ kDirBottomRight = 1,
+ kDirBottomLeft = 3,
+ kDirIdleRight = 4,
+ kDirUpLeft = 5,
+ kDirUpRight = 7
+};
+
+struct GridStruct {
+ int _deltaX, _deltaY;
+ int _gridX1, _gridY1;
+ int _sequenceId;
+ int _id;
+};
+
+const int kMaxGridStructs = 30;
+
+class Character {
+public:
+ Character(GnapEngine *vm);
+ virtual ~Character();
+
+ void walkStep();
+
+ virtual int getSequenceId(int kind, Common::Point gridPos) = 0;
+ virtual void playSequence(int sequenceId) = 0;
+ virtual void updateIdleSequence() = 0;
+ virtual void updateIdleSequence2() = 0;
+ virtual void initPos(int gridX, int gridY, Facing facing) = 0;
+ virtual int getWalkSequenceId(int deltaX, int deltaY) = 0;
+ virtual bool walkTo(Common::Point gridPos, int animationIndex, int sequenceId, int flags) = 0;
+
+ Common::Point _pos;
+ Facing _idleFacing;
+ int _actionStatus;
+ int _sequenceId;
+ int _sequenceDatNum;
+ int _id;
+ int _gridX;
+ int _gridY;
+ int _walkNodesCount;
+ GridStruct _walkNodes[kMaxGridStructs];
+ int _walkDestX, _walkDestY;
+ int _walkDeltaX, _walkDeltaY, _walkDirX, _walkDirY, _walkDirXIncr, _walkDirYIncr;
+
+protected:
+ GnapEngine *_vm;
+};
+
+class PlayerGnap : public Character {
+public:
+ PlayerGnap(GnapEngine *vm);
+ virtual int getSequenceId(int kind, Common::Point gridPos);
+ virtual void initPos(int gridX, int gridY, Facing facing);
+ virtual void playSequence(int sequenceId);
+ virtual void updateIdleSequence();
+ virtual void updateIdleSequence2();
+ virtual int getWalkSequenceId(int deltaX, int deltaY);
+ virtual bool walkTo(Common::Point gridPos, int animationIndex, int sequenceId, int flags);
+
+ void actionIdle(int sequenceId);
+ bool doPlatypusAction(int gridX, int gridY, int platSequenceId, int callback);
+ int getShowSequenceId(int index, int gridX, int gridY);
+ Facing getWalkFacing(int deltaX, int deltaY);
+ int getWalkStopSequenceId(int deltaX, int deltaY);
+ void idle();
+ void initBrainPulseRndValue();
+ void kissPlatypus(int callback);
+ void playBrainPulsating(Common::Point gridPos = Common::Point(0, 0));
+ void playIdle(Common::Point gridPos = Common::Point(0, 0));
+ void playImpossible(Common::Point gridPos = Common::Point(0, 0));
+ void playMoan1(Common::Point gridPos = Common::Point(0, 0));
+ void playMoan2(Common::Point gridPos = Common::Point(0, 0));
+ void playPullOutDevice(Common::Point gridPos = Common::Point(0, 0));
+ void playPullOutDeviceNonWorking(Common::Point gridPos = Common::Point(0, 0));
+ void playScratchingHead(Common::Point gridPos = Common::Point(0, 0));
+ void playShowCurrItem(Common::Point destPos, int gridLookX, int gridLookY);
+ void playShowItem(int itemIndex, int gridLookX, int gridLookY);
+ void playUseDevice(Common::Point gridPos = Common::Point(0, 0));
+ void useDeviceOnPlatypus();
+ void useDisguiseOnPlatypus();
+ void useJointOnPlatypus();
+
+ int _brainPulseNum;
+ int _brainPulseRndValue;
+
+private:
+ bool findPath1(int gridX, int gridY, int index);
+ bool findPath2(int gridX, int gridY, int index);
+ bool findPath3(int gridX, int gridY);
+ bool findPath4(int gridX, int gridY);
+};
+
+class PlayerPlat : public Character {
+public:
+ PlayerPlat(GnapEngine *vm);
+ virtual ~PlayerPlat() {}
+ virtual int getSequenceId(int kind = 0, Common::Point gridPos = Common::Point(0, 0));
+ virtual void initPos(int gridX, int gridY, Facing facing);
+ virtual void playSequence(int sequenceId);
+ virtual void updateIdleSequence();
+ virtual void updateIdleSequence2();
+ virtual int getWalkSequenceId(int deltaX, int deltaY);
+ virtual bool walkTo(Common::Point gridPos, int animationIndex, int sequenceId, int flags);
+
+ void makeRoom();
+
+private:
+ bool findPath1(int gridX, int gridY, int index);
+ bool findPath2(int gridX, int gridY, int index);
+ bool findPath3(int gridX, int gridY);
+ bool findPath4(int gridX, int gridY);
+};
+} // End of namespace Gnap
+
+#endif // GNAP_CHARACTER_H
diff --git a/engines/gnap/configure.engine b/engines/gnap/configure.engine
new file mode 100644
index 0000000000..7aa538fd2c
--- /dev/null
+++ b/engines/gnap/configure.engine
@@ -0,0 +1,3 @@
+# This file is included from the main "configure" script
+# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
+add_engine gnap "UFOs" no
diff --git a/engines/gnap/datarchive.cpp b/engines/gnap/datarchive.cpp
new file mode 100644
index 0000000000..c74766bd03
--- /dev/null
+++ b/engines/gnap/datarchive.cpp
@@ -0,0 +1,124 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/dcl.h"
+#include "common/file.h"
+#include "common/stream.h"
+#include "common/substream.h"
+
+#include "gnap/gnap.h"
+#include "gnap/datarchive.h"
+
+#include "engines/util.h"
+
+namespace Gnap {
+
+// DatArchive
+
+DatArchive::DatArchive(const char *filename) {
+ _fd = new Common::File();
+ if (!_fd->open(filename))
+ error("DatArchive::DatArchive() Could not open %s", filename);
+ _fd->skip(8); // Skip signature
+ _fd->skip(2); // Skip unknown
+ _fd->skip(2); // Skip unknown
+ _entriesCount = _fd->readUint32LE();
+ debugC(kDebugBasic, "_entriesCount: %d", _entriesCount);
+ _fd->skip(4); // Skip unknown
+ _entries = new DatEntry[_entriesCount];
+ for (int i = 0; i < _entriesCount; ++i) {
+ _entries[i]._ofs = _fd->readUint32LE();
+ _entries[i]._outSize1 = _fd->readUint32LE();
+ _entries[i]._type = _fd->readUint32LE();
+ _entries[i]._outSize2 = _fd->readUint32LE();
+ }
+}
+
+DatArchive::~DatArchive() {
+ _fd->close();
+ delete _fd;
+ delete[] _entries;
+}
+
+byte *DatArchive::load(int index) {
+ _fd->seek(_entries[index]._ofs);
+ debugC(kDebugBasic, "_entries[index].outSize2: %d; _entries[index].outSize1: %d", _entries[index]._outSize2, _entries[index]._outSize1);
+ byte *buffer = new byte[_entries[index]._outSize1];
+ if (!Common::decompressDCL(_fd, buffer, _entries[index]._outSize2, _entries[index]._outSize1))
+ error("DatArchive::load() Error during decompression of entry %d", index);
+ return buffer;
+}
+
+// DatManager
+
+DatManager::DatManager() {
+ for (int i = 0; i < kMaxDatArchives; ++i)
+ _datArchives[i] = nullptr;
+}
+
+DatManager::~DatManager() {
+ for (int i = 0; i < kMaxDatArchives; ++i)
+ delete _datArchives[i];
+}
+
+void DatManager::open(int index, const char *filename) {
+ close(index);
+ _datArchives[index] = new DatArchive(filename);
+ warning("Loading %s - %d", filename, index);
+}
+
+void DatManager::close(int index) {
+ delete _datArchives[index];
+ _datArchives[index] = nullptr;
+}
+
+byte *DatManager::loadResource(int resourceId) {
+ const int datIndex = ridToDatIndex(resourceId);
+ const int entryIndex = ridToEntryIndex(resourceId);
+ return _datArchives[datIndex] ? _datArchives[datIndex]->load(entryIndex) : 0;
+}
+
+uint32 DatManager::getResourceType(int resourceId) {
+ const int datIndex = ridToDatIndex(resourceId);
+ const int entryIndex = ridToEntryIndex(resourceId);
+ return _datArchives[datIndex] ? _datArchives[datIndex]->getEntryType(entryIndex) : 0;
+}
+
+uint32 DatManager::getResourceSize(int resourceId) {
+ const int datIndex = ridToDatIndex(resourceId);
+ const int entryIndex = ridToEntryIndex(resourceId);
+ return _datArchives[datIndex] ? _datArchives[datIndex]->getEntrySize(entryIndex) : 0;
+}
+
+int ridToDatIndex(int resourceId) {
+ return (resourceId & 0xFFFF0000) >> 16;
+}
+
+int ridToEntryIndex(int resourceId) {
+ return resourceId & 0xFFFF;
+}
+
+int makeRid(int datIndex, int entryIndex) {
+ return (datIndex << 16) | entryIndex;
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/datarchive.h b/engines/gnap/datarchive.h
new file mode 100644
index 0000000000..e9220f8e6f
--- /dev/null
+++ b/engines/gnap/datarchive.h
@@ -0,0 +1,80 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GNAP_DATARCHIVE_H
+#define GNAP_DATARCHIVE_H
+
+#include "common/array.h"
+#include "common/events.h"
+#include "common/file.h"
+#include "common/memstream.h"
+#include "common/random.h"
+#include "common/str.h"
+#include "common/substream.h"
+#include "common/system.h"
+#include "engines/engine.h"
+
+namespace Gnap {
+
+struct DatEntry {
+ uint32 _ofs;
+ uint32 _outSize1;
+ uint32 _type;
+ uint32 _outSize2;
+};
+
+class DatArchive {
+public:
+ DatArchive(const char *filename);
+ ~DatArchive();
+ byte *load(int index);
+ int getCount() const { return _entriesCount; }
+ uint32 getEntryType(int index) { return _entries[index]._type; }
+ uint32 getEntrySize(int index) { return _entries[index]._outSize1; }
+protected:
+ Common::File *_fd;
+ int _entriesCount;
+ DatEntry *_entries;
+};
+
+const int kMaxDatArchives = 2;
+
+class DatManager {
+public:
+ DatManager();
+ ~DatManager();
+ void open(int index, const char *filename);
+ void close(int index);
+ byte *loadResource(int resourceId);
+ uint32 getResourceType(int resourceId);
+ uint32 getResourceSize(int resourceId);
+protected:
+ DatArchive *_datArchives[kMaxDatArchives];
+};
+
+int ridToDatIndex(int resourceId);
+int ridToEntryIndex(int resourceId);
+int makeRid(int datIndex, int entryIndex);
+
+} // End of namespace Gnap
+
+#endif // GNAP_DATARCHIVE_H
diff --git a/engines/gnap/debugger.cpp b/engines/gnap/debugger.cpp
new file mode 100644
index 0000000000..07f3f6714c
--- /dev/null
+++ b/engines/gnap/debugger.cpp
@@ -0,0 +1,42 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "gnap/debugger.h"
+#include "gnap/gnap.h"
+
+namespace Gnap {
+
+Debugger::Debugger(GnapEngine *vm) : GUI::Debugger(), _vm(vm) {
+ // Register methods
+ registerCmd("hotspots", WRAP_METHOD(Debugger, Cmd_Hotspots));
+
+ // Set fields
+ _showHotspotNumber = false;
+}
+
+bool Debugger::Cmd_Hotspots(int argc, const char **argv) {
+ _showHotspotNumber ^= 1;
+
+ return true;
+}
+
+} // End of namespace Gnap
diff --git a/engines/scumm/he/logic/moonbase.cpp b/engines/gnap/debugger.h
index 29a0dde7a2..ac83cc5504 100644
--- a/engines/scumm/he/logic/moonbase.cpp
+++ b/engines/gnap/debugger.h
@@ -20,33 +20,35 @@
*
*/
-#include "scumm/he/intern_he.h"
-#include "scumm/he/logic_he.h"
+#ifndef GNAP_DEBUGGER_H
+#define GNAP_DEBUGGER_H
-namespace Scumm {
+#include "common/scummsys.h"
+#include "gui/debugger.h"
-/**
- * Logic code for:
- * Moonbase Commander
- */
-class LogicHEmoonbase : public LogicHE {
+namespace Gnap {
+
+class GnapEngine;
+
+class Debugger : public GUI::Debugger {
+private:
+ GnapEngine *_vm;
public:
- LogicHEmoonbase(ScummEngine_v90he *vm) : LogicHE(vm) {}
+ /*
+ * Specifies whether to show the hotspot IDs
+ */
+ bool _showHotspotNumber;
+protected:
+ /**
+ * List the active hotspots during the current time period
+ */
+ bool Cmd_Hotspots(int argc, const char **argv);
- int versionID();
+public:
+ Debugger(GnapEngine *vm);
+ virtual ~Debugger() {}
};
-int LogicHEmoonbase::versionID() {
- if (_vm->_game.features & GF_DEMO)
- return -100;
- else if (strcmp(_vm->_game.variant, "1.1") == 0)
- return 110;
- else
- return 100;
-}
-
-LogicHE *makeLogicHEmoonbase(ScummEngine_v90he *vm) {
- return new LogicHEmoonbase(vm);
-}
+} // End of namespace Gnap
-} // End of namespace Scumm
+#endif
diff --git a/engines/gnap/detection.cpp b/engines/gnap/detection.cpp
new file mode 100644
index 0000000000..a7e9eece4a
--- /dev/null
+++ b/engines/gnap/detection.cpp
@@ -0,0 +1,197 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "gnap/gnap.h"
+
+#include "common/config-manager.h"
+#include "engines/advancedDetector.h"
+#include "common/savefile.h"
+#include "common/system.h"
+#include "base/plugins.h"
+#include "graphics/thumbnail.h"
+
+static const PlainGameDescriptor gnapGames[] = {
+ { "gnap", "Gnap" },
+ { 0, 0 }
+};
+
+namespace Gnap {
+
+static const ADGameDescription gameDescriptions[] = {
+ {
+ "gnap", "",
+ {
+ {"stock_n.dat", 0, "46819043d019a2f36b727cc2bdd6980f", 12515823},
+ AD_LISTEND
+ },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO0()
+ },
+ {
+ "gnap", "",
+ {
+ {"stock_n.dat", 0, "46819043d019a2f36b727cc2bdd6980f", 12995485},
+ AD_LISTEND
+ },
+ Common::RU_RUS, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO0()
+ },
+
+ AD_TABLE_END_MARKER
+};
+
+} // End of namespace Gnap
+
+class GnapMetaEngine : public AdvancedMetaEngine {
+public:
+ GnapMetaEngine() : AdvancedMetaEngine(Gnap::gameDescriptions, sizeof(ADGameDescription), gnapGames) {
+ _singleId = "gnap";
+ _maxScanDepth = 3;
+ }
+
+ virtual const char *getName() const {
+ return "Gnap";
+ }
+
+ virtual const char *getOriginalCopyright() const {
+ return "Gnap (C) Artech Digital Entertainment 1997";
+ }
+
+ virtual bool hasFeature(MetaEngineFeature f) const;
+ virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+ virtual int getMaximumSaveSlot() const;
+ virtual SaveStateList listSaves(const char *target) const;
+ SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
+ virtual void removeSaveState(const char *target, int slot) const;
+};
+
+bool GnapMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsListSaves) ||
+ (f == kSupportsLoadingDuringStartup) ||
+ (f == kSupportsDeleteSave) ||
+ (f == kSavesSupportMetaInfo) ||
+ (f == kSavesSupportThumbnail) ||
+ (f == kSavesSupportCreationDate);
+}
+
+bool Gnap::GnapEngine::hasFeature(EngineFeature f) const {
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime);
+}
+
+void GnapMetaEngine::removeSaveState(const char *target, int slot) const {
+ Common::String fileName = Common::String::format("%s.%03d", target, slot);
+ g_system->getSavefileManager()->removeSavefile(fileName);
+}
+
+int GnapMetaEngine::getMaximumSaveSlot() const { return 99; }
+
+SaveStateList GnapMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringArray filenames;
+ Common::String saveDesc;
+ Common::String pattern = Common::String::format("%s.0##", target);
+ Gnap::GnapSavegameHeader header;
+
+ filenames = saveFileMan->listSavefiles(pattern);
+
+ SaveStateList saveList;
+ for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
+ const char *ext = strrchr(file->c_str(), '.');
+ int slot = ext ? atoi(ext + 1) : -1;
+
+ if (slot >= 0 && slot < getMaximumSaveSlot()) {
+ Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file);
+
+ if (in) {
+ Gnap::GnapEngine::readSavegameHeader(in, header);
+ saveList.push_back(SaveStateDescriptor(slot, header._saveName));
+
+ if (header._thumbnail) {
+ header._thumbnail->free();
+ delete header._thumbnail;
+ }
+ delete in;
+ }
+ }
+ }
+
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
+ return saveList;
+}
+
+SaveStateDescriptor GnapMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+ Common::String fileName = Common::String::format("%s.%03d", target, slot);
+ Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(fileName);
+ if (file) {
+ char saveIdentBuffer[5];
+ file->read(saveIdentBuffer, 5);
+
+ int32 version = file->readByte();
+ if (version > GNAP_SAVEGAME_VERSION) {
+ delete file;
+ return SaveStateDescriptor();
+ }
+
+ char saveName[256];
+ char ch;
+ int i = 0;
+ while ((ch = (char)file->readByte()) != '\0')
+ saveName[i++] = ch;
+
+ SaveStateDescriptor desc(slot, saveName);
+
+ if (version != 1) {
+ Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*file);
+ desc.setThumbnail(thumbnail);
+ }
+
+ int year = file->readSint16LE();
+ int month = file->readSint16LE();
+ int day = file->readSint16LE();
+ int hour = file->readSint16LE();
+ int minutes = file->readSint16LE();
+
+ desc.setSaveDate(year, month, day);
+ desc.setSaveTime(hour, minutes);
+
+ delete file;
+ return desc;
+ }
+
+ return SaveStateDescriptor();
+}
+
+bool GnapMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
+ if (desc) {
+ *engine = new Gnap::GnapEngine(syst, desc);
+ }
+ return desc != 0;
+}
+
+#if PLUGIN_ENABLED_DYNAMIC(GNAP)
+ REGISTER_PLUGIN_DYNAMIC(GNAP, PLUGIN_TYPE_ENGINE, GnapMetaEngine);
+#else
+ REGISTER_PLUGIN_STATIC(GNAP, PLUGIN_TYPE_ENGINE, GnapMetaEngine);
+#endif
diff --git a/engines/gnap/fontdata.h b/engines/gnap/fontdata.h
new file mode 100644
index 0000000000..ef39df960e
--- /dev/null
+++ b/engines/gnap/fontdata.h
@@ -0,0 +1,849 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 GNAP_FONTDATA_H
+#define GNAP_FONTDATA_H
+
+namespace Gnap {
+
+struct FONT_CHAR_INFO {
+ const byte _width; // width, in bits (or pixels), of the character
+ const uint16 _offset; // offset of the character's bitmap, in bytes, into the the FONT_INFO's data array
+};
+
+/*
+** Font data for DejaVu Sans 9pt
+*/
+
+/* Character bitmaps for DejaVu Sans 9pt */
+const byte _dejaVuSans9ptCharBitmaps[] = {
+ /* @0 ' ' (5 pixels wide) */
+ 0x00, 0x00, /* */
+ 0x00, 0x00, /* */
+ 0x00, 0x00, /* */
+ 0x00, 0x00, /* */
+ 0x00, 0x00, /* */
+
+ /* @10 '!' (1 pixels wide) */
+ 0x1B, 0xF0, /* ## ###### */
+
+ /* @12 '"' (3 pixels wide) */
+ 0x00, 0x70, /* ### */
+ 0x00, 0x00, /* */
+ 0x00, 0x70, /* ### */
+
+ /* @18 '#' (8 pixels wide) */
+ 0x04, 0x00, /* # */
+ 0x14, 0x80, /* # # # */
+ 0x0F, 0x80, /* ##### */
+ 0x04, 0xE0, /* # ### */
+ 0x1C, 0x80, /* ### # */
+ 0x07, 0xC0, /* ##### */
+ 0x04, 0xA0, /* # # # */
+ 0x00, 0x80, /* # */
+
+ /* @34 '$' (5 pixels wide) */
+ 0x09, 0xC0, /* # ### */
+ 0x11, 0x20, /* # # # */
+ 0x7F, 0xF0, /* ########### */
+ 0x12, 0x20, /* # # # */
+ 0x0E, 0x40, /* ### # */
+
+ /* @44 '%' (10 pixels wide) */
+ 0x00, 0xE0, /* ### */
+ 0x01, 0x10, /* # # */
+ 0x11, 0x10, /* # # # */
+ 0x0C, 0xE0, /* ## ### */
+ 0x03, 0x00, /* ## */
+ 0x01, 0x80, /* ## */
+ 0x0E, 0x60, /* ### ## */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x00, /* # # */
+ 0x0E, 0x00, /* ### */
+
+ /* @64 '&' (8 pixels wide) */
+ 0x0E, 0x00, /* ### */
+ 0x19, 0xE0, /* ## #### */
+ 0x10, 0x90, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x12, 0x20, /* # # # */
+ 0x0C, 0x00, /* ## */
+ 0x14, 0x00, /* # # */
+ 0x13, 0x00, /* # ## */
+
+ /* @80 ''' (1 pixels wide) */
+ 0x00, 0x70, /* ### */
+
+ /* @82 '(' (3 pixels wide) */
+ 0x07, 0xC0, /* ##### */
+ 0x38, 0x38, /* ### ### */
+ 0x20, 0x08, /* # # */
+
+ /* @88 ')' (3 pixels wide) */
+ 0x20, 0x08, /* # # */
+ 0x38, 0x38, /* ### ### */
+ 0x07, 0xC0, /* ##### */
+
+ /* @94 '*' (5 pixels wide) */
+ 0x01, 0x20, /* # # */
+ 0x00, 0xC0, /* ## */
+ 0x03, 0xF0, /* ###### */
+ 0x00, 0xC0, /* ## */
+ 0x01, 0x20, /* # # */
+
+ /* @104 '+' (7 pixels wide) */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x1F, 0xC0, /* ####### */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+
+ /* @118 ',' (1 pixels wide) */
+ 0x38, 0x00, /* ### */
+
+ /* @120 '-' (3 pixels wide) */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+
+ /* @126 '.' (1 pixels wide) */
+ 0x18, 0x00, /* ## */
+
+ /* @128 '/' (4 pixels wide) */
+ 0x30, 0x00, /* ## */
+ 0x0E, 0x00, /* ### */
+ 0x01, 0xC0, /* ### */
+ 0x00, 0x30, /* ## */
+
+ /* @136 '0' (6 pixels wide) */
+ 0x07, 0xC0, /* ##### */
+ 0x18, 0x30, /* ## ## */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x18, 0x30, /* ## ## */
+ 0x07, 0xC0, /* ##### */
+
+ /* @148 '1' (5 pixels wide) */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x1F, 0xF0, /* ######### */
+ 0x10, 0x00, /* # */
+ 0x10, 0x00, /* # */
+
+ /* @158 '2' (6 pixels wide) */
+ 0x10, 0x20, /* # # */
+ 0x18, 0x10, /* ## # */
+ 0x14, 0x10, /* # # # */
+ 0x12, 0x10, /* # # # */
+ 0x11, 0x30, /* # # ## */
+ 0x10, 0xE0, /* # ### */
+
+ /* @170 '3' (6 pixels wide) */
+ 0x08, 0x20, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x0E, 0xE0, /* ### ### */
+
+ /* @182 '4' (6 pixels wide) */
+ 0x06, 0x00, /* ## */
+ 0x05, 0x80, /* # ## */
+ 0x04, 0x40, /* # # */
+ 0x04, 0x30, /* # ## */
+ 0x1F, 0xF0, /* ######### */
+ 0x04, 0x00, /* # */
+
+ /* @194 '5' (6 pixels wide) */
+ 0x08, 0xF0, /* # #### */
+ 0x10, 0x90, /* # # # */
+ 0x10, 0x90, /* # # # */
+ 0x10, 0x90, /* # # # */
+ 0x19, 0x90, /* ## ## # */
+ 0x0F, 0x00, /* #### */
+
+ /* @206 '6' (6 pixels wide) */
+ 0x07, 0xC0, /* ##### */
+ 0x19, 0x20, /* ## # # */
+ 0x10, 0x90, /* # # # */
+ 0x10, 0x90, /* # # # */
+ 0x19, 0x90, /* ## ## # */
+ 0x0F, 0x20, /* #### # */
+
+ /* @218 '7' (6 pixels wide) */
+ 0x00, 0x10, /* # */
+ 0x10, 0x10, /* # # */
+ 0x0C, 0x10, /* ## # */
+ 0x03, 0x10, /* ## # */
+ 0x00, 0xD0, /* ## # */
+ 0x00, 0x30, /* ## */
+
+ /* @230 '8' (6 pixels wide) */
+ 0x0E, 0xE0, /* ### ### */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x0E, 0xE0, /* ### ### */
+
+ /* @242 '9' (6 pixels wide) */
+ 0x09, 0xE0, /* # #### */
+ 0x13, 0x30, /* # ## ## */
+ 0x12, 0x10, /* # # # */
+ 0x12, 0x10, /* # # # */
+ 0x09, 0x30, /* # # ## */
+ 0x07, 0xC0, /* ##### */
+
+ /* @254 ':' (1 pixels wide) */
+ 0x19, 0x80, /* ## ## */
+
+ /* @256 ';' (1 pixels wide) */
+ 0x39, 0x80, /* ### ## */
+
+ /* @258 '<' (8 pixels wide) */
+ 0x03, 0x00, /* ## */
+ 0x03, 0x00, /* ## */
+ 0x03, 0x00, /* ## */
+ 0x04, 0x80, /* # # */
+ 0x04, 0x80, /* # # */
+ 0x04, 0x80, /* # # */
+ 0x0C, 0xC0, /* ## ## */
+ 0x08, 0x40, /* # # */
+
+ /* @274 '=' (8 pixels wide) */
+ 0x05, 0x00, /* # # */
+ 0x05, 0x00, /* # # */
+ 0x05, 0x00, /* # # */
+ 0x05, 0x00, /* # # */
+ 0x05, 0x00, /* # # */
+ 0x05, 0x00, /* # # */
+ 0x05, 0x00, /* # # */
+ 0x05, 0x00, /* # # */
+
+ /* @290 '>' (8 pixels wide) */
+ 0x08, 0x40, /* # # */
+ 0x0C, 0xC0, /* ## ## */
+ 0x04, 0x80, /* # # */
+ 0x04, 0x80, /* # # */
+ 0x04, 0x80, /* # # */
+ 0x03, 0x00, /* ## */
+ 0x03, 0x00, /* ## */
+ 0x03, 0x00, /* ## */
+
+ /* @306 '?' (5 pixels wide) */
+ 0x00, 0x20, /* # */
+ 0x00, 0x10, /* # */
+ 0x1B, 0x10, /* ## ## # */
+ 0x00, 0x90, /* # # */
+ 0x00, 0x60, /* ## */
+
+ /* @316 '@' (11 pixels wide) */
+ 0x0F, 0x80, /* ##### */
+ 0x10, 0x40, /* # # */
+ 0x20, 0x20, /* # # */
+ 0x47, 0x10, /* # ### # */
+ 0x48, 0x90, /* # # # # */
+ 0x48, 0x90, /* # # # # */
+ 0x48, 0x90, /* # # # # */
+ 0x4F, 0x90, /* # ##### # */
+ 0x28, 0x20, /* # # # */
+ 0x04, 0x60, /* # ## */
+ 0x03, 0x80, /* ### */
+
+ /* @338 'A' (8 pixels wide) */
+ 0x10, 0x00, /* # */
+ 0x0E, 0x00, /* ### */
+ 0x05, 0xC0, /* # ### */
+ 0x04, 0x30, /* # ## */
+ 0x04, 0x30, /* # ## */
+ 0x05, 0xC0, /* # ### */
+ 0x0E, 0x00, /* ### */
+ 0x10, 0x00, /* # */
+
+ /* @354 'B' (6 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x0E, 0xE0, /* ### ### */
+
+ /* @366 'C' (6 pixels wide) */
+ 0x07, 0xC0, /* ##### */
+ 0x08, 0x20, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x08, 0x20, /* # # */
+
+ /* @378 'D' (7 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x08, 0x20, /* # # */
+ 0x07, 0xC0, /* ##### */
+
+ /* @392 'E' (6 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+
+ /* @404 'F' (5 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x01, 0x10, /* # # */
+ 0x01, 0x10, /* # # */
+ 0x01, 0x10, /* # # */
+ 0x01, 0x10, /* # # */
+
+ /* @414 'G' (7 pixels wide) */
+ 0x07, 0xC0, /* ##### */
+ 0x08, 0x20, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x0F, 0x20, /* #### # */
+
+ /* @428 'H' (7 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x01, 0x00, /* # */
+ 0x01, 0x00, /* # */
+ 0x01, 0x00, /* # */
+ 0x01, 0x00, /* # */
+ 0x01, 0x00, /* # */
+ 0x1F, 0xF0, /* ######### */
+
+ /* @442 'I' (1 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+
+ /* @444 'J' (3 pixels wide) */
+ 0x40, 0x00, /* # */
+ 0x40, 0x00, /* # */
+ 0x3F, 0xF0, /* ########## */
+
+ /* @450 'K' (6 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x01, 0x00, /* # */
+ 0x02, 0x80, /* # # */
+ 0x04, 0x40, /* # # */
+ 0x08, 0x20, /* # # */
+ 0x10, 0x10, /* # # */
+
+ /* @462 'L' (5 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x10, 0x00, /* # */
+ 0x10, 0x00, /* # */
+ 0x10, 0x00, /* # */
+ 0x10, 0x00, /* # */
+
+ /* @472 'M' (8 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x00, 0x60, /* ## */
+ 0x01, 0x80, /* ## */
+ 0x06, 0x00, /* ## */
+ 0x06, 0x00, /* ## */
+ 0x01, 0x80, /* ## */
+ 0x00, 0x60, /* ## */
+ 0x1F, 0xF0, /* ######### */
+
+ /* @488 'N' (7 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x00, 0x30, /* ## */
+ 0x00, 0xC0, /* ## */
+ 0x01, 0x00, /* # */
+ 0x06, 0x00, /* ## */
+ 0x18, 0x00, /* ## */
+ 0x1F, 0xF0, /* ######### */
+
+ /* @502 'O' (7 pixels wide) */
+ 0x07, 0xC0, /* ##### */
+ 0x08, 0x20, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x08, 0x20, /* # # */
+ 0x07, 0xC0, /* ##### */
+
+ /* @516 'P' (6 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x01, 0x10, /* # # */
+ 0x01, 0x10, /* # # */
+ 0x01, 0x10, /* # # */
+ 0x01, 0x10, /* # # */
+ 0x00, 0xE0, /* ### */
+
+ /* @528 'Q' (7 pixels wide) */
+ 0x07, 0xC0, /* ##### */
+ 0x08, 0x20, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x30, 0x10, /* ## # */
+ 0x48, 0x20, /* # # # */
+ 0x07, 0xC0, /* ##### */
+
+ /* @542 'R' (7 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x01, 0x10, /* # # */
+ 0x01, 0x10, /* # # */
+ 0x01, 0x10, /* # # */
+ 0x03, 0x10, /* ## # */
+ 0x0C, 0xE0, /* ## ### */
+ 0x10, 0x00, /* # */
+
+ /* @556 'S' (6 pixels wide) */
+ 0x08, 0xE0, /* # ### */
+ 0x11, 0x90, /* # ## # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x0E, 0x20, /* ### # */
+
+ /* @568 'T' (7 pixels wide) */
+ 0x00, 0x10, /* # */
+ 0x00, 0x10, /* # */
+ 0x00, 0x10, /* # */
+ 0x1F, 0xF0, /* ######### */
+ 0x00, 0x10, /* # */
+ 0x00, 0x10, /* # */
+ 0x00, 0x10, /* # */
+
+ /* @582 'U' (7 pixels wide) */
+ 0x0F, 0xF0, /* ######## */
+ 0x18, 0x00, /* ## */
+ 0x10, 0x00, /* # */
+ 0x10, 0x00, /* # */
+ 0x10, 0x00, /* # */
+ 0x18, 0x00, /* ## */
+ 0x0F, 0xF0, /* ######## */
+
+ /* @596 'V' (8 pixels wide) */
+ 0x00, 0x30, /* ## */
+ 0x01, 0xC0, /* ### */
+ 0x06, 0x00, /* ## */
+ 0x18, 0x00, /* ## */
+ 0x18, 0x00, /* ## */
+ 0x06, 0x00, /* ## */
+ 0x01, 0xC0, /* ### */
+ 0x00, 0x30, /* ## */
+
+ /* @612 'W' (11 pixels wide) */
+ 0x00, 0x10, /* # */
+ 0x00, 0xE0, /* ### */
+ 0x07, 0x00, /* ### */
+ 0x18, 0x00, /* ## */
+ 0x07, 0x80, /* #### */
+ 0x00, 0x70, /* ### */
+ 0x07, 0x80, /* #### */
+ 0x18, 0x00, /* ## */
+ 0x07, 0x00, /* ### */
+ 0x00, 0xE0, /* ### */
+ 0x00, 0x10, /* # */
+
+ /* @634 'X' (7 pixels wide) */
+ 0x10, 0x10, /* # # */
+ 0x08, 0x30, /* # ## */
+ 0x06, 0xC0, /* ## ## */
+ 0x01, 0x00, /* # */
+ 0x06, 0xC0, /* ## ## */
+ 0x08, 0x30, /* # ## */
+ 0x10, 0x10, /* # # */
+
+ /* @648 'Y' (7 pixels wide) */
+ 0x00, 0x10, /* # */
+ 0x00, 0x60, /* ## */
+ 0x01, 0x80, /* ## */
+ 0x1E, 0x00, /* #### */
+ 0x01, 0x80, /* ## */
+ 0x00, 0x60, /* ## */
+ 0x00, 0x10, /* # */
+
+ /* @662 'Z' (7 pixels wide) */
+ 0x18, 0x10, /* ## # */
+ 0x14, 0x10, /* # # # */
+ 0x12, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x10, 0x90, /* # # # */
+ 0x10, 0x50, /* # # # */
+ 0x10, 0x30, /* # ## */
+
+ /* @676 '[' (2 pixels wide) */
+ 0x7F, 0xF0, /* ########### */
+ 0x40, 0x10, /* # # */
+
+ /* @680 '\' (4 pixels wide) */
+ 0x00, 0x30, /* ## */
+ 0x01, 0xC0, /* ### */
+ 0x0E, 0x00, /* ### */
+ 0x30, 0x00, /* ## */
+
+ /* @688 ']' (2 pixels wide) */
+ 0x40, 0x10, /* # # */
+ 0x7F, 0xF0, /* ########### */
+
+ /* @692 '^' (6 pixels wide) */
+ 0x00, 0x40, /* # */
+ 0x00, 0x20, /* # */
+ 0x00, 0x10, /* # */
+ 0x00, 0x10, /* # */
+ 0x00, 0x20, /* # */
+ 0x00, 0x40, /* # */
+
+ /* @704 '_' (6 pixels wide) */
+ 0x80, 0x00, /* # */
+ 0x80, 0x00, /* # */
+ 0x80, 0x00, /* # */
+ 0x80, 0x00, /* # */
+ 0x80, 0x00, /* # */
+ 0x80, 0x00, /* # */
+
+ /* @716 '`' (2 pixels wide) */
+ 0x00, 0x08, /* # */
+ 0x00, 0x10, /* # */
+
+ /* @720 'a' (6 pixels wide) */
+ 0x0C, 0x80, /* ## # */
+ 0x12, 0x40, /* # # # */
+ 0x12, 0x40, /* # # # */
+ 0x12, 0x40, /* # # # */
+ 0x0A, 0x40, /* # # # */
+ 0x1F, 0x80, /* ###### */
+
+ /* @732 'b' (6 pixels wide) */
+ 0x1F, 0xF8, /* ########## */
+ 0x18, 0xC0, /* ## ## */
+ 0x10, 0x40, /* # # */
+ 0x10, 0x40, /* # # */
+ 0x18, 0xC0, /* ## ## */
+ 0x0F, 0x80, /* ##### */
+
+ /* @744 'c' (5 pixels wide) */
+ 0x0F, 0x80, /* ##### */
+ 0x18, 0xC0, /* ## ## */
+ 0x10, 0x40, /* # # */
+ 0x10, 0x40, /* # # */
+ 0x08, 0x80, /* # # */
+
+ /* @754 'd' (6 pixels wide) */
+ 0x0F, 0x80, /* ##### */
+ 0x18, 0xC0, /* ## ## */
+ 0x10, 0x40, /* # # */
+ 0x10, 0x40, /* # # */
+ 0x18, 0xC0, /* ## ## */
+ 0x1F, 0xF8, /* ########## */
+
+ /* @766 'e' (6 pixels wide) */
+ 0x0F, 0x80, /* ##### */
+ 0x0A, 0xC0, /* # # ## */
+ 0x12, 0x40, /* # # # */
+ 0x12, 0x40, /* # # # */
+ 0x12, 0xC0, /* # # ## */
+ 0x0B, 0x80, /* # ### */
+
+ /* @778 'f' (4 pixels wide) */
+ 0x00, 0x40, /* # */
+ 0x1F, 0xF0, /* ######### */
+ 0x00, 0x48, /* # # */
+ 0x00, 0x48, /* # # */
+
+ /* @786 'g' (6 pixels wide) */
+ 0x0F, 0x80, /* ##### */
+ 0x58, 0xC0, /* # ## ## */
+ 0x90, 0x40, /* # # # */
+ 0x90, 0x40, /* # # # */
+ 0xD8, 0xC0, /* ## ## ## */
+ 0x7F, 0xC0, /* ######### */
+
+ /* @798 'h' (6 pixels wide) */
+ 0x1F, 0xF8, /* ########## */
+ 0x00, 0x80, /* # */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+ 0x1F, 0x80, /* ###### */
+
+ /* @810 'i' (1 pixels wide) */
+ 0x1F, 0xD0, /* ####### # */
+
+ /* @812 'j' (2 pixels wide) */
+ 0x80, 0x00, /* # */
+ 0xFF, 0xD0, /* ########## # */
+
+ /* @816 'k' (5 pixels wide) */
+ 0x1F, 0xF8, /* ########## */
+ 0x02, 0x00, /* # */
+ 0x05, 0x00, /* # # */
+ 0x08, 0x80, /* # # */
+ 0x10, 0x40, /* # # */
+
+ /* @826 'l' (1 pixels wide) */
+ 0x1F, 0xF8, /* ########## */
+
+ /* @828 'm' (9 pixels wide) */
+ 0x1F, 0xC0, /* ####### */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+ 0x1F, 0x80, /* ###### */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+ 0x1F, 0x80, /* ###### */
+
+ /* @846 'n' (6 pixels wide) */
+ 0x1F, 0xC0, /* ####### */
+ 0x00, 0x80, /* # */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+ 0x1F, 0x80, /* ###### */
+
+ /* @858 'o' (6 pixels wide) */
+ 0x0F, 0x80, /* ##### */
+ 0x18, 0xC0, /* ## ## */
+ 0x10, 0x40, /* # # */
+ 0x10, 0x40, /* # # */
+ 0x18, 0xC0, /* ## ## */
+ 0x0F, 0x80, /* ##### */
+
+ /* @870 'p' (6 pixels wide) */
+ 0xFF, 0xC0, /* ########## */
+ 0x18, 0xC0, /* ## ## */
+ 0x10, 0x40, /* # # */
+ 0x10, 0x40, /* # # */
+ 0x18, 0xC0, /* ## ## */
+ 0x0F, 0x80, /* ##### */
+
+ /* @882 'q' (6 pixels wide) */
+ 0x0F, 0x80, /* ##### */
+ 0x18, 0xC0, /* ## ## */
+ 0x10, 0x40, /* # # */
+ 0x10, 0x40, /* # # */
+ 0x18, 0xC0, /* ## ## */
+ 0xFF, 0xC0, /* ########## */
+
+ /* @894 'r' (4 pixels wide) */
+ 0x1F, 0xC0, /* ####### */
+ 0x00, 0x80, /* # */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+
+ /* @902 's' (5 pixels wide) */
+ 0x09, 0x80, /* # ## */
+ 0x12, 0x40, /* # # # */
+ 0x12, 0x40, /* # # # */
+ 0x12, 0x40, /* # # # */
+ 0x0C, 0x80, /* ## # */
+
+ /* @912 't' (4 pixels wide) */
+ 0x00, 0x40, /* # */
+ 0x1F, 0xF0, /* ######### */
+ 0x10, 0x40, /* # # */
+ 0x10, 0x40, /* # # */
+
+ /* @920 'u' (6 pixels wide) */
+ 0x0F, 0xC0, /* ###### */
+ 0x10, 0x00, /* # */
+ 0x10, 0x00, /* # */
+ 0x10, 0x00, /* # */
+ 0x08, 0x00, /* # */
+ 0x1F, 0xC0, /* ####### */
+
+ /* @932 'v' (6 pixels wide) */
+ 0x00, 0xC0, /* ## */
+ 0x07, 0x00, /* ### */
+ 0x18, 0x00, /* ## */
+ 0x18, 0x00, /* ## */
+ 0x07, 0x00, /* ### */
+ 0x00, 0xC0, /* ## */
+
+ /* @944 'w' (9 pixels wide) */
+ 0x00, 0xC0, /* ## */
+ 0x07, 0x00, /* ### */
+ 0x18, 0x00, /* ## */
+ 0x07, 0x00, /* ### */
+ 0x00, 0xC0, /* ## */
+ 0x07, 0x00, /* ### */
+ 0x18, 0x00, /* ## */
+ 0x07, 0x00, /* ### */
+ 0x00, 0xC0, /* ## */
+
+ /* @962 'x' (6 pixels wide) */
+ 0x10, 0x40, /* # # */
+ 0x0D, 0x80, /* ## ## */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x0D, 0x80, /* ## ## */
+ 0x10, 0x40, /* # # */
+
+ /* @974 'y' (6 pixels wide) */
+ 0x80, 0xC0, /* # ## */
+ 0x83, 0x00, /* # ## */
+ 0x4C, 0x00, /* # ## */
+ 0x38, 0x00, /* ### */
+ 0x07, 0x00, /* ### */
+ 0x00, 0xC0, /* ## */
+
+ /* @986 'z' (5 pixels wide) */
+ 0x18, 0x40, /* ## # */
+ 0x14, 0x40, /* # # # */
+ 0x12, 0x40, /* # # # */
+ 0x11, 0x40, /* # # # */
+ 0x10, 0xC0, /* # ## */
+
+ /* @996 '{' (5 pixels wide) */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x7D, 0xF0, /* ##### ##### */
+ 0x40, 0x10, /* # # */
+ 0x40, 0x10, /* # # */
+
+ /* @1006 '|' (1 pixels wide) */
+ 0xFF, 0xF0, /* ############ */
+
+ /* @1008 '}' (5 pixels wide) */
+ 0x40, 0x10, /* # # */
+ 0x40, 0x10, /* # # */
+ 0x7D, 0xF0, /* ##### ##### */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+
+ /* @1018 '~' (8 pixels wide) */
+ 0x02, 0x00, /* # */
+ 0x01, 0x00, /* # */
+ 0x01, 0x00, /* # */
+ 0x01, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x01, 0x00, /* # */
+};
+
+/* Character descriptors for DejaVu Sans 9pt */
+/* { [Char width in bits], [Offset into dejaVuSans9ptCharBitmaps in bytes] } */
+const FONT_CHAR_INFO _dejaVuSans9ptCharDescriptors[] = {
+ {5, 0}, /* */
+ {1, 10}, /* ! */
+ {3, 12}, /* " */
+ {8, 18}, /* # */
+ {5, 34}, /* $ */
+ {10, 44}, /* % */
+ {8, 64}, /* & */
+ {1, 80}, /* ' */
+ {3, 82}, /* ( */
+ {3, 88}, /* ) */
+ {5, 94}, /* * */
+ {7, 104}, /* + */
+ {1, 118}, /* , */
+ {3, 120}, /* - */
+ {1, 126}, /* . */
+ {4, 128}, /* / */
+ {6, 136}, /* 0 */
+ {5, 148}, /* 1 */
+ {6, 158}, /* 2 */
+ {6, 170}, /* 3 */
+ {6, 182}, /* 4 */
+ {6, 194}, /* 5 */
+ {6, 206}, /* 6 */
+ {6, 218}, /* 7 */
+ {6, 230}, /* 8 */
+ {6, 242}, /* 9 */
+ {1, 254}, /* : */
+ {1, 256}, /* ; */
+ {8, 258}, /* < */
+ {8, 274}, /* = */
+ {8, 290}, /* > */
+ {5, 306}, /* ? */
+ {11, 316}, /* @ */
+ {8, 338}, /* A */
+ {6, 354}, /* B */
+ {6, 366}, /* C */
+ {7, 378}, /* D */
+ {6, 392}, /* E */
+ {5, 404}, /* F */
+ {7, 414}, /* G */
+ {7, 428}, /* H */
+ {1, 442}, /* I */
+ {3, 444}, /* J */
+ {6, 450}, /* K */
+ {5, 462}, /* L */
+ {8, 472}, /* M */
+ {7, 488}, /* N */
+ {7, 502}, /* O */
+ {6, 516}, /* P */
+ {7, 528}, /* Q */
+ {7, 542}, /* R */
+ {6, 556}, /* S */
+ {7, 568}, /* T */
+ {7, 582}, /* U */
+ {8, 596}, /* V */
+ {11, 612}, /* W */
+ {7, 634}, /* X */
+ {7, 648}, /* Y */
+ {7, 662}, /* Z */
+ {2, 676}, /* [ */
+ {4, 680}, /* \ */
+ {2, 688}, /* ] */
+ {6, 692}, /* ^ */
+ {6, 704}, /* _ */
+ {2, 716}, /* ` */
+ {6, 720}, /* a */
+ {6, 732}, /* b */
+ {5, 744}, /* c */
+ {6, 754}, /* d */
+ {6, 766}, /* e */
+ {4, 778}, /* f */
+ {6, 786}, /* g */
+ {6, 798}, /* h */
+ {1, 810}, /* i */
+ {2, 812}, /* j */
+ {5, 816}, /* k */
+ {1, 826}, /* l */
+ {9, 828}, /* m */
+ {6, 846}, /* n */
+ {6, 858}, /* o */
+ {6, 870}, /* p */
+ {6, 882}, /* q */
+ {4, 894}, /* r */
+ {5, 902}, /* s */
+ {4, 912}, /* t */
+ {6, 920}, /* u */
+ {6, 932}, /* v */
+ {9, 944}, /* w */
+ {6, 962}, /* x */
+ {6, 974}, /* y */
+ {5, 986}, /* z */
+ {5, 996}, /* { */
+ {1, 1006}, /* | */
+ {5, 1008}, /* } */
+ {8, 1018}, /* ~ */
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_RESOURCE_H
diff --git a/engines/gnap/gamesys.cpp b/engines/gnap/gamesys.cpp
new file mode 100644
index 0000000000..e59662f08a
--- /dev/null
+++ b/engines/gnap/gamesys.cpp
@@ -0,0 +1,1260 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "gnap/gamesys.h"
+#include "gnap/fontdata.h"
+#include "graphics/fontman.h"
+#include "graphics/font.h"
+#include "image/bmp.h"
+
+namespace Gnap {
+
+void GfxItem::testUpdRect(const Common::Rect &updRect) {
+ Common::Rect intersectingRect;
+ if (!_updFlag && _prevFrame._spriteId != -1 &&
+ _updRectsCount < 20 && intersectRect(intersectingRect, _prevFrame._rect, updRect))
+ _updRects[_updRectsCount++] = intersectingRect;
+}
+
+// GameSys
+
+GameSys::GameSys(GnapEngine *vm) : _vm(vm) {
+ _newSpriteDrawItemsCount = 0;
+ _removeSequenceItemsCount = 0;
+ _removeSpriteDrawItemsCount = 0;
+ _grabSpriteId = -1;
+ _grabSpriteChanged = false;
+ _reqRemoveSequenceItem = false;
+ _removeSequenceItemSequenceId = -1;
+ _removeSequenceItemValue = 0;
+ _gfxItemsCount = 0;
+ _animationsCount = 0;
+ _backgroundImageValue3 = 0;
+ _backgroundImageValue1 = 0;
+ _backgroundImageValue4 = 1000;
+ _backgroundImageValue2 = 1000;
+ _gameSysClock = 0;
+ _lastUpdateClock = 0;
+ _backgroundSurface = nullptr;
+ _frontSurface = nullptr;
+ for (int i = 0; i < kMaxAnimations; ++i) {
+ _animations[i]._sequenceId = -1;
+ _animations[i]._id = -1;
+ _animations[i]._status = 0;
+ }
+ _removeSequenceItems->_sequenceId = -1;
+ _removeSequenceItems->_id = -1;
+ _removeSequenceItems->_forceFrameReset = false;
+ _removeSpriteDrawItems->_id = -1;
+ _removeSpriteDrawItems->_surface = nullptr;
+
+ _grabSpriteSurface1 = _grabSpriteSurface2 = nullptr;
+
+ _screenRect = Common::Rect(0, 0, 800, 600);
+}
+
+GameSys::~GameSys() {
+ if (_frontSurface)
+ _frontSurface->free();
+ delete _frontSurface;
+}
+
+void GameSys::insertSequence(int sequenceId, int id, int sequenceId2, int id2, int flags, int totalDuration, int16 x, int16 y) {
+ debugC(kDebugBasic, "GameSys::insertSequence() [%08X, %d] -> [%08X, %d] (%d, %d)", sequenceId, id, sequenceId2, id2, x, y);
+ Sequence sequence;
+ SequenceResource *sequenceResource = _vm->_sequenceCache->get(sequenceId);
+ sequenceResource->_sequenceId = sequenceId;
+ sequence._sequenceId = sequenceId;
+ sequence._id = id != -1 ? id : sequenceResource->_defaultId;
+ sequence._sequenceId2 = sequenceId2 != (int32)0x80000000 ? sequenceId2 : sequenceResource->_sequenceId2;
+ sequence._id2 = id2 != -1 ? id2 : sequenceResource->_defaultId2;
+ sequence._flags = flags != -1 ? flags : sequenceResource->_flags;
+ sequence._totalDuration = totalDuration != -1 ? totalDuration : sequenceResource->_totalDuration;
+ sequence._x = (x < 10000 && x > -10000) ? x : sequenceResource->_xOffs;
+ sequence._y = (y < 10000 && y > -10000) ? y : sequenceResource->_yOffs;
+ _fatSequenceItems.push_back(sequence);
+}
+
+void GameSys::insertDirtyRect(const Common::Rect &rect) {
+ _dirtyRects.push_back(rect);
+}
+
+void GameSys::removeSequence(int sequenceId, int id, bool resetFl) {
+ //WaitForSingleObject(removeSequence2Mutex, INFINITE);
+ if (_removeSequenceItemsCount < kMaxSequenceItems) {
+ _removeSequenceItems[_removeSequenceItemsCount]._sequenceId = sequenceId;
+ _removeSequenceItems[_removeSequenceItemsCount]._id = id;
+ _removeSequenceItems[_removeSequenceItemsCount]._forceFrameReset = resetFl;
+ ++_removeSequenceItemsCount;
+ //ResetEvent(removeSequenceItemsEvent);
+ //ReleaseMutex(removeSequence2Mutex);
+ //WaitForSingleObject(removeSequenceItemsEvent, INFINITE);
+ }
+}
+
+void GameSys::invalidateGrabCursorSprite(int id, Common::Rect &rect, Graphics::Surface *surface1, Graphics::Surface *surface2) {
+ //WaitForSingleObject(grabSpriteMutex, INFINITE);
+ _grabSpriteId = id;
+ _grabSpriteRect = rect;
+ _grabSpriteSurface2 = surface2;
+ _grabSpriteSurface1 = surface1;
+ //ResetEvent(grabSpriteEvent);
+ _grabSpriteChanged = true;
+ //ReleaseMutex(grabSpriteMutex);
+ //WaitForSingleObject(grabSpriteEvent, INFINITE);
+}
+
+void GameSys::requestClear2(bool resetFl) {
+ _fatSequenceItems.clear();
+ _seqItems.clear();
+ for (int i = 0; i < _gfxItemsCount; ++i) {
+ GfxItem *gfxItem = &_gfxItems[i];
+ gfxItem->_sequenceId = -1;
+ gfxItem->_animation = nullptr;
+ if (resetFl) {
+ gfxItem->_currFrame._duration = 0;
+ gfxItem->_currFrame._spriteId = -1;
+ gfxItem->_currFrame._soundId = -1;
+ gfxItem->_updFlag = true;
+ } else {
+ gfxItem->_updFlag = false;
+ }
+ }
+ _lastUpdateClock = 0;
+ _gameSysClock = 0;
+}
+
+void GameSys::requestClear1() {
+ _gfxItemsCount = 0;
+ _fatSequenceItems.clear();
+ _seqItems.clear();
+ _lastUpdateClock = 0;
+ _gameSysClock = 0;
+}
+
+void GameSys::requestRemoveSequence(int sequenceId, int id) {
+ //WaitForSingleObject(removeSequence2Mutex, INFINITE);
+ _reqRemoveSequenceItem = true;
+ _removeSequenceItemSequenceId = sequenceId;
+ _removeSequenceItemValue = id;
+
+ handleReqRemoveSequenceItem(); //CHECKME?
+
+ //ResetEvent(reqClearEvent);
+ //ReleaseMutex(removeSequence2Mutex);
+ //WaitForSingleObject(reqClearEvent, INFINITE);
+}
+
+void GameSys::waitForUpdate() {
+ //ResetEvent(updateEvent);
+ //WaitForSingleObject(updateEvent, INFINITE);
+}
+
+int GameSys::isSequenceActive(int sequenceId, int id) {
+ for (uint i = 0; i < _seqItems.size(); ++i)
+ if (_seqItems[i]._sequenceId == sequenceId && _seqItems[i]._id == id)
+ return true;
+ return false;
+}
+
+void GameSys::setBackgroundSurface(Graphics::Surface *surface, int a4, int a5, int a6, int a7) {
+ debugC(kDebugBasic, "GameSys::setBackgroundSurface() Setting background image");
+
+ _backgroundSurface = surface;
+ if (!_backgroundSurface) {
+ return;
+ }
+
+ if (!_frontSurface || _frontSurface->w != surface->w || _frontSurface->h != surface->h) {
+ debugC(kDebugBasic, "GameSys::setBackgroundSurface() Creating background working surface");
+ if (_frontSurface)
+ _frontSurface->free();
+ delete _frontSurface;
+ _frontSurface = new Graphics::Surface();
+ _frontSurface->create(surface->w, surface->h, surface->format);
+ }
+
+ memcpy(_frontSurface->getPixels(), surface->getPixels(), surface->pitch * surface->h);
+ _vm->_system->copyRectToScreen(_frontSurface->getPixels(), _frontSurface->pitch, 0, 0, _frontSurface->w, _frontSurface->h);
+
+ _backgroundImageValue1 = a4;
+ _backgroundImageValue3 = a6;
+ _backgroundImageValue2 = a5;
+ _backgroundImageValue4 = a7;
+ _lastUpdateClock = 0;
+ _gameSysClock = 0;
+}
+
+void GameSys::setScaleValues(int a1, int a2, int a3, int a4) {
+ _backgroundImageValue1 = a1;
+ _backgroundImageValue3 = a3;
+ _backgroundImageValue2 = a2;
+ _backgroundImageValue4 = a4;
+}
+
+void GameSys::insertSpriteDrawItem(Graphics::Surface *surface, int x, int y, int id) {
+ if (surface && _newSpriteDrawItemsCount < kMaxSpriteDrawItems) {
+ _newSpriteDrawItems[_newSpriteDrawItemsCount]._id = id;
+ _newSpriteDrawItems[_newSpriteDrawItemsCount]._rect = Common::Rect(x, y, x + surface->w, y + surface->h);
+ _newSpriteDrawItems[_newSpriteDrawItemsCount]._surface = surface;
+ ++_newSpriteDrawItemsCount;
+ }
+}
+
+void GameSys::removeSpriteDrawItem(Graphics::Surface *surface, int id) {
+ if (surface && _removeSpriteDrawItemsCount < kMaxSpriteDrawItems) {
+ _removeSpriteDrawItems[_removeSpriteDrawItemsCount]._id = id;
+ _removeSpriteDrawItems[_removeSpriteDrawItemsCount]._surface = surface;
+ ++_removeSpriteDrawItemsCount;
+ }
+}
+
+void GameSys::drawSpriteToBackground(int x, int y, int resourceId) {
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ uint32 *sourcePalette = spriteResource->_palette;
+ byte *sourcePixels = spriteResource->_pixels;
+ int spriteWidth = spriteResource->_width;
+ int spriteHeight = spriteResource->_height;
+ Common::Rect dstRect(0, 0, spriteWidth, spriteHeight);
+ blitSprite32(_backgroundSurface, x, y, sourcePixels, spriteResource->_width, dstRect, sourcePalette, spriteResource->_transparent);
+ _vm->_spriteCache->release(resourceId);
+
+ // Add dirty rect so the modified background is redrawn
+ insertDirtyRect(Common::Rect(x, y, x + spriteWidth, y + spriteHeight));
+}
+
+Graphics::Surface *GameSys::allocSurface(int width, int height) {
+ Graphics::Surface *surface = new Graphics::Surface();
+ surface->create(width, height, _backgroundSurface->format);
+ surface->fillRect(Common::Rect(0, 0, surface->w, surface->h), 0xFFFFFF00);
+ return surface;
+}
+
+Graphics::Surface *GameSys::createSurface(int resourceId) {
+ debugC(kDebugBasic, "GameSys::createSurface() resourceId: %08X", resourceId);
+
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ Graphics::Surface *surface = allocSurface(spriteResource->_width, spriteResource->_height);
+ _vm->_spriteCache->release(resourceId);
+
+ drawSpriteToSurface(surface, 0, 0, resourceId);
+
+ return surface;
+}
+
+void GameSys::drawSpriteToSurface(Graphics::Surface *surface, int x, int y, int resourceId) {
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ uint32 *sourcePalette = spriteResource->_palette;
+ byte *sourcePixels = spriteResource->_pixels;
+ Common::Rect dstRect(0, 0, spriteResource->_width, spriteResource->_height);
+ blitSprite32(surface, x, y, sourcePixels, spriteResource->_width, dstRect, sourcePalette, true);
+ _vm->_spriteCache->release(resourceId);
+}
+
+void GameSys::drawTextToSurface(Graphics::Surface *surface, int x, int y, byte r, byte g, byte b, const char *text) {
+ bool doDirty = false;
+
+ if (!surface) {
+ surface = _backgroundSurface;
+ doDirty = true;
+ }
+
+ uint32 color = surface->format.RGBToColor(r, g, b);
+ if (_vm->_font) {
+ _vm->_font->drawString(surface, text, x, y, _vm->_font->getStringWidth(text), color);
+
+ if (doDirty)
+ insertDirtyRect(Common::Rect(x, y, x + _vm->_font->getStringWidth(text), y + _vm->_font->getFontHeight()));
+ } else {
+ for (const char *cp = text; *cp != 0; ++cp) {
+ byte c = *cp;
+ if (c < 32 || c >= 127)
+ c = (byte)'_';
+ c -= 32;
+ int w = _dejaVuSans9ptCharDescriptors[c]._width;
+ const byte *data = _dejaVuSans9ptCharBitmaps + _dejaVuSans9ptCharDescriptors[c]._offset;
+ for (int xc = 0; xc < w; ++xc) {
+ for (int yc = 15; yc >= 0; --yc) {
+ byte *dst = (byte *)surface->getBasePtr(x + xc, y + yc);
+ if (data[1 - (yc >> 3)] & (1 << (yc & 7)))
+ WRITE_LE_UINT32(dst, color);
+ }
+ data += 2;
+ }
+ x += w + 1;
+ }
+
+ if (doDirty)
+ insertDirtyRect(Common::Rect(x, y, x + getTextWidth(text), y + 16));
+ }
+}
+
+int GameSys::getTextHeight(const char *text) {
+ byte height = 0;
+ for (const char *cp = text; *cp != 0; ++cp) {
+ byte c = *cp;
+ if (c < 32 || c >= 127)
+ c = (byte)'_';
+ c -= 32;
+ height = MAX(height, _dejaVuSans9ptCharDescriptors[c]._width);
+ }
+ return height;
+}
+
+int GameSys::getTextWidth(const char *text) {
+ int width = 0;
+ for (const char *cp = text; *cp != 0; ++cp) {
+ byte c = *cp;
+ if (c < 32 || c >= 127)
+ c = (byte)'_';
+ c -= 32;
+ width += _dejaVuSans9ptCharDescriptors[c]._width + 1;
+ }
+ return width;
+}
+
+void GameSys::fillSurface(Graphics::Surface *surface, int x, int y, int width, int height, byte r, byte g, byte b) {
+ Common::Rect rect(x, y, x + width, y + height);
+ if (!surface) {
+ _backgroundSurface->fillRect(rect, _backgroundSurface->format.RGBToColor(r, g, b));
+ insertDirtyRect(rect);
+ } else {
+ surface->fillRect(rect, surface->format.RGBToColor(r, g, b));
+ }
+}
+
+void GameSys::setAnimation(int sequenceId, int id, int animationIndex) {
+ if (animationIndex < kMaxAnimations) {
+ _animations[animationIndex]._sequenceId = sequenceId;
+ _animations[animationIndex]._id = id;
+ _animations[animationIndex]._status = 0;
+ }
+}
+
+int GameSys::getAnimationStatus(int animationIndex) {
+ int result = -1;
+ if (animationIndex < kMaxAnimations)
+ result = _animations[animationIndex]._status;
+ return result;
+}
+
+int GameSys::getSpriteWidthById(int resourceId) {
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ const int width = spriteResource->_width;
+ _vm->_spriteCache->release(resourceId);
+ return width;
+}
+
+int GameSys::getSpriteHeightById(int resourceId) {
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ const int height = spriteResource->_height;
+ _vm->_spriteCache->release(resourceId);
+ return height;
+}
+
+Graphics::Surface *GameSys::loadBitmap(int resourceId) {
+ debugC(kDebugBasic, "GameSys::loadBitmap() resourceId: %08X", resourceId);
+ if (_vm->_dat->getResourceType(resourceId) != 1)
+ return nullptr;
+ byte *resourceData = _vm->_dat->loadResource(resourceId);
+ uint32 resourceSize = _vm->_dat->getResourceSize(resourceId);
+ Common::MemoryReadStream stream(resourceData, resourceSize, DisposeAfterUse::NO);
+ Graphics::Surface *bmpSurface;
+ Image::BitmapDecoder bmp;
+ if (!bmp.loadStream(stream))
+ error("GameSys::loadBitmap() Could not load bitmap resource %08X", resourceId);
+ bmpSurface = bmp.getSurface()->convertTo(_vm->_system->getScreenFormat());
+ delete[] resourceData;
+ return bmpSurface;
+}
+
+void GameSys::drawBitmap(int resourceId) {
+ assert(_backgroundSurface);
+
+ Graphics::Surface *bmpSurface = loadBitmap(resourceId);
+ if (!bmpSurface)
+ error("GameSys::drawBitmap() Error loading the bitmap");
+
+ if (bmpSurface->format != _backgroundSurface->format
+ || bmpSurface->w != _backgroundSurface->w || bmpSurface->h != _backgroundSurface->h)
+ error("GameSys::drawBitmap() Different bitmap properties than current background");
+
+ byte *src = (byte *)bmpSurface->getPixels();
+ byte *dst = (byte *)_backgroundSurface->getPixels();
+ const int pitch = bmpSurface->pitch;
+ int height = bmpSurface->h;
+ while (height--) {
+ memcpy(dst, src, pitch);
+ src += pitch;
+ dst += pitch;
+ }
+
+ bmpSurface->free();
+ delete bmpSurface;
+
+ insertDirtyRect(Common::Rect(0, 0, 800, 600));
+}
+
+Sequence *GameSys::seqFind(int sequenceId, int id, int *outIndex) {
+ for (uint i = 0; i < _seqItems.size(); ++i)
+ if (_seqItems[i]._sequenceId == sequenceId && _seqItems[i]._id == id) {
+ if (outIndex)
+ *outIndex = i;
+ return &_seqItems[i];
+ }
+ return nullptr;
+}
+
+int GameSys::seqLocateGfx(int sequenceId, int id, int *outGfxIndex) {
+ for (int i = 0; i < _gfxItemsCount; ++i) {
+ GfxItem *gfxItem = &_gfxItems[i];
+ if (gfxItem->_sequenceId == sequenceId && gfxItem->_id == id) {
+ if (outGfxIndex)
+ *outGfxIndex = i;
+ return gfxItem->_sequenceId;
+ }
+ if (gfxItem->_id > id) {
+ if (outGfxIndex)
+ *outGfxIndex = i;
+ return 0;
+ }
+ }
+ if (outGfxIndex)
+ *outGfxIndex = _gfxItemsCount;
+ return 0;
+}
+
+void GameSys::seqInsertGfx(int index, int duration) {
+ Sequence *seqItem = &_seqItems[index];
+ SequenceResource *sequenceResource = _vm->_sequenceCache->get(seqItem->_sequenceId);
+
+ if (sequenceResource->_animationsCount > 50 - _gfxItemsCount)
+ return;
+
+ int gfxIndex;
+ seqLocateGfx(seqItem->_sequenceId, seqItem->_id, &gfxIndex);
+
+ if (gfxIndex != _gfxItemsCount)
+ memmove(&_gfxItems[gfxIndex + sequenceResource->_animationsCount], &_gfxItems[gfxIndex], sizeof(GfxItem) * (_gfxItemsCount - gfxIndex));
+ _gfxItemsCount += sequenceResource->_animationsCount;
+
+ for (int i = 0; i < sequenceResource->_animationsCount; ++i) {
+ GfxItem *gfxItem = &_gfxItems[i + gfxIndex];
+ SequenceAnimation *animation = &sequenceResource->_animations[i];
+
+ debugC(kDebugBasic, "GameSys::seqInsertGfx() seqItem->sequenceId: %08X", seqItem->_sequenceId);
+
+ gfxItem->_sequenceId = seqItem->_sequenceId;
+ gfxItem->_id = seqItem->_id;
+ gfxItem->_animation = animation;
+ gfxItem->_currFrameNum = 0;
+ gfxItem->_flags = 0;
+ gfxItem->_delayTicks = seqItem->_totalDuration + animation->_additionalDelay;
+ gfxItem->_updFlag = false;
+ gfxItem->_updRectsCount = 0;
+ gfxItem->_prevFrame._duration = 0;
+ gfxItem->_prevFrame._spriteId = -1;
+ gfxItem->_prevFrame._soundId = -1;
+ int totalDuration = duration;
+ if ((seqItem->_flags & kSeqUnk) && totalDuration > 0) {
+ gfxItem->_prevFrame._duration = 1;
+ if (gfxItem->_delayTicks <= totalDuration)
+ gfxItem->_delayTicks = 0;
+ else
+ gfxItem->_delayTicks -= totalDuration + 1;
+ gfxItem->_updFlag = false;
+ } else if (gfxItem->_delayTicks <= totalDuration) {
+ int j;
+ totalDuration -= gfxItem->_delayTicks;
+ gfxItem->_delayTicks = 0;
+ for (j = gfxItem->_currFrameNum; j < animation->_framesCount && animation->frames[j]._duration <= totalDuration; ++j) {
+ if (animation->frames[j]._soundId != -1)
+ _soundIds.push_back((gfxItem->_sequenceId & 0xFFFF0000) | animation->frames[j]._soundId);
+ totalDuration -= animation->frames[j]._duration;
+ }
+ if (animation->_framesCount > j)
+ gfxItem->_currFrame = animation->frames[j++];
+ else
+ gfxItem->_currFrame = animation->frames[j - 1];
+ if (gfxItem->_currFrame._spriteId != -1 && (seqItem->_x != 0 || seqItem->_y != 0))
+ gfxItem->_currFrame._rect.translate(seqItem->_x, seqItem->_y);
+ // Update sprite scaling
+ if ((seqItem->_flags & kSeqScale) && gfxItem->_currFrame._rect.bottom >= _backgroundImageValue1 && gfxItem->_currFrame._rect.bottom <= _backgroundImageValue3) {
+ int scaleValue = _backgroundImageValue2 + (gfxItem->_currFrame._rect.bottom - _backgroundImageValue1) *
+ (_backgroundImageValue4 - _backgroundImageValue2) /
+ (_backgroundImageValue3 - _backgroundImageValue1);
+ gfxItem->_currFrame._rect.top = gfxItem->_currFrame._rect.bottom - scaleValue * (gfxItem->_currFrame._rect.bottom - gfxItem->_currFrame._rect.top) / 1000;
+ gfxItem->_currFrame._rect.right = scaleValue * (gfxItem->_currFrame._rect.right - gfxItem->_currFrame._rect.left) / 1000 + gfxItem->_currFrame._rect.left;
+ gfxItem->_currFrame._isScaled = true;
+ }
+ gfxItem->_currFrame._duration -= totalDuration;
+ if (gfxItem->_currFrame._soundId != -1)
+ _soundIds.push_back((gfxItem->_sequenceId & 0xFFFF0000) | gfxItem->_currFrame._soundId);
+ gfxItem->_currFrameNum = j;
+ gfxItem->_updFlag = true;
+ } else {
+ gfxItem->_delayTicks -= totalDuration + 1;
+ gfxItem->_updFlag = false;
+ }
+ }
+
+ for (int k = 0; k < kMaxAnimations; ++k) {
+ if (_animations[k]._sequenceId != -1 && _animations[k]._sequenceId == seqItem->_sequenceId && _animations[k]._id == seqItem->_id) {
+ _animations[k]._status = 1;
+ break;
+ }
+ }
+}
+
+void GameSys::seqRemoveGfx(int sequenceId, int id) {
+ int gfxIndex;
+ if (seqLocateGfx(sequenceId, id, &gfxIndex)) {
+ GfxItem *gfxItem = &_gfxItems[gfxIndex];
+ while (gfxIndex < _gfxItemsCount && gfxItem->_sequenceId == sequenceId && gfxItem->_id == id) {
+ if (gfxItem->_prevFrame._spriteId == -1) {
+ --_gfxItemsCount;
+ if (gfxIndex != _gfxItemsCount)
+ memmove(&_gfxItems[gfxIndex], &_gfxItems[gfxIndex + 1], sizeof(GfxItem) * (_gfxItemsCount - gfxIndex));
+ } else {
+ gfxItem->_sequenceId = -1;
+ gfxItem->_animation = nullptr;
+ gfxItem->_currFrame._duration = 0;
+ gfxItem->_currFrame._spriteId = -1;
+ gfxItem->_currFrame._soundId = -1;
+ gfxItem->_updFlag = true;
+ ++gfxIndex;
+ gfxItem = &_gfxItems[gfxIndex];
+ }
+ }
+ }
+}
+
+bool GameSys::updateSequenceDuration(int sequenceId, int id, int *outDuration) {
+ bool found = false;
+ int duration = 0x7FFFFFFF;
+ for (int i = 0; i < _gfxItemsCount; ++i) {
+ GfxItem *gfxItem = &_gfxItems[i];
+ if (gfxItem->_sequenceId == sequenceId && gfxItem->_id == id) {
+ found = true;
+ SequenceAnimation *animation = gfxItem->_animation;
+ if (animation) {
+ if (gfxItem->_currFrameNum < animation->_framesCount)
+ return false;
+ if (gfxItem->_updFlag) {
+ if (gfxItem->_currFrame._duration > 0)
+ return false;
+ if (-gfxItem->_currFrame._duration < duration)
+ duration = -gfxItem->_currFrame._duration;
+ } else {
+ if (gfxItem->_prevFrame._duration > 0)
+ return false;
+ if (-gfxItem->_prevFrame._duration < duration)
+ duration = -gfxItem->_prevFrame._duration;
+ }
+ }
+ }
+ }
+ if (found)
+ *outDuration = duration;
+ return found;
+}
+
+void GameSys::updateAnimationsStatus(int sequenceId, int id) {
+ Animation *foundAnimation = nullptr;
+ for (int animationIndex = 0; animationIndex < kMaxAnimations; ++animationIndex) {
+ Animation *animation = &_animations[animationIndex];
+ if (animation->_sequenceId != -1 && animation->_sequenceId == sequenceId && animation->_id == id) {
+ foundAnimation = animation;
+ break;
+ }
+ }
+
+ if (!foundAnimation)
+ return;
+
+ bool foundSequence = false;
+ for (int i = 0; i < _gfxItemsCount; ++i) {
+ GfxItem *gfxItem = &_gfxItems[i];
+ SequenceAnimation *animation = gfxItem->_animation;
+ if (gfxItem->_sequenceId == sequenceId && gfxItem->_id == id && animation) {
+ foundSequence = true;
+ if (animation->_framesCount > gfxItem->_currFrameNum ||
+ (gfxItem->_updFlag && gfxItem->_currFrame._duration > 1) ||
+ gfxItem->_prevFrame._duration > 1)
+ foundSequence = false;
+ break;
+ }
+ }
+
+ if (foundSequence) {
+ foundAnimation->_sequenceId = -1;
+ foundAnimation->_status = 2;
+ }
+}
+
+void GameSys::restoreBackgroundRect(const Common::Rect &rect) {
+ Common::Rect clipRect;
+ if (!intersectRect(clipRect, rect, _screenRect))
+ return;
+ byte *src = (byte *)_backgroundSurface->getBasePtr(clipRect.left, clipRect.top);
+ byte *dst = (byte *)_frontSurface->getBasePtr(clipRect.left, clipRect.top);
+ const int bytes = _backgroundSurface->format.bytesPerPixel * clipRect.width();
+ int height = clipRect.height();
+ while (height--) {
+ memcpy(dst, src, bytes);
+ src += _backgroundSurface->pitch;
+ dst += _frontSurface->pitch;
+ }
+}
+
+void GameSys::blitSurface32(Graphics::Surface *destSurface, int x, int y, Graphics::Surface *sourceSurface,
+ Common::Rect &sourceRect, bool transparent) {
+
+ const int sourcePitch = sourceSurface->pitch;
+ byte *dst = (byte *)destSurface->getBasePtr(x, y);
+ byte *src = (byte *)sourceSurface->getBasePtr(sourceRect.left, sourceRect.top);
+ int width = sourceRect.width();
+ int height = sourceRect.height();
+ while (height--) {
+ byte *rsrc = src;
+ byte *rdst = dst;
+ for (int xc = 0; xc < width; ++xc) {
+ uint32 pixel = READ_LE_UINT32(rsrc);
+ if (!transparent || pixel != 0xFFFFFF00)
+ WRITE_LE_UINT32(rdst, pixel);
+ rsrc += 4;
+ rdst += 4;
+ }
+ dst += destSurface->pitch;
+ src += sourcePitch;
+ }
+}
+
+void GameSys::blitSprite32(Graphics::Surface *destSurface, int x, int y, byte *sourcePixels,
+ int sourceWidth, Common::Rect &sourceRect, uint32 *sourcePalette, bool transparent) {
+
+ const int sourcePitch = (sourceWidth + 3) & 0xFFFFFFFC;
+ byte *dst = (byte *)destSurface->getBasePtr(x, y);
+ byte *src = sourcePixels + sourceRect.left + sourcePitch * sourceRect.top;
+ int width = sourceRect.width();
+ int height = sourceRect.height();
+ while (height--) {
+ byte *rdst = dst;
+ for (int xc = 0; xc < width; ++xc) {
+ byte srcPixel = src[xc];
+ if (!transparent || srcPixel) {
+ uint32 rgb = sourcePalette[srcPixel];
+ rdst[0] = 0xFF;
+ rdst[1] = rgb & 0x000000FF;
+ rdst[2] = (rgb & 0x0000FF00) >> 8;
+ rdst[3] = (rgb & 0x00FF0000) >> 16;
+ }
+ rdst += 4;
+ }
+ dst += destSurface->pitch;
+ src += sourcePitch;
+ }
+}
+
+void GameSys::blitSpriteScaled32(Graphics::Surface *destSurface, Common::Rect &frameRect,
+ Common::Rect &destRect, byte *sourcePixels, int sourceWidth, Common::Rect &sourceRect, uint32 *sourcePalette) {
+
+ if (frameRect.height() <= 0 || frameRect.width() <= 0)
+ return;
+
+ const int ys = ((sourceRect.bottom - sourceRect.top - 1) << 16) / (frameRect.bottom - frameRect.top - 1);
+ const int xs = ((sourceRect.right - sourceRect.left - 1) << 16) / (frameRect.right - frameRect.left - 1);
+ const int destPitch = destSurface->pitch;
+ const int sourcePitch = (sourceWidth + 3) & 0xFFFFFFFC;
+
+ if (!frameRect.equals(destRect)) {
+ byte *dst = (byte *)destSurface->getBasePtr(destRect.left, destRect.top);
+ byte *src = sourcePixels + sourcePitch * sourceRect.top + sourceRect.left;
+ const int height = destRect.bottom - destRect.top;
+ const int width = destRect.right - destRect.left;
+ int yi = ys * (destRect.top - frameRect.top);
+ byte *hsrc = src + sourcePitch * ((yi + 0x8000) >> 16);
+ for (int i = 0; i < height; ++i) {
+ byte *wdst = dst;
+ int xi = xs * (destRect.left - frameRect.left);
+ byte *wsrc = hsrc + ((xi + 0x8000) >> 16);
+ for (int j = 0; j < width; ++j) {
+ byte srcPixel = *wsrc;
+ if (srcPixel) {
+ uint32 rgb = sourcePalette[srcPixel];
+ wdst[0] = 0xFF;
+ wdst[1] = rgb & 0x000000FF;
+ wdst[2] = (rgb & 0x0000FF00) >> 8;
+ wdst[3] = (rgb & 0x00FF0000) >> 16;
+ }
+ wdst += 4;
+ xi += xs;
+ wsrc = hsrc + ((xi + 0x8000) >> 16);
+ }
+ dst += destPitch;
+ yi += ys;
+ hsrc = src + sourcePitch * ((yi + 0x8000) >> 16);
+ }
+ } else {
+ byte *dst = (byte *)destSurface->getBasePtr(frameRect.left, frameRect.top);
+ byte *src = sourcePixels + sourcePitch * sourceRect.top + sourceRect.left;
+ const int height = frameRect.bottom - frameRect.top;
+ const int width = frameRect.right - frameRect.left;
+ byte *hsrc = sourcePixels + sourcePitch * sourceRect.top + sourceRect.left;
+ int yi = 0;
+ for (int i = 0; i < height; ++i) {
+ byte *wdst = dst;
+ byte *wsrc = hsrc;
+ int xi = 0;
+ for (int j = 0; j < width; ++j) {
+ byte srcPixel = *wsrc;
+ if (srcPixel) {
+ uint32 rgb = sourcePalette[srcPixel];
+ wdst[0] = 0xFF;
+ wdst[1] = rgb & 0x000000FF;
+ wdst[2] = (rgb & 0x0000FF00) >> 8;
+ wdst[3] = (rgb & 0x00FF0000) >> 16;
+ }
+ wdst += 4;
+ xi += xs;
+ wsrc = hsrc + ((xi + 0x8000) >> 16);
+ }
+ dst += destPitch;
+ yi += ys;
+ hsrc = src + sourcePitch * ((yi + 0x8000) >> 16);
+ }
+ }
+
+}
+
+void GameSys::seqDrawStaticFrame(Graphics::Surface *surface, SequenceFrame &frame, Common::Rect *subRect) {
+ debugC(kDebugBasic, "GameSys::seqDrawStaticFrame() rect: (%d, %d, %d, %d)",
+ frame._rect.left, frame._rect.top, frame._rect.right, frame._rect.bottom);
+
+ Common::Rect srcRect = subRect ? *subRect : frame._rect;
+ Common::Rect clipRect;
+
+ if (!intersectRect(clipRect, srcRect, _screenRect)) {
+ debugC(kDebugBasic, "GameSys::seqDrawStaticFrame() Surface not inside screen");
+ return;
+ }
+
+ const int x = clipRect.left, y = clipRect.top;
+
+ clipRect.translate(-frame._rect.left, -frame._rect.top);
+
+ // TODO Save transparent flag somewhere
+ blitSurface32(_frontSurface, x, y, surface, clipRect, true);
+}
+
+void GameSys::seqDrawSpriteFrame(SpriteResource *spriteResource, SequenceFrame &frame, Common::Rect *subRect) {
+ debugC(kDebugBasic, "GameSys::seqDrawSpriteFrame() spriteId: %04X; rect: (%d, %d, %d, %d)",
+ frame._spriteId, frame._rect.left, frame._rect.top, frame._rect.right, frame._rect.bottom);
+
+ Common::Rect srcRect = subRect ? *subRect : frame._rect;
+ Common::Rect clipRect;
+
+ if (!intersectRect(clipRect, srcRect, _screenRect)) {
+ debugC(kDebugBasic, "GameSys::seqDrawSpriteFrame() Sprite not inside screen");
+ return;
+ }
+
+ uint32 *sourcePalette = spriteResource->_palette;
+ byte *sourcePixels = spriteResource->_pixels;
+
+ const int x = clipRect.left, y = clipRect.top;
+
+ debugC(kDebugBasic, "GameSys::seqDrawSpriteFrame() destX: %d; destY: %d; frame.isScaled: %d", x, y, frame._isScaled ? 1 : 0);
+
+ // 32bit sprite drawing
+ if (frame._isScaled) {
+ Common::Rect sourceRect(0, 0, spriteResource->_width, spriteResource->_height);
+ blitSpriteScaled32(_frontSurface, frame._rect, clipRect, sourcePixels, spriteResource->_width, sourceRect, sourcePalette);
+ } else {
+ clipRect.translate(-frame._rect.left, -frame._rect.top);
+ blitSprite32(_frontSurface, x, y, sourcePixels, spriteResource->_width, clipRect, sourcePalette, true);
+ }
+}
+
+void GameSys::drawSprites() {
+ debugC(kDebugBasic, "GameSys::drawSprites() _gfxItemsCount: %d", _gfxItemsCount);
+
+ // Restore dirty background and collect rects to be redrawn for all sprites
+ // which aren't marked to be redrawn yet
+ Common::Rect intersectingRect;
+ for (uint i = 0; i < _dirtyRects.size(); ++i) {
+ restoreBackgroundRect(_dirtyRects[i]);
+ for (int j = 0; j < _gfxItemsCount; ++j)
+ _gfxItems[j].testUpdRect(_dirtyRects[i]);
+ }
+
+ for (int k = 0; k < _gfxItemsCount; ++k) {
+ GfxItem *gfxItem2 = &_gfxItems[k];
+
+ if (!gfxItem2->_updFlag)
+ continue;
+
+ if (gfxItem2->_prevFrame._spriteId != -1) {
+ bool transparent = false;
+ if (gfxItem2->_currFrame._spriteId != -1) {
+ if (gfxItem2->_flags) {
+ transparent = true;
+ } else {
+ int resourceId = (gfxItem2->_sequenceId & 0xFFFF0000) | gfxItem2->_currFrame._spriteId;
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ transparent = spriteResource->_transparent;
+ _vm->_spriteCache->release(resourceId);
+ }
+ }
+ if (gfxItem2->_currFrame._spriteId == -1 || !gfxItem2->_prevFrame._rect.equals(gfxItem2->_currFrame._rect) || !transparent) {
+ restoreBackgroundRect(gfxItem2->_prevFrame._rect);
+ for (int l = 0; l < _gfxItemsCount; ++l)
+ _gfxItems[l].testUpdRect(gfxItem2->_prevFrame._rect);
+ }
+ }
+
+ if (gfxItem2->_currFrame._spriteId != -1) {
+ bool transparent = false;
+ if (gfxItem2->_flags) {
+ transparent = true;
+ } else {
+ int resourceId = (gfxItem2->_sequenceId & 0xFFFF0000) | gfxItem2->_currFrame._spriteId;
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ transparent = spriteResource->_transparent;
+ _vm->_spriteCache->release(resourceId);
+ }
+ if (gfxItem2->_prevFrame._spriteId == -1 || !gfxItem2->_prevFrame._rect.equals(gfxItem2->_currFrame._rect) || transparent) {
+ for (int l = k; l < _gfxItemsCount; ++l)
+ _gfxItems[l].testUpdRect(gfxItem2->_currFrame._rect);
+ }
+ }
+ }
+
+ for (int m = 0; m < _gfxItemsCount; ++m) {
+ GfxItem *gfxItem5 = &_gfxItems[m];
+
+ debugC(kDebugBasic, "DrawGfxItem(%d) updFlag: %d; currFrame.spriteId: %04X; updRectsCount: %d; flags: %04X; sequenceId: %08X",
+ m, gfxItem5->_updFlag, gfxItem5->_currFrame._spriteId, gfxItem5->_updRectsCount, gfxItem5->_flags, gfxItem5->_sequenceId);
+
+ if (gfxItem5->_updFlag) {
+ if (gfxItem5->_currFrame._spriteId != -1) {
+ if (gfxItem5->_flags) {
+ seqDrawStaticFrame(gfxItem5->_surface, gfxItem5->_currFrame, nullptr);
+ } else {
+ int resourceId = (gfxItem5->_sequenceId & 0xFFFF0000) | gfxItem5->_currFrame._spriteId;
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ seqDrawSpriteFrame(spriteResource, gfxItem5->_currFrame, nullptr);
+ _vm->_spriteCache->release(resourceId);
+ }
+ }
+ } else if (gfxItem5->_updRectsCount > 0) {
+ if (gfxItem5->_flags) {
+ for (int n = 0; n < gfxItem5->_updRectsCount; ++n)
+ seqDrawStaticFrame(gfxItem5->_surface, gfxItem5->_prevFrame, &gfxItem5->_updRects[n]);
+ } else {
+ int resourceId = (gfxItem5->_sequenceId & 0xFFFF0000) | gfxItem5->_prevFrame._spriteId;
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ for (int n = 0; n < gfxItem5->_updRectsCount; ++n)
+ seqDrawSpriteFrame(spriteResource, gfxItem5->_prevFrame, &gfxItem5->_updRects[n]);
+ _vm->_spriteCache->release(resourceId);
+ }
+ }
+ }
+
+ debugC(kDebugBasic, "GameSys::drawSprites() OK");
+}
+
+void GameSys::updateRect(const Common::Rect &r) {
+ debugC(kDebugBasic, "GameSys::updateRect() %d, %d, %d, %d [%d, %d]", r.left, r.top, r.right, r.bottom, r.width(), r.height());
+ if (r.width() > 0 && r.height() > 0) {
+ byte *pixels = (byte *)_frontSurface->getBasePtr(r.left, r.top);
+ _vm->_system->copyRectToScreen(pixels, _frontSurface->pitch, r.left, r.top,
+ r.width(), r.height());
+ }
+}
+
+void GameSys::updateScreen() {
+ debugC(kDebugBasic, "GameSys::updateScreen()");
+
+ for (uint i = 0; i < _dirtyRects.size(); ++i)
+ updateRect(_dirtyRects[i]);
+
+ if (_dirtyRects.size() > 0) {
+ _dirtyRects.clear();
+ _lastUpdateClock = 0;
+ _gameSysClock = 0;
+ }
+
+ Common::Rect dstRect, srcRect, rcSrc2;
+
+ for (int j = 0; j < _gfxItemsCount; ++j) {
+
+ GfxItem *gfxItem = &_gfxItems[j];
+
+ if (!gfxItem->_updFlag)
+ continue;
+
+ if (gfxItem->_prevFrame._spriteId == -1 ||
+ !intersectRect(srcRect, _screenRect, gfxItem->_prevFrame._rect)) {
+ if (gfxItem->_currFrame._spriteId != -1 && intersectRect(rcSrc2, _screenRect, gfxItem->_currFrame._rect))
+ updateRect(rcSrc2);
+ } else if (gfxItem->_currFrame._spriteId != -1 &&
+ intersectRect(rcSrc2, _screenRect, gfxItem->_currFrame._rect)) {
+ updateRect(srcRect);
+ updateRect(rcSrc2);
+ }
+ gfxItem->_prevFrame = gfxItem->_currFrame;
+ }
+
+ updateRect(Common::Rect(0, 0, 800, 600));
+
+ debugC(kDebugBasic, "GameSys::updateScreen() OK");
+}
+
+void GameSys::handleReqRemoveSequenceItem() {
+ if (_reqRemoveSequenceItem) {
+ int gfxIndex2;
+ _reqRemoveSequenceItem = false;
+ if (seqFind(_removeSequenceItemSequenceId, _removeSequenceItemValue, &gfxIndex2))
+ _seqItems.remove_at(gfxIndex2);
+ if (seqLocateGfx(_removeSequenceItemSequenceId, _removeSequenceItemValue, &gfxIndex2)) {
+ int gfxIndex2a = gfxIndex2;
+ for (GfxItem *gfxItem = &_gfxItems[gfxIndex2a];
+ gfxIndex2a < _gfxItemsCount && gfxItem->_sequenceId == _removeSequenceItemSequenceId && gfxItem->_id == _removeSequenceItemValue;
+ gfxItem = &_gfxItems[gfxIndex2a])
+ ++gfxIndex2a;
+ _gfxItemsCount -= gfxIndex2a - gfxIndex2;
+ if (_gfxItemsCount != gfxIndex2)
+ memmove(&_gfxItems[gfxIndex2], &_gfxItems[gfxIndex2a], sizeof(GfxItem) * (_gfxItemsCount - gfxIndex2));
+ }
+ }
+}
+
+void GameSys::handleReqRemoveSequenceItems() {
+ if (_removeSequenceItemsCount > 0) {
+ for (int i = 0; i < _removeSequenceItemsCount; ++i) {
+ int gfxIndex;
+ if (seqFind(_removeSequenceItems[i]._sequenceId, _removeSequenceItems[i]._id, &gfxIndex))
+ _seqItems.remove_at(gfxIndex);
+ seqLocateGfx(_removeSequenceItems[i]._sequenceId, _removeSequenceItems[i]._id, &gfxIndex);
+ for (GfxItem *gfxItem = &_gfxItems[gfxIndex];
+ gfxIndex < _gfxItemsCount && gfxItem->_sequenceId == _removeSequenceItems[i]._sequenceId && gfxItem->_id == _removeSequenceItems[i]._id;
+ gfxItem = &_gfxItems[gfxIndex]) {
+ gfxItem->_sequenceId = -1;
+ gfxItem->_animation = nullptr;
+ if (_removeSequenceItems[i]._forceFrameReset) {
+ gfxItem->_currFrame._duration = 0;
+ gfxItem->_currFrame._spriteId = -1;
+ gfxItem->_currFrame._soundId = -1;
+ gfxItem->_updFlag = true;
+ } else {
+ gfxItem->_updFlag = false;
+ }
+ ++gfxIndex;
+ }
+ }
+ _removeSequenceItemsCount = 0;
+ }
+}
+
+void GameSys::handleReqRemoveSpriteDrawItems() {
+ if (_removeSpriteDrawItemsCount > 0) {
+ for (int j = 0; j < _removeSpriteDrawItemsCount; ++j) {
+ for (int i = 0; i < _gfxItemsCount; ++i) {
+ GfxItem *gfxItem = &_gfxItems[i];
+ if (gfxItem->_sequenceId == -1 && !gfxItem->_animation && gfxItem->_flags
+ && gfxItem->_id == _removeSpriteDrawItems[j]._id && _removeSpriteDrawItems[j]._surface == gfxItem->_surface) {
+ gfxItem->_flags = 0;
+ gfxItem->_currFrame._duration = 0;
+ gfxItem->_currFrame._spriteId = -1;
+ gfxItem->_currFrame._soundId = -1;
+ gfxItem->_updFlag = true;
+ }
+ }
+ }
+ _removeSpriteDrawItemsCount = 0;
+ }
+}
+
+void GameSys::fatUpdateFrame() {
+ debugC(kDebugBasic, "GameSys::fatUpdateFrame()");
+
+ int32 clockDelta = _gameSysClock - _lastUpdateClock;
+ _lastUpdateClock = _gameSysClock;
+
+ debugC(kDebugBasic, "GameSys::fatUpdateFrame() clockDelta: %d", clockDelta);
+
+ if (clockDelta <= 0)
+ return;
+
+ int duration, currFrameNum;
+
+ for (int i = 0; i < _gfxItemsCount; ++i) {
+ GfxItem *gfxItem = &_gfxItems[i];
+ SequenceAnimation *animation = gfxItem->_animation;
+ if ((gfxItem->_sequenceId != -1 && animation) || gfxItem->_prevFrame._spriteId != -1 || gfxItem->_prevFrame._duration > 0) {
+ if (gfxItem->_sequenceId != -1 && !gfxItem->_updFlag) {
+ Sequence *seqItem = seqFind(gfxItem->_sequenceId, gfxItem->_id, nullptr);
+ if (!animation) {
+ gfxItem->_sequenceId = -1;
+ gfxItem->_animation = nullptr;
+ gfxItem->_currFrame._duration = 0;
+ gfxItem->_currFrame._spriteId = -1;
+ gfxItem->_currFrame._soundId = -1;
+ gfxItem->_updFlag = true;
+ } else if (!seqItem) {
+ gfxItem->_animation = nullptr;
+ gfxItem->_currFrame._duration = 0;
+ gfxItem->_currFrame._spriteId = -1;
+ gfxItem->_currFrame._soundId = -1;
+ gfxItem->_updFlag = true;
+ } else if ((seqItem->_flags & kSeqUnk) && clockDelta > 1) {
+ if (gfxItem->_delayTicks < clockDelta) {
+ duration = clockDelta - gfxItem->_delayTicks;
+ gfxItem->_delayTicks = 0;
+ if (gfxItem->_prevFrame._duration <= duration)
+ gfxItem->_prevFrame._duration = 1;
+ else
+ gfxItem->_prevFrame._duration -= duration;
+ } else {
+ gfxItem->_delayTicks -= clockDelta;
+ }
+ gfxItem->_updFlag = false;
+ } else if (gfxItem->_delayTicks < clockDelta) {
+ duration = clockDelta - gfxItem->_delayTicks;
+ gfxItem->_delayTicks = 0;
+ if (gfxItem->_prevFrame._duration <= duration) {
+ bool v20 = false;
+ if (gfxItem->_prevFrame._duration > 0) {
+ duration -= gfxItem->_prevFrame._duration;
+ gfxItem->_prevFrame._duration = -duration;
+ } else {
+ gfxItem->_prevFrame._duration = 0;
+ v20 = true;
+ }
+ currFrameNum = gfxItem->_currFrameNum;
+ if (animation->_framesCount > currFrameNum) {
+ while (animation->_framesCount > currFrameNum
+ && animation->frames[currFrameNum]._duration <= duration) {
+ if (animation->frames[currFrameNum]._soundId != -1)
+ _soundIds.push_back((gfxItem->_sequenceId & 0xFFFF0000) | animation->frames[currFrameNum]._soundId);
+ duration -= animation->frames[currFrameNum]._duration;
+ ++currFrameNum;
+ }
+ if (animation->_framesCount > currFrameNum)
+ gfxItem->_currFrame = animation->frames[currFrameNum++];
+ else
+ gfxItem->_currFrame = animation->frames[currFrameNum - 1];
+ if (gfxItem->_currFrame._spriteId != -1 && (seqItem->_x != 0 || seqItem->_y != 0))
+ gfxItem->_currFrame._rect.translate(seqItem->_x, seqItem->_y);
+ // Update sprite scaling
+ if ((seqItem->_flags & kSeqScale) && gfxItem->_currFrame._rect.bottom >= _backgroundImageValue1 && gfxItem->_currFrame._rect.bottom <= _backgroundImageValue3) {
+ int v17 = _backgroundImageValue2 + (gfxItem->_currFrame._rect.bottom - _backgroundImageValue1) *
+ (_backgroundImageValue4 - _backgroundImageValue2) /
+ (_backgroundImageValue3 - _backgroundImageValue1);
+ gfxItem->_currFrame._rect.top = gfxItem->_currFrame._rect.bottom - v17 * (gfxItem->_currFrame._rect.bottom - gfxItem->_currFrame._rect.top) / 1000;
+ gfxItem->_currFrame._rect.right = v17 * (gfxItem->_currFrame._rect.right - gfxItem->_currFrame._rect.left) / 1000 + gfxItem->_currFrame._rect.left;
+ gfxItem->_currFrame._isScaled = true;
+ }
+ gfxItem->_currFrame._duration -= duration;
+ if (gfxItem->_currFrame._soundId != -1)
+ _soundIds.push_back((gfxItem->_sequenceId & 0xFFFF0000) | gfxItem->_currFrame._soundId);
+ gfxItem->_currFrameNum = currFrameNum;
+ gfxItem->_updFlag = true;
+ } else if (v20 && gfxItem->_prevFrame._spriteId == -1) {
+ --_gfxItemsCount;
+ if (_gfxItemsCount != i)
+ memmove(&_gfxItems[i], &_gfxItems[i + 1], sizeof(GfxItem) * (_gfxItemsCount - i));
+ --i;
+ } else {
+ gfxItem->_updFlag = false;
+ }
+ } else {
+ gfxItem->_prevFrame._duration -= duration;
+ gfxItem->_updFlag = false;
+ }
+ } else {
+ gfxItem->_delayTicks -= clockDelta;
+ gfxItem->_updFlag = false;
+ }
+ }
+ } else {
+ --_gfxItemsCount;
+ if (_gfxItemsCount != i)
+ memmove(&_gfxItems[i], &_gfxItems[i + 1], sizeof(GfxItem) * (_gfxItemsCount - i));
+ --i;
+ }
+ }
+
+ if (_newSpriteDrawItemsCount > 0) {
+ debugC(kDebugBasic, "_newSpriteDrawItemsCount: %d", _newSpriteDrawItemsCount);
+ for (int k = 0; k < _newSpriteDrawItemsCount; ++k) {
+ if (_gfxItemsCount < 50) {
+ int insertIndex;
+ seqLocateGfx(-1, _newSpriteDrawItems[k]._id, &insertIndex);
+ if (_gfxItemsCount != insertIndex)
+ memmove(&_gfxItems[insertIndex + 1], &_gfxItems[insertIndex], sizeof(GfxItem) * (_gfxItemsCount - insertIndex));
+ ++_gfxItemsCount;
+ GfxItem *gfxItem = &_gfxItems[insertIndex];
+ gfxItem->_sequenceId = -1;
+ gfxItem->_id = _newSpriteDrawItems[k]._id;
+ gfxItem->_animation = nullptr;
+ gfxItem->_currFrameNum = 0;
+ gfxItem->_flags = 1;
+ gfxItem->_delayTicks = 0;
+ gfxItem->_updFlag = true;
+ gfxItem->_updRectsCount = 0;
+ gfxItem->_surface = _newSpriteDrawItems[k]._surface;
+ gfxItem->_prevFrame._duration = 0;
+ gfxItem->_prevFrame._spriteId = -1;
+ gfxItem->_prevFrame._soundId = -1;
+ gfxItem->_currFrame._duration = 0;
+ gfxItem->_currFrame._isScaled = false;
+ gfxItem->_currFrame._rect = _newSpriteDrawItems[k]._rect;
+ gfxItem->_currFrame._spriteId = _newSpriteDrawItems[k]._surface ? 0xCAFEBABE : -1;// TODO
+ gfxItem->_currFrame._soundId = -1;
+ }
+ }
+ _newSpriteDrawItemsCount = 0;
+ }
+
+ if (_grabSpriteChanged) {
+ for (int i = 0; i < _gfxItemsCount; ++i) {
+ GfxItem *gfxItem = &_gfxItems[i];
+ if (gfxItem->_sequenceId == -1 && !gfxItem->_animation && gfxItem->_flags
+ && gfxItem->_id == _grabSpriteId && gfxItem->_surface == _grabSpriteSurface1) {
+ gfxItem->_currFrame._duration = 0;
+ gfxItem->_currFrame._isScaled = false;
+ gfxItem->_currFrame._rect = _grabSpriteRect;
+ gfxItem->_currFrame._spriteId = _grabSpriteSurface2 ? 1 : -1;// TODO
+ gfxItem->_currFrame._soundId = -1;
+ gfxItem->_updFlag = true;
+ gfxItem->_surface = _grabSpriteSurface2;
+ break;
+ }
+ }
+ _grabSpriteChanged = false;
+ }
+
+ debugC(kDebugBasic, "GameSys::fatUpdateFrame() _fatSequenceItems.size(): %d", _fatSequenceItems.size());
+
+ for (uint i = 0; i < _fatSequenceItems.size(); ++i) {
+ Sequence *seqItem = &_fatSequenceItems[i];
+ if (((seqItem->_flags & kSeqSyncWait) || (seqItem->_flags & kSeqSyncExists)) && seqItem->_sequenceId2 != -1) {
+ duration = 0;
+ if (((seqItem->_flags & kSeqSyncExists) && seqLocateGfx(seqItem->_sequenceId2, seqItem->_id2, nullptr)) ||
+ updateSequenceDuration(seqItem->_sequenceId2, seqItem->_id2, &duration)) {
+ int index = -1;
+ bool found = false;
+ if (seqItem->_sequenceId2 == seqItem->_sequenceId && seqItem->_id == seqItem->_id2 &&
+ seqFind(seqItem->_sequenceId, seqItem->_id, &index)) {
+ _seqItems[index] = *seqItem;
+ found = true;
+ } else if (_seqItems.size() < 50) {
+ index = _seqItems.size();
+ _seqItems.push_back(*seqItem);
+ found = true;
+ }
+ if (found) {
+ seqRemoveGfx(seqItem->_sequenceId2, seqItem->_id2);
+ seqRemoveGfx(seqItem->_sequenceId, seqItem->_id);
+ _fatSequenceItems.remove_at(i);
+ --i;
+ seqInsertGfx(index, duration);
+ }
+ }
+ } else {
+ if (seqItem->_totalDuration < clockDelta) {
+ int index;
+ bool found = false;
+ duration = clockDelta - seqItem->_totalDuration;
+ seqItem->_totalDuration = 0;
+ if (seqFind(seqItem->_sequenceId, seqItem->_id, &index)) {
+ _seqItems[index] = *seqItem;
+ found = true;
+ } else if (_seqItems.size() < 50) {
+ index = _seqItems.size();
+ _seqItems.push_back(*seqItem);
+ found = true;
+ }
+ if (found) {
+ seqRemoveGfx(seqItem->_sequenceId, seqItem->_id);
+ _fatSequenceItems.remove_at(i);
+ --i;
+ seqInsertGfx(index, duration - 1);
+ }
+ } else {
+ seqItem->_totalDuration -= clockDelta;
+ }
+ }
+ }
+
+ debugC(kDebugBasic, "GameSys::fatUpdateFrame() _seqItems.size(): %d", _seqItems.size());
+
+ for (uint i = 0; i < _seqItems.size(); ++i) {
+ Sequence *seqItem = &_seqItems[i];
+ if (seqLocateGfx(seqItem->_sequenceId, seqItem->_id, nullptr)) {
+ updateAnimationsStatus(seqItem->_sequenceId, seqItem->_id);
+ if (seqItem->_flags & kSeqLoop) {
+ int gfxDuration;
+ if (updateSequenceDuration(seqItem->_sequenceId, seqItem->_id, &gfxDuration)) {
+ seqRemoveGfx(seqItem->_sequenceId, seqItem->_id);
+ seqInsertGfx(i, gfxDuration);
+ }
+ }
+ } else {
+ _seqItems.remove_at(i);
+ --i;
+ }
+ }
+}
+
+void GameSys::fatUpdate() {
+ debugC(kDebugBasic, "GameSys::fatUpdate() _gfxItemsCount: %d", _gfxItemsCount);
+
+ for (int i = 0; i < _gfxItemsCount; ++i) {
+ _gfxItems[i]._updFlag = false;
+ _gfxItems[i]._updRectsCount = 0;
+ }
+
+ handleReqRemoveSequenceItem();
+ handleReqRemoveSequenceItems();
+ handleReqRemoveSpriteDrawItems();
+
+ fatUpdateFrame();
+}
+
+void GameSys::updatePlaySounds() {
+ for (uint i = 0; i < _soundIds.size(); ++i)
+ _vm->playSound(_soundIds[i], false);
+ _soundIds.clear();
+}
+
+bool intersectRect(Common::Rect &intersectingRect, const Common::Rect &r1, const Common::Rect &r2) {
+ if (r1.intersects(r2)) {
+ intersectingRect = r1.findIntersectingRect(r2);
+ return true;
+ } else
+ return false;
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/gamesys.h b/engines/gnap/gamesys.h
new file mode 100644
index 0000000000..98014f1bac
--- /dev/null
+++ b/engines/gnap/gamesys.h
@@ -0,0 +1,211 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GNAP_GAMESYS_H
+#define GNAP_GAMESYS_H
+
+#include "gnap/gnap.h"
+#include "gnap/resource.h"
+#include "common/array.h"
+#include "common/rect.h"
+#include "graphics/surface.h"
+
+namespace Gnap {
+
+const int kMaxSequenceItems = 40;
+const int kMaxSpriteDrawItems = 30;
+const int kMaxSoundIds = 50;
+const int kMaxSeqItems = 50;
+const int kMaxUpdRects = 20;
+const int kMaxGfxItems = 50;
+const int kMaxAnimations = 12;
+
+enum {
+ kSeqNone = 0x00,
+ kSeqScale = 0x01, // Enable scaling
+ kSeqLoop = 0x02, // Loop
+ kSeqUnk = 0x04, // Unknown
+ kSeqSyncWait = 0x08, // Start if other sequence is done
+ kSeqSyncExists = 0x20 // Start if other sequence exists
+};
+
+struct Sequence {
+ int32 _sequenceId;
+ int32 _id;
+ int32 _sequenceId2;
+ int32 _id2;
+ uint32 _flags;
+ int32 _totalDuration;
+ int16 _x, _y;
+};
+
+struct SpriteDrawItem {
+ int _id;
+ Common::Rect _rect;
+ Graphics::Surface *_surface;
+};
+
+struct RemoveSequenceItem {
+ int _sequenceId;
+ int _id;
+ bool _forceFrameReset;
+};
+
+struct RemoveSpriteDrawItem {
+ int _id;
+ Graphics::Surface *_surface;
+};
+
+struct GfxItem {
+ int _sequenceId;
+ int _id;
+ int _flags;
+ SequenceAnimation *_animation;
+ int _currFrameNum;
+ int _delayTicks;
+ bool _updFlag;
+ int _updRectsCount;
+ Graphics::Surface *_surface;
+ Common::Rect _updRects[kMaxUpdRects];
+ SequenceFrame _prevFrame;
+ SequenceFrame _currFrame;
+ void testUpdRect(const Common::Rect &updRect);
+};
+
+struct Animation {
+ int _sequenceId;
+ int _id;
+ int _status;
+};
+
+class GameSys {
+public:
+ GameSys(GnapEngine *vm);
+ ~GameSys();
+ void insertSequence(int sequenceId, int id, int sequenceId2, int id2, int flags, int totalDuration, int16 x, int16 y);
+ void insertDirtyRect(const Common::Rect &rect);
+ void removeSequence(int sequenceId, int id, bool resetFl);
+ void invalidateGrabCursorSprite(int id, Common::Rect &rect, Graphics::Surface *surface1, Graphics::Surface *surface2);
+ void requestClear2(bool resetFl);
+ void requestClear1();
+ void requestRemoveSequence(int sequenceId, int id);
+ void waitForUpdate();
+ int isSequenceActive(int sequenceId, int id);
+ void setBackgroundSurface(Graphics::Surface *surface, int a4, int a5, int a6, int a7);
+ void setScaleValues(int a1, int a2, int a3, int a4);
+ void insertSpriteDrawItem(Graphics::Surface *surface, int x, int y, int id);
+ void removeSpriteDrawItem(Graphics::Surface *surface, int id);
+ void drawSpriteToBackground(int x, int y, int resourceId);
+ Graphics::Surface *allocSurface(int width, int height);
+ Graphics::Surface *createSurface(int resourceId);
+ void drawSpriteToSurface(Graphics::Surface *surface, int x, int y, int resourceId);
+ void drawTextToSurface(Graphics::Surface *surface, int x, int y, byte r, byte g, byte b, const char *text);
+ int getTextHeight(const char *text);
+ int getTextWidth(const char *text);
+ void fillSurface(Graphics::Surface *surface, int x, int y, int width, int height, byte r, byte g, byte b);
+ void setAnimation(int sequenceId, int id, int animationIndex);
+ int getAnimationStatus(int animationIndex);
+ int getSpriteWidthById(int resourceId);
+ int getSpriteHeightById(int resourceId);
+ Graphics::Surface *loadBitmap(int resourceId);
+ void drawBitmap(int resourceId);
+public:
+ GnapEngine *_vm;
+
+ Common::Array<Common::Rect> _dirtyRects;
+
+ SpriteDrawItem _newSpriteDrawItems[kMaxSpriteDrawItems];
+ int _newSpriteDrawItemsCount;
+
+ RemoveSequenceItem _removeSequenceItems[kMaxSequenceItems];
+ int _removeSequenceItemsCount;
+
+ RemoveSpriteDrawItem _removeSpriteDrawItems[kMaxSpriteDrawItems];
+ int _removeSpriteDrawItemsCount;
+
+ int _grabSpriteId;
+ Common::Rect _grabSpriteRect;
+ bool _grabSpriteChanged;
+ Graphics::Surface *_grabSpriteSurface1, *_grabSpriteSurface2;
+
+ bool _reqRemoveSequenceItem;
+ int _removeSequenceItemSequenceId, _removeSequenceItemValue;
+
+ Common::Array<int> _soundIds;
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ Common::Array<Sequence> _seqItems;
+ Common::Array<Sequence> _fatSequenceItems;
+
+ GfxItem _gfxItems[kMaxGfxItems];
+ int _gfxItemsCount;
+
+ Animation _animations[kMaxAnimations];
+ int _animationsCount;
+
+ int _backgroundImageValue3, _backgroundImageValue1;
+ int _backgroundImageValue4, _backgroundImageValue2;
+
+ int32 _gameSysClock, _lastUpdateClock;
+
+ Graphics::Surface *_backgroundSurface;
+ Graphics::Surface *_frontSurface;
+ Common::Rect _screenRect;
+
+ Sequence *seqFind(int sequenceId, int id, int *outIndex);
+ int seqLocateGfx(int sequenceId, int id, int *outGfxIndex);
+ void seqInsertGfx(int index, int duration);
+ void seqRemoveGfx(int sequenceId, int id);
+ bool updateSequenceDuration(int sequenceId, int id, int *outDuration);
+ void updateAnimationsStatus(int sequenceId, int id);
+
+ void restoreBackgroundRect(const Common::Rect &rect);
+
+ void blitSurface32(Graphics::Surface *destSurface, int x, int y, Graphics::Surface *sourceSurface,
+ Common::Rect &sourceRect, bool transparent);
+ void blitSprite32(Graphics::Surface *destSurface, int x, int y, byte *sourcePixels,
+ int sourceWidth, Common::Rect &sourceRect, uint32 *sourcePalette, bool transparent);
+ void blitSpriteScaled32(Graphics::Surface *destSurface, Common::Rect &frameRect,
+ Common::Rect &destRect, byte *sourcePixels, int sourceWidth, Common::Rect &sourceRect, uint32 *sourcePalette);
+
+ void seqDrawStaticFrame(Graphics::Surface *surface, SequenceFrame &frame, Common::Rect *subRect);
+ void seqDrawSpriteFrame(SpriteResource *spriteResource, SequenceFrame &frame, Common::Rect *subRect);
+
+ void drawSprites();
+ void updateRect(const Common::Rect &r);
+ void updateScreen();
+
+ void handleReqRemoveSequenceItem();
+ void handleReqRemoveSequenceItems();
+ void handleReqRemoveSpriteDrawItems();
+ void fatUpdateFrame();
+ void fatUpdate();
+ void updatePlaySounds();
+
+};
+
+bool intersectRect(Common::Rect &intersectingRect, const Common::Rect &r1, const Common::Rect &r2);
+
+} // End of namespace Gnap
+
+#endif // GNAP_GAMESYS_H
diff --git a/engines/gnap/gnap.cpp b/engines/gnap/gnap.cpp
new file mode 100644
index 0000000000..ed2d25f3de
--- /dev/null
+++ b/engines/gnap/gnap.cpp
@@ -0,0 +1,1190 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "graphics/cursorman.h"
+#include "gnap/gnap.h"
+#include "gnap/datarchive.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/sound.h"
+
+#include "common/config-manager.h"
+#include "common/debug-channels.h"
+#include "common/timer.h"
+
+#include "engines/util.h"
+
+namespace Gnap {
+
+static const int kCursors[] = {
+ LOOK_CURSOR,
+ GRAB_CURSOR,
+ TALK_CURSOR,
+ PLAT_CURSOR
+};
+
+static const int kDisabledCursors[] = {
+ NOLOOK_CURSOR,
+ NOGRAB_CURSOR,
+ NOTALK_CURSOR,
+ NOPLAT_CURSOR
+};
+
+static const char *kCursorNames[] = {
+ "LOOK_CURSOR",
+ "GRAB_CURSOR",
+ "TALK_CURSOR",
+ "PLAT_CURSOR",
+ "NOLOOK_CURSOR",
+ "NOGRAB_CURSOR",
+ "NOTALK_CURSOR",
+ "NOPLAT_CURSOR",
+ "EXIT_L_CURSOR",
+ "EXIT_R_CURSOR",
+ "EXIT_U_CURSOR",
+ "EXIT_D_CURSOR",
+ "EXIT_NE_CURSOR",
+ "EXIT_NW_CURSOR",
+ "EXIT_SE_CURSOR",
+ "EXIT_SW_CURSOR",
+ "WAIT_CURSOR"
+};
+
+
+static const int kCursorSpriteIds[30] = {
+ 0x005, 0x008, 0x00A, 0x004, 0x009, 0x003,
+ 0x006, 0x007, 0x00D, 0x00F, 0x00B, 0x00C,
+ 0x019, 0x01C, 0x015, 0x014, 0x010, 0x01A,
+ 0x018, 0x013, 0x011, 0x012, 0x01B, 0x016,
+ 0x017, 0x01D, 0x01E, 0x01F, 0x76A, 0x76B
+};
+
+static const char *kSceneNames[] = {
+ "open", "pigpn", "truck", "creek", "mafrm", "frbrn", "inbrn", "crash",
+ "porch", "barbk", "kitch", "bar", "juke", "wash", "john", "jkbox",
+ "brawl", "stret", "frtoy", "intoy", "frgro", "park", "cash", "ingro",
+ "frcir", "booth", "circ", "outcl", "incln", "monk", "elcir", "beer",
+ "pig2", "trk2", "creek", "frbrn", "inbrn", "mafrm", "infrm", "efair",
+ "fair", "souv", "chick", "ship", "kiss", "disco", "boot", "can",
+ "can2", "drive", "tung", "puss", "space", "phone", "can3"
+};
+
+GnapEngine::GnapEngine(OSystem *syst, const ADGameDescription *gd) :
+ Engine(syst), _gameDescription(gd) {
+
+ _random = new Common::RandomSource("gnap");
+ DebugMan.addDebugChannel(kDebugBasic, "basic", "Basic debug level");
+
+ Engine::syncSoundSettings();
+ _scene = nullptr;
+ _music = nullptr;
+ _tempThumbnail = nullptr;
+
+ _wasSavegameLoaded = false;
+ for (int i = 0; i < kMaxTimers; ++i)
+ _savedTimers[i] = _timers[i] = 0;
+
+ _isWaiting = false;
+ _sceneWaiting = false;
+
+ _mousePos = Common::Point(0, 0);
+ _currGrabCursorX = _currGrabCursorY = 0;
+
+ _idleTimerIndex = -1;
+ _menuStatus = 0;
+ _menuSpritesIndex = -1;
+ _menuDone = false;
+ _menuBackgroundSurface = nullptr;
+ _menuQuitQuerySprite = nullptr;
+ _largeSprite = nullptr;
+ _menuSaveLoadSprite = nullptr;
+ _menuSprite2 = nullptr;
+ _menuSprite1 = nullptr;
+ _spriteHandle = nullptr;
+ _cursorSprite = nullptr;
+ _savegameIndex = -1;
+ _gridMinX = 0;
+ _gridMinY = 0;
+ _gridMaxX = 0;
+ _gridMaxY = 0;
+ _toyUfoNextSequenceId = -1;
+ _toyUfoSequenceId = -1;
+ _toyUfoId = -1;
+ _toyUfoActionStatus = -1;
+ _toyUfoX = 0;
+ _toyUfoY = 0;
+ _s18GarbageCanPos = 0;
+
+ for (int i = 0; i < 7; i++)
+ _savegameSprites[i] = nullptr;
+ for (int i = 0; i < 30; i++)
+ _menuInventorySprites[i] = nullptr;
+}
+
+GnapEngine::~GnapEngine() {
+ delete _random;
+ delete _music;
+ delete _tempThumbnail;
+}
+
+Common::Error GnapEngine::run() {
+ // Initialize the graphics mode to RGBA8888
+ Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
+ initGraphics(800, 600, true, &format);
+
+ // We do not support color conversion yet
+ if (_system->getScreenFormat() != format)
+ return Common::kUnsupportedColorMode;
+
+ _lastUpdateClock = 0;
+
+ // >>>>> Variable initialization
+ _cursorIndex = -1;
+ _verbCursor = 1;
+
+ _loadGameSlot = -1;
+ if (ConfMan.hasKey("save_slot"))
+ _loadGameSlot = ConfMan.getInt("save_slot");
+
+ invClear();
+ clearFlags();
+
+ _grabCursorSprite = nullptr;
+ _newGrabCursorSpriteIndex = -1;
+ _backgroundSurface = nullptr;
+ _isStockDatLoaded = false;
+ _gameDone = false;
+ _isPaused = false;
+ _pauseSprite = nullptr;
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ _exe = new Common::PEResources();
+ if (!_exe->loadFromEXE("ufos.exe"))
+ error("Could not load ufos.exe");
+
+#ifdef USE_FREETYPE2
+ Common::SeekableReadStream *stream = _exe->getResource(Common::kPEFont, 2000);
+ _font = Graphics::loadTTFFont(*stream, 24);
+ if (!_font)
+ warning("Unable to load font");
+ delete stream;
+#else
+ _font = nullptr;
+#endif
+
+ _dat = new DatManager();
+ _spriteCache = new SpriteCache(_dat);
+ _soundCache = new SoundCache(_dat);
+ _sequenceCache = new SequenceCache(_dat);
+ _gameSys = new GameSys(this);
+ _soundMan = new SoundMan(this);
+ _debugger = new Debugger(this);
+ _gnap = new PlayerGnap(this);
+ _plat = new PlayerPlat(this);
+
+ _menuBackgroundSurface = nullptr;
+
+ initGlobalSceneVars();
+ mainLoop();
+
+ delete _plat;
+ delete _gnap;
+ delete _soundMan;
+ delete _gameSys;
+ delete _sequenceCache;
+ delete _soundCache;
+ delete _spriteCache;
+ delete _dat;
+ delete _debugger;
+ delete _font;
+ delete _exe;
+
+ return Common::kNoError;
+}
+
+void GnapEngine::updateEvents() {
+ Common::Event event;
+
+ while (_eventMan->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ // Check for debugger
+ if (event.kbd.keycode == Common::KEYCODE_d && (event.kbd.flags & Common::KBD_CTRL)) {
+ // Attach to the debugger
+ _debugger->attach();
+ _debugger->onFrame();
+ }
+
+ _keyPressState[event.kbd.keycode] = 1;
+ _keyDownState[event.kbd.keycode] = 1;
+ break;
+ case Common::EVENT_KEYUP:
+ _keyDownState[event.kbd.keycode] = 0;
+ break;
+ case Common::EVENT_MOUSEMOVE:
+ _mousePos = event.mouse;
+ break;
+ case Common::EVENT_LBUTTONUP:
+ _mouseButtonState._left = false;
+ break;
+ case Common::EVENT_LBUTTONDOWN:
+ _leftClickMouseX = event.mouse.x;
+ _leftClickMouseY = event.mouse.y;
+ _mouseButtonState._left = true;
+ _mouseClickState._left = true;
+ break;
+ case Common::EVENT_RBUTTONUP:
+ _mouseButtonState._right = false;
+ break;
+ case Common::EVENT_RBUTTONDOWN:
+ _mouseButtonState._right = true;
+ _mouseClickState._right = true;
+ break;
+ case Common::EVENT_QUIT:
+ quitGame();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void GnapEngine::gameUpdateTick() {
+ updateEvents();
+
+ if (shouldQuit()) {
+ _gameDone = true;
+ _sceneDone = true;
+ }
+
+ int currClock = _system->getMillis();
+ if (currClock >= _lastUpdateClock + 66) {
+ _gameSys->fatUpdate();
+ _gameSys->drawSprites();
+ _gameSys->updateScreen();
+ _gameSys->updatePlaySounds();
+ _gameSys->_gameSysClock++;
+ updateTimers();
+ _lastUpdateClock = currClock;
+ }
+
+ _soundMan->update();
+ _system->updateScreen();
+ _system->delayMillis(5);
+}
+
+void GnapEngine::saveTimers() {
+ for (int i = 0; i < kMaxTimers; ++i )
+ _savedTimers[i] = _timers[i];
+}
+
+void GnapEngine::restoreTimers() {
+ for (int i = 0; i < kMaxTimers; ++i )
+ _timers[i] = _savedTimers[i];
+}
+
+void GnapEngine::pauseGame() {
+ if (!_isPaused) {
+ saveTimers();
+ hideCursor();
+ setGrabCursorSprite(-1);
+ _pauseSprite = _gameSys->createSurface(0x1076C);
+ _gameSys->insertSpriteDrawItem(_pauseSprite, (800 - _pauseSprite->w) / 2, (600 - _pauseSprite->h) / 2, 356);
+ _lastUpdateClock = 0;
+ gameUpdateTick();
+ playMidi("pause.mid");
+ _isPaused = true;
+ }
+}
+
+void GnapEngine::resumeGame() {
+ if (_isPaused) {
+ restoreTimers();
+ _gameSys->removeSpriteDrawItem(_pauseSprite, 356);
+ _lastUpdateClock = 0;
+ gameUpdateTick();
+ deleteSurface(&_pauseSprite);
+ stopMidi();
+ _isPaused = false;
+ clearAllKeyStatus1();
+ _mouseClickState._left = false;
+ _mouseClickState._right = false;
+ showCursor();
+ _gameSys->_gameSysClock = 0;
+ _gameSys->_lastUpdateClock = 0;
+ }
+}
+
+void GnapEngine::updatePause() {
+ while (_isPaused && !_gameDone) {
+ gameUpdateTick();
+ if (isKeyStatus1(Common::KEYCODE_p)) {
+ clearKeyStatus1(Common::KEYCODE_p);
+ resumeGame();
+ }
+ }
+}
+
+int GnapEngine::getRandom(int max) {
+ return _random->getRandomNumber(max - 1);
+}
+
+int GnapEngine::readSavegameDescription(int savegameNum, Common::String &description) {
+ description = Common::String::format("Savegame %d", savegameNum);
+ return 0;
+}
+
+int GnapEngine::loadSavegame(int savegameNum) {
+ return 1;
+}
+
+void GnapEngine::delayTicks(int val, int idx = 0, bool updateCursor = false) {
+ int startTick = _timers[idx];
+
+ _timers[idx] = val;
+
+ while (_timers[idx] && !_gameDone) {
+ gameUpdateTick();
+
+ if (updateCursor)
+ updateGrabCursorSprite(0, 0);
+ }
+
+ startTick -= _timers[idx];
+ if (startTick < 0)
+ startTick = 0;
+
+ _timers[idx] = startTick;
+}
+
+void GnapEngine::delayTicksA(int val, int idx) {
+ delayTicks(val, idx);
+}
+
+void GnapEngine::delayTicksCursor(int val) {
+ delayTicks(val, 0, true);
+}
+
+void GnapEngine::setHotspot(int index, int16 x1, int16 y1, int16 x2, int16 y2, uint16 flags,
+ int16 walkX, int16 walkY) {
+ _hotspots[index]._rect = Common::Rect(x1, y1, x2, y2);
+ _hotspots[index]._flags = flags;
+ _hotspotsWalkPos[index] = Common::Point(walkX, walkY);
+}
+
+int GnapEngine::getHotspotIndexAtPos(Common::Point pos) {
+ for (int i = 0; i < _hotspotsCount; ++i) {
+ if (!_hotspots[i].isFlag(SF_DISABLED) && _hotspots[i].isPointInside(pos))
+ return i;
+ }
+ return -1;
+}
+
+void GnapEngine::updateCursorByHotspot() {
+ if (!_isWaiting) {
+ int hotspotIndex = getHotspotIndexAtPos(_mousePos);
+
+ if (_debugger->_showHotspotNumber) {
+ // NOTE This causes some display glitches
+ char t[256];
+ sprintf(t, "hotspot = %2d", hotspotIndex);
+ if (!_font)
+ _gameSys->fillSurface(nullptr, 10, 10, 80, 16, 0, 0, 0);
+ else
+ _gameSys->fillSurface(nullptr, 8, 9, _font->getStringWidth(t) + 10, _font->getFontHeight() + 2, 0, 0, 0);
+ _gameSys->drawTextToSurface(nullptr, 10, 10, 255, 255, 255, t);
+ }
+
+ if (hotspotIndex < 0)
+ setCursor(kDisabledCursors[_verbCursor]);
+ else if (_hotspots[hotspotIndex]._flags & SF_EXIT_L_CURSOR)
+ setCursor(EXIT_L_CURSOR);
+ else if (_hotspots[hotspotIndex]._flags & SF_EXIT_R_CURSOR)
+ setCursor(EXIT_R_CURSOR);
+ else if (_hotspots[hotspotIndex]._flags & SF_EXIT_U_CURSOR)
+ setCursor(EXIT_U_CURSOR);
+ else if (_hotspots[hotspotIndex]._flags & SF_EXIT_D_CURSOR)
+ setCursor(EXIT_D_CURSOR);
+ else if (_hotspots[hotspotIndex]._flags & SF_EXIT_NE_CURSOR)
+ setCursor(EXIT_NE_CURSOR);
+ else if (_hotspots[hotspotIndex]._flags & SF_EXIT_NW_CURSOR)
+ setCursor(EXIT_NW_CURSOR);
+ else if (_hotspots[hotspotIndex]._flags & SF_EXIT_SE_CURSOR)
+ setCursor(EXIT_SE_CURSOR);
+ else if (_hotspots[hotspotIndex]._flags & SF_EXIT_SW_CURSOR)
+ setCursor(EXIT_SW_CURSOR);
+ else if (_hotspots[hotspotIndex]._flags & (1 << _verbCursor))
+ setCursor(kCursors[_verbCursor]);
+ else
+ setCursor(kDisabledCursors[_verbCursor]);
+ }
+ // Update platypus hotspot
+ _hotspots[0]._rect = Common::Rect(_gridMinX + 75 * _plat->_pos.x - 30, _gridMinY + 48 * _plat->_pos.y - 100
+ , _gridMinX + 75 * _plat->_pos.x + 30, _gridMinY + 48 * _plat->_pos.y);
+}
+
+int GnapEngine::getClickedHotspotId() {
+ int result = -1;
+ if (_isWaiting)
+ _mouseClickState._left = false;
+ else if (_mouseClickState._left) {
+ int hotspotIndex = getHotspotIndexAtPos(Common::Point(_leftClickMouseX, _leftClickMouseY));
+ if (hotspotIndex >= 0) {
+ _mouseClickState._left = false;
+ _timers[3] = 300;
+ result = hotspotIndex;
+ }
+ }
+ return result;
+}
+
+int GnapEngine::getInventoryItemSpriteNum(int index) {
+ return kCursorSpriteIds[index];
+}
+
+void GnapEngine::updateMouseCursor() {
+ if (_mouseClickState._right) {
+ // Switch through the verb cursors
+ _mouseClickState._right = false;
+ _timers[3] = 300;
+ _verbCursor = (_verbCursor + 1) % 4;
+ if (!isFlag(kGFPlatypus) && _verbCursor == PLAT_CURSOR && _cursorValue == 1)
+ _verbCursor = (_verbCursor + 1) % 4;
+ if (!_isWaiting)
+ setCursor(kDisabledCursors[_verbCursor]);
+ setGrabCursorSprite(-1);
+ }
+ if (_isWaiting && ((_gnap->_actionStatus < 0 && _plat->_actionStatus < 0) || _sceneWaiting)) {
+ setCursor(kDisabledCursors[_verbCursor]);
+ _isWaiting = false;
+ } else if (!_isWaiting && (_gnap->_actionStatus >= 0 || _plat->_actionStatus >= 0) && !_sceneWaiting) {
+ setCursor(WAIT_CURSOR);
+ _isWaiting = true;
+ }
+}
+
+void GnapEngine::setVerbCursor(int verbCursor) {
+ _verbCursor = verbCursor;
+ if (!_isWaiting)
+ setCursor(kDisabledCursors[_verbCursor]);
+}
+
+void GnapEngine::setCursor(int cursorIndex) {
+ if (_cursorIndex != cursorIndex) {
+ const char *cursorName = kCursorNames[cursorIndex];
+ Graphics::WinCursorGroup *cursorGroup = Graphics::WinCursorGroup::createCursorGroup(*_exe, Common::WinResourceID(cursorName));
+ if (cursorGroup) {
+ Graphics::Cursor *cursor = cursorGroup->cursors[0].cursor;
+ CursorMan.replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(),
+ cursor->getHotspotX(), cursor->getHotspotY(), cursor->getKeyColor());
+ CursorMan.replaceCursorPalette(cursor->getPalette(), 0, 256);
+ delete cursorGroup;
+ }
+ _cursorIndex = cursorIndex;
+ }
+}
+
+void GnapEngine::showCursor() {
+ CursorMan.showMouse(true);
+}
+
+void GnapEngine::hideCursor() {
+ CursorMan.showMouse(false);
+}
+
+void GnapEngine::setGrabCursorSprite(int index) {
+ freeGrabCursorSprite();
+ if (index >= 0) {
+ createGrabCursorSprite(makeRid(1, kCursorSpriteIds[index]));
+ setVerbCursor(GRAB_CURSOR);
+ }
+ _grabCursorSpriteIndex = index;
+}
+
+void GnapEngine::createGrabCursorSprite(int spriteId) {
+ _grabCursorSprite = _gameSys->createSurface(spriteId);
+ _gameSys->insertSpriteDrawItem(_grabCursorSprite,
+ _mousePos.x - (_grabCursorSprite->w / 2),
+ _mousePos.y - (_grabCursorSprite->h / 2),
+ 300);
+ delayTicks(5);
+}
+
+void GnapEngine::freeGrabCursorSprite() {
+ if (_grabCursorSprite) {
+ _gameSys->removeSpriteDrawItem(_grabCursorSprite, 300);
+ _gameSys->removeSpriteDrawItem(_grabCursorSprite, 301);
+ delayTicks(5);
+ deleteSurface(&_grabCursorSprite);
+ }
+}
+
+void GnapEngine::updateGrabCursorSprite(int x, int y) {
+ if (_grabCursorSprite) {
+ int newGrabCursorX = _mousePos.x - (_grabCursorSprite->w / 2) - x;
+ int newGrabCursorY = _mousePos.y - (_grabCursorSprite->h / 2) - y;
+ if (_currGrabCursorX != newGrabCursorX || _currGrabCursorY != newGrabCursorY) {
+ _currGrabCursorX = newGrabCursorX;
+ _currGrabCursorY = newGrabCursorY;
+ Common::Rect rect(newGrabCursorX, newGrabCursorY,
+ newGrabCursorX + _grabCursorSprite->w, newGrabCursorY + _grabCursorSprite->h);
+ _gameSys->invalidateGrabCursorSprite(300, rect, _grabCursorSprite, _grabCursorSprite);
+ }
+ }
+}
+
+void GnapEngine::invClear() {
+ _inventory = 0;
+}
+
+void GnapEngine::invAdd(int itemId) {
+ _inventory |= (1 << itemId);
+}
+
+void GnapEngine::invRemove(int itemId) {
+ _inventory &= ~(1 << itemId);
+}
+
+bool GnapEngine::invHas(int itemId) {
+ return (_inventory & (1 << itemId)) != 0;
+}
+
+void GnapEngine::clearFlags() {
+ _gameFlags = 0;
+}
+
+void GnapEngine::setFlag(int num) {
+ _gameFlags |= (1 << num);
+}
+
+void GnapEngine::clearFlag(int num) {
+ _gameFlags &= ~(1 << num);
+}
+
+bool GnapEngine::isFlag(int num) {
+ return (_gameFlags & (1 << num)) != 0;
+}
+
+Graphics::Surface *GnapEngine::addFullScreenSprite(int resourceId, int id) {
+ _fullScreenSpriteId = id;
+ _fullScreenSprite = _gameSys->createSurface(resourceId);
+ _gameSys->insertSpriteDrawItem(_fullScreenSprite, 0, 0, id);
+ return _fullScreenSprite;
+}
+
+void GnapEngine::removeFullScreenSprite() {
+ _gameSys->removeSpriteDrawItem(_fullScreenSprite, _fullScreenSpriteId);
+ deleteSurface(&_fullScreenSprite);
+}
+
+void GnapEngine::showFullScreenSprite(int resourceId) {
+ hideCursor();
+ setGrabCursorSprite(-1);
+ addFullScreenSprite(resourceId, 256);
+ while (!_mouseClickState._left && !isKeyStatus1(Common::KEYCODE_ESCAPE)
+ && !isKeyStatus1(Common::KEYCODE_SPACE) && !isKeyStatus1(Common::KEYCODE_RETURN) && !_gameDone) {
+ gameUpdateTick();
+ }
+ _mouseClickState._left = false;
+ clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ clearKeyStatus1(Common::KEYCODE_RETURN);
+ clearKeyStatus1(Common::KEYCODE_SPACE);
+ removeFullScreenSprite();
+ showCursor();
+}
+
+void GnapEngine::queueInsertDeviceIcon() {
+ _gameSys->insertSequence(0x10849, 20, 0, 0, kSeqNone, 0, _deviceX1, _deviceY1);
+}
+
+void GnapEngine::insertDeviceIconActive() {
+ _gameSys->insertSequence(0x1084A, 21, 0, 0, kSeqNone, 0, _deviceX1, _deviceY1);
+}
+
+void GnapEngine::removeDeviceIconActive() {
+ _gameSys->removeSequence(0x1084A, 21, true);
+}
+
+void GnapEngine::setDeviceHotspot(int hotspotIndex, int x1, int y1, int x2, int y2) {
+ _deviceX1 = x1;
+ _deviceX2 = x2;
+ _deviceY1 = y1;
+ _deviceY2 = y2;
+ if (x1 == -1)
+ _deviceX1 = 730;
+ if (x2 == -1)
+ _deviceX2 = 780;
+ if (y1 == -1)
+ _deviceY1 = 14;
+ if (y2 == -1)
+ _deviceY2 = 79;
+
+ _hotspots[hotspotIndex]._rect = Common::Rect(_deviceX1, _deviceY1, _deviceX2, _deviceY2);
+ _hotspots[hotspotIndex]._flags = SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+}
+
+int GnapEngine::getSequenceTotalDuration(int resourceId) {
+ SequenceResource *sequenceResource = _sequenceCache->get(resourceId);
+ int maxValue = 0;
+ for (int i = 0; i < sequenceResource->_animationsCount; ++i) {
+ SequenceAnimation *animation = &sequenceResource->_animations[i];
+ if (animation->_additionalDelay + animation->_maxTotalDuration > maxValue)
+ maxValue = animation->_additionalDelay + animation->_maxTotalDuration;
+ }
+ int totalDuration = maxValue + sequenceResource->_totalDuration;
+ _sequenceCache->release(resourceId);
+ return totalDuration;
+}
+
+bool GnapEngine::isSoundPlaying(int resourceId) {
+ return _soundMan->isSoundPlaying(resourceId);
+}
+
+void GnapEngine::playSound(int resourceId, bool looping) {
+ debugC(kDebugBasic, "playSound(%08X, %d)", resourceId, looping);
+ _soundMan->playSound(resourceId, looping);
+}
+
+void GnapEngine::stopSound(int resourceId) {
+ _soundMan->stopSound(resourceId);
+}
+
+void GnapEngine::setSoundVolume(int resourceId, int volume) {
+ _soundMan->setSoundVolume(resourceId, volume);
+}
+
+void GnapEngine::updateTimers() {
+ for (int i = 0; i < kMaxTimers; ++i)
+ if (_timers[i] > 0)
+ --_timers[i];
+}
+
+void GnapEngine::initGameFlags(int num) {
+ invClear();
+ invAdd(kItemMagazine);
+ switch (num) {
+ case 1:
+ setFlag(kGFPlatypusTalkingToAssistant);
+ break;
+ case 2:
+ clearFlags();
+ break;
+ case 3:
+ invAdd(kItemDiceQuarterHole);
+ clearFlags();
+ break;
+ case 4:
+ invAdd(kItemDiceQuarterHole);
+ invAdd(kItemHorn);
+ invAdd(kItemLightbulb);
+ clearFlags();
+ setFlag(kGFPlatypus);
+ setFlag(kGFMudTaken);
+ setFlag(kGFNeedleTaken);
+ setFlag(kGFTwigTaken);
+ setFlag(kGFUnk04);
+ setFlag(kGFKeysTaken);
+ setFlag(kGFGrassTaken);
+ setFlag(kGFBarnPadlockOpen);
+ break;
+ }
+}
+
+void GnapEngine::loadStockDat() {
+ if (!_isStockDatLoaded) {
+ _isStockDatLoaded = true;
+ _dat->open(1, "stock_n.dat");
+ // The pre-loading of data is skipped as it's no longer required on modern hardware
+ }
+}
+
+void GnapEngine::mainLoop() {
+ _newCursorValue = 1;
+ _cursorValue = -1;
+ _newSceneNum = 0;
+ _currentSceneNum = 55;
+ _prevSceneNum = 55;
+ invClear();
+ clearFlags();
+ _grabCursorSpriteIndex = -1;
+ _grabCursorSprite = nullptr;
+
+ loadStockDat();
+
+ if (_loadGameSlot != -1) {
+ // Load a savegame
+ int slot = _loadGameSlot;
+ _loadGameSlot = -1;
+ loadGameState(slot);
+ _wasSavegameLoaded = true;
+
+ showCursor();
+ }
+
+ while (!_gameDone) {
+ debugC(kDebugBasic, "New scene: %d", _newSceneNum);
+
+ _prevSceneNum = _currentSceneNum;
+ _currentSceneNum = _newSceneNum;
+
+ debugC(kDebugBasic, "GnapEngine::mainLoop() _prevSceneNum: %d; _currentSceneNum: %d", _prevSceneNum, _currentSceneNum);
+
+ if (_newCursorValue != _cursorValue) {
+ debugC(kDebugBasic, "_newCursorValue: %d", _newCursorValue);
+ _cursorValue = _newCursorValue;
+ if (!_wasSavegameLoaded)
+ initGameFlags(_cursorValue);
+ }
+
+ _sceneSavegameLoaded = _wasSavegameLoaded;
+ _wasSavegameLoaded = false;
+
+ initScene();
+
+ runSceneLogic();
+ afterScene();
+
+ _soundMan->stopAll();
+
+ // Force purge all resources
+ _sequenceCache->purge(true);
+ _soundCache->purge(true);
+ _spriteCache->purge(true);
+ }
+
+ if (_backgroundSurface)
+ deleteSurface(&_backgroundSurface);
+
+ _dat->close(1);
+}
+
+void GnapEngine::initScene() {
+ Common::String datFilename;
+
+ _isLeavingScene = false;
+ _sceneDone = false;
+ _newSceneNum = 55;
+ _gnap->_actionStatus = -1;
+ _plat->_actionStatus = -1;
+ _gnap->initBrainPulseRndValue();
+ hideCursor();
+ clearAllKeyStatus1();
+ _mouseClickState._left = false;
+ _mouseClickState._right = false;
+ _sceneClickedHotspot = -1;
+
+ datFilename = Common::String::format("%s_n.dat", kSceneNames[_currentSceneNum]);
+
+ debugC(kDebugBasic, "GnapEngine::initScene() datFilename: %s", datFilename.c_str());
+
+ _dat->open(0, datFilename.c_str());
+
+ int backgroundId = initSceneLogic();
+
+ if (!_backgroundSurface) {
+ if (_currentSceneNum != 0)
+ _backgroundSurface = _gameSys->loadBitmap(makeRid(1, 0x8AA));
+ else
+ _backgroundSurface = _gameSys->loadBitmap(makeRid(0, backgroundId));
+ _gameSys->setBackgroundSurface(_backgroundSurface, 0, 500, 1, 1000);
+ }
+
+ if (_currentSceneNum != 0 && _currentSceneNum != 16 && _currentSceneNum != 47 &&
+ _currentSceneNum != 48 && _currentSceneNum != 54) {
+ _gameSys->drawBitmap(backgroundId);
+ }
+
+ if ((_cursorValue == 4 && isFlag(kGFGnapControlsToyUFO)) || _currentSceneNum == 41)
+ playSound(makeRid(1, 0x8F6), true);
+
+}
+
+void GnapEngine::endSceneInit() {
+ showCursor();
+ if (_newGrabCursorSpriteIndex >= 0)
+ setGrabCursorSprite(_newGrabCursorSpriteIndex);
+}
+
+void GnapEngine::afterScene() {
+ if (_gameDone)
+ return;
+
+ if (_newCursorValue == _cursorValue && _newSceneNum != 0 && _newSceneNum != 16 &&
+ _newSceneNum != 47 && _newSceneNum != 48 && _newSceneNum != 54 && _newSceneNum != 49 &&
+ _newSceneNum != 50 && _newSceneNum != 51 && _newSceneNum != 52)
+ _newGrabCursorSpriteIndex = _grabCursorSpriteIndex;
+ else
+ _newGrabCursorSpriteIndex = -1;
+
+ setGrabCursorSprite(-1);
+
+ _gameSys->requestClear2(false);
+ _gameSys->requestClear1();
+ _gameSys->waitForUpdate();
+
+ _gameSys->requestClear2(false);
+ _gameSys->requestClear1();
+ _gameSys->waitForUpdate();
+
+ screenEffect(0, 0, 0, 0);
+
+ _dat->close(0);
+
+ for (int animationIndex = 0; animationIndex < 12; ++animationIndex)
+ _gameSys->setAnimation(0, 0, animationIndex);
+
+ clearKeyStatus1(Common::KEYCODE_p);
+
+ _mouseClickState._left = false;
+ _mouseClickState._right = false;
+
+}
+
+void GnapEngine::checkGameKeys() {
+ if (isKeyStatus1(Common::KEYCODE_p)) {
+ clearKeyStatus1(Common::KEYCODE_p);
+ pauseGame();
+ updatePause();
+ }
+}
+
+void GnapEngine::startSoundTimerA(int timerIndex) {
+ _soundTimerIndexA = timerIndex;
+ _timers[timerIndex] = getRandom(50) + 100;
+}
+
+int GnapEngine::playSoundA() {
+ static const int kSoundIdsA[] = {
+ 0x93E, 0x93F, 0x941, 0x942, 0x943, 0x944,
+ 0x945, 0x946, 0x947, 0x948, 0x949
+ };
+
+ int soundId = -1;
+
+ if (!_timers[_soundTimerIndexA]) {
+ _timers[_soundTimerIndexA] = getRandom(50) + 100;
+ soundId = kSoundIdsA[getRandom(11)];
+ playSound(soundId | 0x10000, false);
+ }
+ return soundId;
+}
+
+void GnapEngine::startSoundTimerB(int timerIndex) {
+ _soundTimerIndexB = timerIndex;
+ _timers[timerIndex] = getRandom(50) + 150;
+}
+
+int GnapEngine::playSoundB() {
+ static const int kSoundIdsB[] = {
+ 0x93D, 0x929, 0x92A, 0x92B, 0x92C, 0x92D,
+ 0x92E, 0x92F, 0x930, 0x931, 0x932, 0x933,
+ 0x934, 0x935, 0x936, 0x937, 0x938, 0x939,
+ 0x93A
+ };
+
+ int soundId = -1;
+
+ if (!_timers[_soundTimerIndexB]) {
+ _timers[_soundTimerIndexB] = getRandom(50) + 150;
+ soundId = kSoundIdsB[getRandom(19)];
+ playSound(soundId | 0x10000, false);
+ }
+ return soundId;
+}
+
+void GnapEngine::startSoundTimerC(int timerIndex) {
+ _soundTimerIndexC = timerIndex;
+ _timers[timerIndex] = getRandom(50) + 150;
+}
+
+int GnapEngine::playSoundC() {
+ static const int kSoundIdsC[] = {
+ 0x918, 0x91F, 0x920, 0x922, 0x923, 0x924,
+ 0x926
+ };
+
+ int soundId = -1;
+
+ if (!_timers[_soundTimerIndexC]) {
+ _timers[_soundTimerIndexC] = getRandom(50) + 150;
+ soundId = kSoundIdsC[getRandom(7)] ;
+ playSound(soundId | 0x10000, false);
+ }
+ return soundId;
+}
+
+void GnapEngine::startIdleTimer(int timerIndex) {
+ _idleTimerIndex = timerIndex;
+ _timers[timerIndex] = 3000;
+}
+
+void GnapEngine::updateIdleTimer() {
+ if (!_timers[_idleTimerIndex]) {
+ _timers[_idleTimerIndex] = 3000;
+ _gameSys->insertSequence(0x1088B, 255, 0, 0, kSeqNone, 0, 0, 75);
+ }
+}
+
+void GnapEngine::screenEffect(int dir, byte r, byte g, byte b) {
+ int startVal = 0;
+ if (dir == 1)
+ startVal = 300;
+
+ for (int y = startVal; y < startVal + 300 && !_gameDone; y += 50) {
+ _gameSys->fillSurface(nullptr, 0, y, 800, 50, r, g, b);
+ _gameSys->fillSurface(nullptr, 0, 549 - y + 1, 800, 50, r, g, b);
+ gameUpdateTick();
+ _system->delayMillis(50);
+ }
+}
+
+bool GnapEngine::isKeyStatus1(int key) {
+ return _keyPressState[key] != 0;
+}
+
+bool GnapEngine::isKeyStatus2(int key) {
+ return _keyDownState[key] != 0;
+}
+
+void GnapEngine::clearKeyStatus1(int key) {
+ _keyPressState[key] = 0;
+ _keyDownState[key] = 0;
+}
+
+void GnapEngine::clearAllKeyStatus1() {
+ _keyStatus1[0] = 0;
+ _keyStatus1[1] = 0;
+ memset(_keyPressState, 0, sizeof(_keyPressState));
+ memset(_keyDownState, 0, sizeof(_keyDownState));
+}
+
+void GnapEngine::deleteSurface(Graphics::Surface **surface) {
+ if (surface && *surface) {
+ (*surface)->free();
+ delete *surface;
+ *surface = nullptr;
+ }
+}
+
+bool GnapEngine::testWalk(int animationIndex, int someStatus, int gridX1, int gridY1, int gridX2, int gridY2) {
+ if (_mouseClickState._left && someStatus == _gnap->_actionStatus) {
+ _isLeavingScene = false;
+ _gameSys->setAnimation(0, 0, animationIndex);
+ _gnap->_actionStatus = -1;
+ _plat->_actionStatus = -1;
+ _gnap->walkTo(Common::Point(gridX1, gridY1), -1, -1, 1);
+ _plat->walkTo(Common::Point(gridX2, gridY2), -1, -1, 1);
+ _mouseClickState._left = false;
+ return true;
+ }
+ return false;
+}
+
+void GnapEngine::doCallback(int callback) {
+ switch (callback) {
+ case 8:
+ case 10:
+ case 20:
+ _scene->updateAnimationsCb();
+ break;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GnapEngine::initGlobalSceneVars() {
+ // Shared by scenes 17 && 18
+ _s18GarbageCanPos = 8;
+
+ // Toy UFO
+ _toyUfoId = 0;
+ _toyUfoActionStatus = -1;
+ _toyUfoX = 0;
+ _toyUfoY = 50;
+}
+
+void GnapEngine::playSequences(int fullScreenSpriteId, int sequenceId1, int sequenceId2, int sequenceId3) {
+ setGrabCursorSprite(-1);
+ _gameSys->setAnimation(sequenceId2, _gnap->_id, 0);
+ _gameSys->insertSequence(sequenceId2, _gnap->_id,
+ makeRid(_gnap->_sequenceDatNum, _gnap->_sequenceId), _gnap->_id,
+ kSeqSyncWait, 0, 15 * (5 * _gnap->_pos.x - 25), 48 * (_gnap->_pos.y - 8));
+ _gnap->_sequenceId = sequenceId2;
+ _gnap->_sequenceDatNum = 0;
+ while (_gameSys->getAnimationStatus(0) != 2 && !_gameDone)
+ gameUpdateTick();
+ hideCursor();
+ addFullScreenSprite(fullScreenSpriteId, 255);
+ _gameSys->setAnimation(sequenceId1, 256, 0);
+ _gameSys->insertSequence(sequenceId1, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (_gameSys->getAnimationStatus(0) != 2 && !_gameDone)
+ gameUpdateTick();
+ _gameSys->setAnimation(sequenceId3, _gnap->_id, 0);
+ _gameSys->insertSequence(sequenceId3, _gnap->_id,
+ makeRid(_gnap->_sequenceDatNum, _gnap->_sequenceId), _gnap->_id,
+ kSeqSyncWait, 0, 15 * (5 * _gnap->_pos.x - 25), 48 * (_gnap->_pos.y - 8));
+ removeFullScreenSprite();
+ showCursor();
+ _gnap->_sequenceId = sequenceId3;
+}
+
+void GnapEngine::toyUfoSetStatus(int flagNum) {
+ clearFlag(kGFUnk16);
+ clearFlag(kGFJointTaken);
+ clearFlag(kGFUnk18);
+ clearFlag(kGFGroceryStoreHatTaken);
+ setFlag(flagNum);
+}
+
+int GnapEngine::toyUfoGetSequenceId() {
+ if (isFlag(kGFUnk16))
+ return 0x84E;
+ if (isFlag(kGFJointTaken))
+ return 0x84B;
+ if (isFlag(kGFUnk18))
+ return 0x84D;
+ if (isFlag(kGFGroceryStoreHatTaken))
+ return 0x84C;
+ return 0x84E;
+}
+
+bool GnapEngine::toyUfoCheckTimer() {
+ if (!isFlag(kGFGnapControlsToyUFO) || isFlag(kGFUnk18) || _timers[9] ||
+ _toyUfoSequenceId == 0x870 || _toyUfoSequenceId == 0x871 || _toyUfoSequenceId == 0x872 || _toyUfoSequenceId == 0x873)
+ return false;
+ _sceneDone = true;
+ _newSceneNum = 41;
+ return true;
+}
+
+void GnapEngine::toyUfoFlyTo(int destX, int destY, int minX, int maxX, int minY, int maxY, int animationIndex) {
+ GridStruct flyNodes[34];
+
+ if (destX == -1)
+ destX = _leftClickMouseX;
+
+ if (destY == -1)
+ destY = _leftClickMouseY;
+
+ int clippedDestX = CLIP(destX, minX, maxX);
+ int clippedDestY = CLIP(destY, minY, maxY);
+ int dirX = 0, dirY = 0; // 0, -1 or 1
+
+ if (clippedDestX != _toyUfoX)
+ dirX = (clippedDestX - _toyUfoX) / ABS(clippedDestX - _toyUfoX);
+
+ if (clippedDestY != _toyUfoY)
+ dirY = (clippedDestY - _toyUfoY) / ABS(clippedDestY - _toyUfoY);
+
+ int deltaX = ABS(clippedDestX - _toyUfoX);
+ int deltaY = ABS(clippedDestY - _toyUfoY);
+
+ int i = 0;
+ if (deltaY > deltaX) {
+ int flyDirYIncr = 32;
+ int gridDistY = deltaY / flyDirYIncr;
+ int curMove = 0;
+ while (curMove < deltaY && i < 34) {
+ if (gridDistY - 5 >= i) {
+ flyDirYIncr = MIN(36, 8 * i + 8);
+ } else {
+ flyDirYIncr = MAX(6, flyDirYIncr - 3);
+ }
+ curMove += flyDirYIncr;
+ flyNodes[i]._gridX1 = _toyUfoX + dirX * deltaX * curMove / deltaY;
+ flyNodes[i]._gridY1 = _toyUfoY + dirY * curMove;
+ ++i;
+ }
+ } else {
+ int flyDirXIncr = 36;
+ int gridDistX = deltaX / flyDirXIncr;
+ int curMove = 0;
+ while (curMove < deltaX && i < 34) {
+ if (gridDistX - 5 >= i) {
+ flyDirXIncr = MIN(38, 8 * i + 8);
+ } else {
+ flyDirXIncr = MAX(6, flyDirXIncr - 3);
+ }
+ curMove += flyDirXIncr;
+ flyNodes[i]._gridX1 = _toyUfoX + dirX * curMove;
+ flyNodes[i]._gridY1 = _toyUfoY + dirY * deltaY * curMove / deltaX;
+ ++i;
+ }
+ }
+
+ int nodesCount = i - 1;
+
+ _toyUfoX = clippedDestX;
+ _toyUfoY = clippedDestY;
+
+ if (nodesCount > 0) {
+ int seqId = 0;
+ if (isFlag(kGFUnk16))
+ seqId = 0x867;
+ else if (isFlag(kGFJointTaken))
+ seqId = 0x84F;
+ else if (isFlag(kGFUnk18))
+ seqId = 0x85F;
+ else if (isFlag(kGFGroceryStoreHatTaken))
+ seqId = 0x857;
+ else
+ error("Unhandled flag in GnapEngine::toyUfoFlyTo(): 0x%x", _gameFlags);
+ flyNodes[0]._sequenceId = seqId;
+ flyNodes[0]._id = 0;
+ _gameSys->insertSequence(seqId | 0x10000, 0,
+ _toyUfoSequenceId | 0x10000, _toyUfoId,
+ kSeqSyncWait, 0, flyNodes[0]._gridX1 - 365, flyNodes[0]._gridY1 - 128);
+ for (i = 1; i < nodesCount; ++i) {
+ flyNodes[i]._sequenceId = seqId + (i % 8);
+ flyNodes[i]._id = i;
+ _gameSys->insertSequence(flyNodes[i]._sequenceId | 0x10000, flyNodes[i]._id,
+ flyNodes[i - 1]._sequenceId | 0x10000, flyNodes[i - 1]._id,
+ kSeqSyncWait, 0,
+ flyNodes[i]._gridX1 - 365, flyNodes[i]._gridY1 - 128);
+ }
+
+ _toyUfoSequenceId = flyNodes[nodesCount - 1]._sequenceId;
+ _toyUfoId = flyNodes[nodesCount - 1]._id;
+
+ if (animationIndex >= 0)
+ _gameSys->setAnimation(_toyUfoSequenceId | 0x10000, _toyUfoId, animationIndex);
+
+ }
+}
+
+void GnapEngine::playMidi(const char *name) {
+ if (_music)
+ return;
+
+ _music = new MusicPlayer(name);
+ _music->playSMF(true);
+}
+
+void GnapEngine::stopMidi() {
+ if (_music) {
+ _music->stop();
+ delete _music;
+ _music = nullptr;
+ }
+}
+} // End of namespace Gnap
diff --git a/engines/gnap/gnap.h b/engines/gnap/gnap.h
new file mode 100644
index 0000000000..84c40e2969
--- /dev/null
+++ b/engines/gnap/gnap.h
@@ -0,0 +1,477 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 GNAP_GNAP_H
+#define GNAP_GNAP_H
+
+#include "common/array.h"
+#include "common/events.h"
+#include "common/file.h"
+#include "common/memstream.h"
+#include "common/random.h"
+#include "common/savefile.h"
+#include "common/serializer.h"
+#include "common/str.h"
+#include "common/substream.h"
+#include "common/system.h"
+#include "common/winexe.h"
+#include "common/winexe_pe.h"
+#include "engines/engine.h"
+#include "graphics/pixelformat.h"
+#include "graphics/wincursor.h"
+#include "graphics/fontman.h"
+#include "graphics/font.h"
+#include "graphics/fonts/ttf.h"
+
+#include "gnap/debugger.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/scenecore.h"
+#include "gnap/character.h"
+#include "gnap/music.h"
+
+struct ADGameDescription;
+
+namespace Gnap {
+
+class DatManager;
+class SequenceResource;
+class SpriteResource;
+class GameSys;
+class SoundMan;
+class MusicPlayer;
+
+#define GNAP_SAVEGAME_VERSION 2
+
+struct MouseButtonState {
+ bool _left;
+ bool _right;
+ MouseButtonState() : _left(false), _right(false) {
+ }
+};
+
+struct Hotspot {
+ Common::Rect _rect;
+ uint16 _flags;
+
+ bool isPointInside(Common::Point pos) const {
+ return _rect.contains(pos);
+ }
+
+ bool isFlag(uint16 flag) const {
+ return (_flags & flag) != 0;
+ }
+
+ void clearRect() {
+ _rect = Common::Rect(0, 0, 0, 0);
+ }
+};
+
+const int kMaxTimers = 10;
+
+enum GnapDebugChannels {
+ kDebugBasic = 1 << 0,
+ kDebugMusic = 1 << 1
+};
+
+enum {
+ SF_NONE = 0x0000,
+ SF_LOOK_CURSOR = 0x0001,
+ SF_GRAB_CURSOR = 0x0002,
+ SF_TALK_CURSOR = 0x0004,
+ SF_PLAT_CURSOR = 0x0008,
+ SF_DISABLED = 0x0010,
+ SF_WALKABLE = 0x0020,
+ SF_EXIT_L_CURSOR = 0x0040,
+ SF_EXIT_R_CURSOR = 0x0080,
+ SF_EXIT_U_CURSOR = 0x0100,
+ SF_EXIT_D_CURSOR = 0x0200,
+ SF_EXIT_NW_CURSOR = 0x0400,
+ SF_EXIT_NE_CURSOR = 0x0800,
+ SF_EXIT_SW_CURSOR = 0x1000,
+ SF_EXIT_SE_CURSOR = 0x2000
+};
+
+enum {
+ LOOK_CURSOR = 0,
+ GRAB_CURSOR = 1,
+ TALK_CURSOR = 2,
+ PLAT_CURSOR = 3,
+ NOLOOK_CURSOR = 4,
+ NOGRAB_CURSOR = 5,
+ NOTALK_CURSOR = 6,
+ NOPLAT_CURSOR = 7,
+ EXIT_L_CURSOR = 8,
+ EXIT_R_CURSOR = 9,
+ EXIT_U_CURSOR = 10,
+ EXIT_D_CURSOR = 11,
+ EXIT_NE_CURSOR = 12,
+ EXIT_NW_CURSOR = 13,
+ EXIT_SE_CURSOR = 14,
+ EXIT_SW_CURSOR = 15,
+ WAIT_CURSOR = 16
+};
+
+enum {
+ kGSPullOutDevice = 0,
+ kGSPullOutDeviceNonWorking = 1,
+ kGSIdle = 2,
+ kGSBrainPulsating = 3,
+ kGSImpossible = 4,
+ kGSScratchingHead = 5,
+ kGSDeflect = 6,
+ kGSUseDevice = 7,
+ kGSMoan1 = 8,
+ kGSMoan2 = 9
+};
+
+enum {
+ kItemMagazine = 0,
+ kItemMud = 1,
+ kItemGrass = 2,
+ kItemDisguise = 3,
+ kItemNeedle = 4,
+ kItemTwig = 5,
+ kItemGas = 6,
+ kItemKeys = 7,
+ kItemDice = 8,
+ kItemTongs = 9,
+ kItemQuarter = 10,
+ kItemQuarterWithHole = 11,
+ kItemDiceQuarterHole = 12,
+ kItemWrench = 13,
+ kItemCowboyHat = 14,
+ kItemGroceryStoreHat = 15,
+ kItemBanana = 16,
+ kItemTickets = 17,
+ kItemPicture = 18,
+ kItemEmptyBucket = 19,
+ kItemBucketWithBeer = 20,
+ kItemBucketWithPill = 21,
+ kItemPill = 22,
+ kItemHorn = 23,
+ kItemJoint = 24,
+ kItemChickenBucket = 25,
+ kItemGum = 26,
+ kItemSpring = 27,
+ kItemLightbulb = 28,
+ kItemCereals = 29
+};
+
+enum {
+ kGFPlatypus = 0,
+ kGFMudTaken = 1,
+ kGFNeedleTaken = 2,
+ kGFTwigTaken = 3,
+ kGFUnk04 = 4,
+ kGFKeysTaken = 5,
+ kGFGrassTaken = 6,
+ kGFBarnPadlockOpen = 7,
+ kGFTruckFilledWithGas = 8,
+ kGFTruckKeysUsed = 9,
+ kGFPlatypusDisguised = 10,
+ kGFSceneFlag1 = 11,
+ kGFGnapControlsToyUFO = 12,
+ kGFUnk13 = 13, // Tongue Fight Won?
+ kGFUnk14 = 14,
+ kGFSpringTaken = 15,
+ kGFUnk16 = 16,
+ kGFJointTaken = 17,
+ kGFUnk18 = 18,
+ kGFGroceryStoreHatTaken = 19,
+ kGFPictureTaken = 20,
+ kGFUnk21 = 21,
+ kGFUnk22 = 22,
+ kGFUnk23 = 23,
+ kGFUnk24 = 24,
+ kGFUnk25 = 25,
+ kGFPlatypusTalkingToAssistant = 26,
+ kGFUnk27 = 27,
+ kGFUnk28 = 28,
+ kGFGasTaken = 29,
+ kGFUnk30 = 30,
+ kGFUnk31 = 31
+};
+
+struct GnapSavegameHeader {
+ uint8 _version;
+ Common::String _saveName;
+ Graphics::Surface *_thumbnail;
+ int _year, _month, _day;
+ int _hour, _minute;
+};
+
+class GnapEngine : public Engine {
+protected:
+ Common::Error run();
+ virtual bool hasFeature(EngineFeature f) const;
+public:
+ GnapEngine(OSystem *syst, const ADGameDescription *gd);
+ ~GnapEngine();
+private:
+ const ADGameDescription *_gameDescription;
+ Graphics::PixelFormat _pixelFormat;
+ int _loadGameSlot;
+
+public:
+ Common::RandomSource *_random;
+ Common::PEResources *_exe;
+
+ DatManager *_dat;
+ SpriteCache *_spriteCache;
+ SoundCache *_soundCache;
+ SequenceCache *_sequenceCache;
+ GameSys *_gameSys;
+ SoundMan *_soundMan;
+ Debugger *_debugger;
+ Scene *_scene;
+ PlayerGnap *_gnap;
+ PlayerPlat *_plat;
+ MusicPlayer *_music;
+ Graphics::Font *_font;
+
+ Common::MemoryWriteStreamDynamic *_tempThumbnail;
+
+ int _lastUpdateClock;
+ bool _gameDone;
+
+ byte _keyPressState[512];
+ byte _keyDownState[512];
+
+ bool _isPaused;
+ Graphics::Surface *_pauseSprite;
+ int _timers[kMaxTimers], _savedTimers[kMaxTimers];
+
+ MouseButtonState _mouseButtonState;
+ MouseButtonState _mouseClickState;
+
+ uint32 _keyStatus1[2];
+
+ bool _sceneSavegameLoaded, _wasSavegameLoaded;
+
+ Graphics::Surface *_backgroundSurface;
+ int _prevSceneNum, _currentSceneNum, _newSceneNum;
+ bool _sceneDone, _sceneWaiting;
+
+ uint32 _inventory, _gameFlags;
+
+ Hotspot _hotspots[20];
+ Common::Point _hotspotsWalkPos[20];
+ int _hotspotsCount;
+ int _sceneClickedHotspot;
+
+ bool _isWaiting;
+ bool _isLeavingScene;
+
+ bool _isStockDatLoaded;
+
+ int _newCursorValue, _cursorValue;
+
+ int _verbCursor, _cursorIndex;
+ Common::Point _mousePos;
+ int _leftClickMouseX, _leftClickMouseY;
+
+ Graphics::Surface *_grabCursorSprite;
+ int _currGrabCursorX, _currGrabCursorY;
+ int _grabCursorSpriteIndex, _newGrabCursorSpriteIndex;
+
+ Graphics::Surface *_fullScreenSprite;
+ int _fullScreenSpriteId;
+
+ int _deviceX1, _deviceY1, _deviceX2, _deviceY2;
+
+ int _soundTimerIndexA;
+ int _soundTimerIndexB;
+ int _soundTimerIndexC;
+ int _idleTimerIndex;
+
+ void updateEvents();
+ void gameUpdateTick();
+ void saveTimers();
+ void restoreTimers();
+
+ void pauseGame();
+ void resumeGame();
+ void updatePause();
+
+ int getRandom(int max);
+
+ int readSavegameDescription(int savegameNum, Common::String &description);
+ int loadSavegame(int savegameNum);
+ Common::Error saveGameState(int slot, const Common::String &desc);
+ Common::Error loadGameState(int slot);
+ Common::String generateSaveName(int slot);
+ void synchronize(Common::Serializer &s);
+ void writeSavegameHeader(Common::OutSaveFile *out, GnapSavegameHeader &header);
+ static bool readSavegameHeader(Common::InSaveFile *in, GnapSavegameHeader &header);
+
+ void delayTicks(int val, int idx, bool updateCursor);
+ void delayTicksA(int val, int idx);
+ void delayTicksCursor(int val);
+
+ void setHotspot(int index, int16 x1, int16 y1, int16 x2, int16 y2, uint16 flags = SF_NONE,
+ int16 walkX = -1, int16 walkY = -1);
+ int getHotspotIndexAtPos(Common::Point pos);
+ void updateCursorByHotspot();
+ int getClickedHotspotId();
+
+ int getInventoryItemSpriteNum(int index);
+
+ void updateMouseCursor();
+ void setVerbCursor(int verbCursor);
+ void setCursor(int cursorIndex);
+ void showCursor();
+ void hideCursor();
+
+ void setGrabCursorSprite(int index);
+ void createGrabCursorSprite(int spriteId);
+ void freeGrabCursorSprite();
+ void updateGrabCursorSprite(int x, int y);
+
+ void invClear();
+ void invAdd(int itemId);
+ void invRemove(int itemId);
+ bool invHas(int itemId);
+
+ void clearFlags();
+ void setFlag(int num);
+ void clearFlag(int num);
+ bool isFlag(int num);
+
+ Graphics::Surface *addFullScreenSprite(int resourceId, int id);
+ void removeFullScreenSprite();
+ void showFullScreenSprite(int resourceId);
+
+ void queueInsertDeviceIcon();
+ void insertDeviceIconActive();
+ void removeDeviceIconActive();
+ void setDeviceHotspot(int hotspotIndex, int x1, int y1, int x2, int y2);
+
+ int getSequenceTotalDuration(int resourceId);
+
+ bool isSoundPlaying(int resourceId);
+ void playSound(int resourceId, bool looping);
+ void stopSound(int resourceId);
+ void setSoundVolume(int resourceId, int volume);
+
+ void updateTimers();
+
+ void initGameFlags(int num);
+ void loadStockDat();
+
+ void mainLoop();
+ void initScene();
+ void endSceneInit();
+ void afterScene();
+
+ int initSceneLogic();
+ void runSceneLogic();
+
+ void checkGameKeys();
+
+ void startSoundTimerA(int timerIndex);
+ int playSoundA();
+ void startSoundTimerB(int timerIndex);
+ int playSoundB();
+ void startSoundTimerC(int timerIndex);
+ int playSoundC();
+ void startIdleTimer(int timerIndex);
+ void updateIdleTimer();
+
+ void screenEffect(int dir, byte r, byte g, byte b);
+
+ bool isKeyStatus1(int key);
+ bool isKeyStatus2(int key);
+ void clearKeyStatus1(int key);
+ void clearAllKeyStatus1();
+
+ void deleteSurface(Graphics::Surface **surface);
+
+ // Menu
+ int _menuStatus;
+ int _menuSpritesIndex;
+ bool _menuDone;
+ Graphics::Surface *_menuBackgroundSurface;
+ Graphics::Surface *_menuQuitQuerySprite;
+ Graphics::Surface *_largeSprite;
+ Graphics::Surface *_menuSaveLoadSprite;
+ Graphics::Surface *_menuSprite2;
+ Graphics::Surface *_menuSprite1;
+ char _savegameFilenames[7][30];
+ Graphics::Surface *_savegameSprites[7];
+ Graphics::Surface *_spriteHandle;
+ Graphics::Surface *_cursorSprite;
+ int _menuInventoryIndices[30];
+ Graphics::Surface *_menuInventorySprites[30];
+ int _savegameIndex;
+ void createMenuSprite();
+ void freeMenuSprite();
+ void initMenuHotspots1();
+ void initMenuHotspots2();
+ void initMenuQuitQueryHotspots();
+ void initSaveLoadHotspots();
+ void drawInventoryFrames();
+ void insertInventorySprites();
+ void removeInventorySprites();
+ void runMenu();
+ void updateMenuStatusInventory();
+ void updateMenuStatusMainMenu();
+ void updateMenuStatusSaveGame();
+ void updateMenuStatusLoadGame();
+ void updateMenuStatusQueryQuit();
+
+ // Grid common
+ int _gridMinX, _gridMinY;
+ int _gridMaxX, _gridMaxY;
+ bool isPointBlocked(int gridX, int gridY);
+ bool isPointBlocked(Common::Point gridPos);
+ void initSceneGrid(int gridMinX, int gridMinY, int gridMaxX, int gridMaxY);
+ bool testWalk(int animationIndex, int someStatus, int gridX1, int gridY1, int gridX2, int gridY2);
+
+ // Gnap
+ void doCallback(int callback);
+
+ // Scenes
+ int _toyUfoNextSequenceId, _toyUfoSequenceId;
+ int _toyUfoId;
+ int _toyUfoActionStatus;
+ int _toyUfoX;
+ int _toyUfoY;
+
+ void initGlobalSceneVars();
+ void playSequences(int fullScreenSpriteId, int sequenceId1, int sequenceId2, int sequenceId3);
+
+ // Shared by scenes 17 & 18
+ int _s18GarbageCanPos;
+
+ // Scene 4x
+ void toyUfoSetStatus(int flagNum);
+ int toyUfoGetSequenceId();
+ bool toyUfoCheckTimer();
+ void toyUfoFlyTo(int destX, int destY, int minX, int maxX, int minY, int maxY, int animationIndex);
+
+ void playMidi(const char *name);
+ void stopMidi();
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_GNAP_H
diff --git a/engines/gnap/grid.cpp b/engines/gnap/grid.cpp
new file mode 100644
index 0000000000..aa6da71395
--- /dev/null
+++ b/engines/gnap/grid.cpp
@@ -0,0 +1,995 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "gnap/gnap.h"
+#include "gnap/datarchive.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+
+namespace Gnap {
+
+void GnapEngine::initSceneGrid(int gridMinX, int gridMinY, int gridMaxX, int gridMaxY) {
+ _gridMinX = gridMinX;
+ _gridMinY = gridMinY;
+ _gridMaxX = gridMaxX;
+ _gridMaxY = gridMaxY;
+ _gnap->_gridX = 410 - gridMinX;
+ _gnap->_gridY = 450 - gridMinY;
+ _plat->_gridX = 396 - gridMinX;
+ _plat->_gridY = 347 - gridMinY;
+}
+
+bool GnapEngine::isPointBlocked(Common::Point gridPos) {
+ return isPointBlocked(gridPos.x, gridPos.y);
+}
+
+bool GnapEngine::isPointBlocked(int gridX, int gridY) {
+
+ if (gridX < 0 || gridX >= _gridMaxX || gridY < 0 || gridY >= _gridMaxY)
+ return true;
+
+ if ((_gnap->_pos == Common::Point(gridX, gridY)) || (_plat->_pos == Common::Point(gridX, gridY)))
+ return true;
+
+ Common::Point pos = Common::Point(_gridMinX + 75 * gridX, _gridMinY + 48 * gridY);
+
+ for (int i = 0; i < _hotspotsCount; ++i) {
+ if (_hotspots[i].isPointInside(pos) && !(_hotspots[i]._flags & SF_WALKABLE))
+ return true;
+ }
+
+ return false;
+}
+
+/******************************************************************************/
+
+int PlayerGnap::getWalkStopSequenceId(int deltaX, int deltaY) {
+ static const int gnapWalkStopSequenceIds[9] = {
+ 0x7BC, 0x7BA, 0x7BA,
+ 0x7BC, 0x000, 0x7BA,
+ 0x7BB, 0x7B9, 0x7B9
+ };
+
+ int id = 3 * (deltaX + 1) + deltaY + 1;
+ assert (id >= 0 && id < 9 );
+ return gnapWalkStopSequenceIds[id];
+}
+
+Facing PlayerGnap::getWalkFacing(int deltaX, int deltaY) {
+ static const Facing gnapWalkFacings[9] = {
+ kDirUpLeft, kDirBottomLeft, kDirBottomLeft,
+ kDirUpLeft, kDirIdleLeft, kDirBottomLeft,
+ kDirUpRight, kDirBottomRight, kDirBottomRight
+ };
+
+ int id = 3 * (deltaX + 1) + deltaY + 1;
+ assert (id >= 0 && id < 9 );
+ return gnapWalkFacings[id];
+}
+
+bool PlayerGnap::findPath1(int gridX, int gridY, int index) {
+ _walkNodesCount = index;
+ _walkDirXIncr = 0;
+ _walkDirYIncr = 0;
+ _walkDeltaX = ABS(_walkDestX - gridX);
+ _walkDeltaY = ABS(_walkDestY - gridY);
+
+ if (_walkDeltaX)
+ _walkDirX = (_walkDestX - gridX) / _walkDeltaX;
+ else
+ _walkDirX = 0;
+
+ if (_walkDeltaY)
+ _walkDirY = (_walkDestY - gridY) / _walkDeltaY;
+ else
+ _walkDirY = 0;
+
+ while (_walkDirXIncr < _walkDeltaX && _walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirXIncr;
+ ++_walkDirYIncr;
+ } else if (_walkDeltaY - _walkDirYIncr > _walkDeltaX - _walkDirXIncr) {
+ if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else
+ return false;
+ } else {
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else
+ return false;
+ }
+ ++_walkNodesCount;
+ }
+
+ while (_walkDirXIncr < _walkDeltaX) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = _walkDestY;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDestY)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ while (_walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = _walkDestX;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDestX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ return true;
+}
+
+bool PlayerGnap::findPath2(int gridX, int gridY, int index) {
+ _walkNodesCount = index;
+ _walkDirXIncr = 0;
+ _walkDirYIncr = 0;
+ _walkDeltaX = ABS(_walkDestX - gridX);
+ _walkDeltaY = ABS(_walkDestY - gridY);
+
+ if (_walkDeltaX)
+ _walkDirX = (_walkDestX - gridX) / _walkDeltaX;
+ else
+ _walkDirX = 0;
+
+ if (_walkDeltaY)
+ _walkDirY = (_walkDestY - gridY) / _walkDeltaY;
+ else
+ _walkDirY = 0;
+
+ while (_walkDeltaY < _walkDeltaX - _walkDirXIncr) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, gridY)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ while (_walkDeltaX < _walkDeltaY - _walkDirYIncr) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(gridX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ while (_walkDirXIncr < _walkDeltaX && _walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirXIncr;
+ ++_walkDirYIncr;
+ } else if (_walkDeltaY - _walkDirYIncr > _walkDeltaX - _walkDirXIncr) {
+ if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else
+ return false;
+ } else {
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else
+ return false;
+ }
+ ++_walkNodesCount;
+ }
+
+ while (_walkDirXIncr < _walkDeltaX) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = _walkDestY;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDestY)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ while (_walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = _walkDestX;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDestX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ return true;
+}
+
+bool PlayerGnap::findPath3(int gridX, int gridY) {
+ int gridIncr = 1;
+ bool done = false;
+
+ while (!done && gridIncr < _vm->_gridMaxX) {
+ if (!_vm->isPointBlocked(gridX + gridIncr, gridY) && findPath1(gridX + gridIncr, gridY, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX + i;
+ _walkNodes[i]._gridY1 = gridY;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = 0;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX - gridIncr, gridY) && findPath1(gridX - gridIncr, gridY, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX - i;
+ _walkNodes[i]._gridY1 = gridY;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = 0;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX, gridY + gridIncr) && findPath1(gridX, gridY + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX;
+ _walkNodes[i]._gridY1 = gridY + i;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX, gridY - gridIncr) && findPath1(gridX, gridY - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX;
+ _walkNodes[i]._gridY1 = gridY - i;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX + gridIncr, gridY + gridIncr) && findPath1(gridX + gridIncr, gridY + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX + i;
+ _walkNodes[i]._gridY1 = gridY + i;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX - gridIncr, gridY + gridIncr) && findPath1(gridX - gridIncr, gridY + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX - i;
+ _walkNodes[i]._gridY1 = gridY + i;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX + gridIncr, gridY - gridIncr) && findPath1(gridX + gridIncr, gridY - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX + i;
+ _walkNodes[i]._gridY1 = gridY - i;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX - gridIncr, gridY - gridIncr) && findPath1(gridX - gridIncr, gridY - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX - i;
+ _walkNodes[i]._gridY1 = gridY - i;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX + gridIncr, gridY) && findPath2(gridX + gridIncr, gridY, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX + i;
+ _walkNodes[i]._gridY1 = gridY;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = 0;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX - gridIncr, gridY) && findPath2(gridX - gridIncr, gridY, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX - i;
+ _walkNodes[i]._gridY1 = gridY;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = 0;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX, gridY + gridIncr) && findPath2(gridX, gridY + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX;
+ _walkNodes[i]._gridY1 = gridY + i;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX, gridY - gridIncr) && findPath2(gridX, gridY - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX;
+ _walkNodes[i]._gridY1 = gridY - i;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX + gridIncr, gridY + gridIncr) && findPath2(gridX + gridIncr, gridY + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX + i;
+ _walkNodes[i]._gridY1 = gridY + i;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX - gridIncr, gridY + gridIncr) && findPath2(gridX - gridIncr, gridY + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX - i;
+ _walkNodes[i]._gridY1 = gridY + i;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX + gridIncr, gridY - gridIncr) && findPath2(gridX + gridIncr, gridY - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX + i;
+ _walkNodes[i]._gridY1 = gridY - i;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX - gridIncr, gridY - gridIncr) && findPath2(gridX - gridIncr, gridY - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX - i;
+ _walkNodes[i]._gridY1 = gridY - i;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ ++gridIncr;
+ }
+
+ return done;
+}
+
+bool PlayerGnap::findPath4(int gridX, int gridY) {
+ bool result = false;
+
+ _walkNodesCount = 0;
+ _walkDirXIncr = 0;
+ _walkDirYIncr = 0;
+ _walkDeltaX = ABS(_walkDestX - gridX);
+ _walkDeltaY = ABS(_walkDestY - gridY);
+
+ if (_walkDeltaX)
+ _walkDirX = (_walkDestX - gridX) / _walkDeltaX;
+ else
+ _walkDirX = 0;
+
+ if (_walkDeltaY)
+ _walkDirY = (_walkDestY - gridY) / _walkDeltaY;
+ else
+ _walkDirY = 0;
+
+ while (_walkDirXIncr < _walkDeltaX && _walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirXIncr;
+ ++_walkDirYIncr;
+ } else if (_walkDeltaY - _walkDirYIncr > _walkDeltaX - _walkDirXIncr) {
+ if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else {
+ _walkDeltaX = _walkDirXIncr;
+ _walkDeltaY = _walkDirYIncr;
+ --_walkNodesCount;
+ }
+ } else {
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else {
+ _walkDeltaX = _walkDirXIncr;
+ _walkDeltaY = _walkDirYIncr;
+ --_walkNodesCount;
+ }
+ }
+ ++_walkNodesCount;
+ }
+
+ while (_walkDirXIncr < _walkDeltaX) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = _walkDestY;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDestY)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ ++_walkNodesCount;
+ } else {
+ _walkDeltaX = _walkDirXIncr;
+ }
+ }
+
+ while (_walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = _walkDestX;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDestX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ ++_walkNodesCount;
+ } else {
+ _walkDeltaY = _walkDirYIncr;
+ }
+ }
+
+ if (gridX + _walkDirX * _walkDirXIncr != _walkDestX || gridY + _walkDirY * _walkDirYIncr != _walkDestY) {
+ _walkDestX = gridX + _walkDirX * _walkDirXIncr;
+ _walkDestY = gridY + _walkDirY * _walkDirYIncr;
+ result = false;
+ } else {
+ result = true;
+ }
+
+ return result;
+}
+
+/******************************************************************************/
+
+bool PlayerPlat::findPath1(int gridX, int gridY, int index) {
+ _walkNodesCount = index;
+ _walkDirXIncr = 0;
+ _walkDirYIncr = 0;
+ _walkDeltaX = ABS(_walkDestX - gridX);
+ _walkDeltaY = ABS(_walkDestY - gridY);
+
+ if (_walkDeltaX)
+ _walkDirX = (_walkDestX - gridX) / _walkDeltaX;
+ else
+ _walkDirX = 0;
+
+ if (_walkDeltaY)
+ _walkDirY = (_walkDestY - gridY) / _walkDeltaY;
+ else
+ _walkDirY = 0;
+
+ while (_walkDirXIncr < _walkDeltaX && _walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirXIncr;
+ ++_walkDirYIncr;
+ } else if (_walkDeltaY - _walkDirYIncr > _walkDeltaX - _walkDirXIncr) {
+ if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else
+ return false;
+ } else {
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else
+ return false;
+ }
+ ++_walkNodesCount;
+ }
+
+ while (_walkDirXIncr < _walkDeltaX) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = _walkDestY;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDestY)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ while (_walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = _walkDestX;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDestX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ return true;
+}
+
+bool PlayerPlat::findPath2(int gridX, int gridY, int index) {
+ _walkNodesCount = index;
+ _walkDirXIncr = 0;
+ _walkDirYIncr = 0;
+ _walkDeltaX = ABS(_walkDestX - gridX);
+ _walkDeltaY = ABS(_walkDestY - gridY);
+
+ if (_walkDeltaX)
+ _walkDirX = (_walkDestX - gridX) / _walkDeltaX;
+ else
+ _walkDirX = 0;
+
+ if (_walkDeltaY)
+ _walkDirY = (_walkDestY - gridY) / _walkDeltaY;
+ else
+ _walkDirY = 0;
+
+ while (_walkDeltaY < _walkDeltaX - _walkDirXIncr) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, gridY)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ while (_walkDeltaX < _walkDeltaY - _walkDirYIncr) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(gridX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ while (_walkDirXIncr < _walkDeltaX && _walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirXIncr;
+ ++_walkDirYIncr;
+ } else if (_walkDeltaY - _walkDirYIncr > _walkDeltaX - _walkDirXIncr) {
+ if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else
+ return false;
+ } else {
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else
+ return false;
+ }
+ ++_walkNodesCount;
+ }
+
+ while (_walkDirXIncr < _walkDeltaX) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = _walkDestY;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDestY)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ while (_walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = _walkDestX;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDestX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ return true;
+}
+
+bool PlayerPlat::findPath3(int gridX, int gridY) {
+ int gridIncr = 1;
+ bool done = false;
+
+ while (!done && gridIncr < _vm->_gridMaxX) {
+ if (!_vm->isPointBlocked(_pos.x + gridIncr, _pos.y) && findPath1(_pos.x + gridIncr, _pos.y, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x + i;
+ _walkNodes[i]._gridY1 = _pos.y;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = 0;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x - gridIncr, _pos.y) && findPath1(_pos.x - gridIncr, _pos.y, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x - i;
+ _walkNodes[i]._gridY1 = _pos.y;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = 0;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x, _pos.y + gridIncr) && findPath1(_pos.x, _pos.y + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x;
+ _walkNodes[i]._gridY1 = _pos.y + i;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x, _pos.y - gridIncr) && findPath1(_pos.x, _pos.y - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x;
+ _walkNodes[i]._gridY1 = _pos.y - i;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x + gridIncr, _pos.y + gridIncr) && findPath1(_pos.x + gridIncr, _pos.y + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x + i;
+ _walkNodes[i]._gridY1 = _pos.y + i;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x - gridIncr, _pos.y + gridIncr) && findPath1(_pos.x - gridIncr, _pos.y + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x - i;
+ _walkNodes[i]._gridY1 = _pos.y + i;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x + gridIncr, _pos.y - gridIncr) && findPath1(_pos.x + gridIncr, _pos.y - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x + i;
+ _walkNodes[i]._gridY1 = _pos.y - i;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x - gridIncr, _pos.y - gridIncr) && findPath1(_pos.x - gridIncr, _pos.y - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x - i;
+ _walkNodes[i]._gridY1 = _pos.y - i;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x + gridIncr, _pos.y) && findPath2(_pos.x + gridIncr, _pos.y, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x + i;
+ _walkNodes[i]._gridY1 = _pos.y;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = 0;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x - gridIncr, _pos.y) && findPath2(_pos.x - gridIncr, _pos.y, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x - i;
+ _walkNodes[i]._gridY1 = _pos.y;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = 0;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x, _pos.y + gridIncr) && findPath2(_pos.x, _pos.y + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x;
+ _walkNodes[i]._gridY1 = _pos.y + i;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x, _pos.y - gridIncr) && findPath2(_pos.x, _pos.y - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x;
+ _walkNodes[i]._gridY1 = _pos.y - i;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x + gridIncr, _pos.y + gridIncr) && findPath2(_pos.x + gridIncr, _pos.y + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x + i;
+ _walkNodes[i]._gridY1 = _pos.y + i;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x - gridIncr, _pos.y + gridIncr) && findPath2(_pos.x - gridIncr, _pos.y + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x - i;
+ _walkNodes[i]._gridY1 = _pos.y + i;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x + gridIncr, _pos.y - gridIncr) && findPath2(_pos.x + gridIncr, _pos.y - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x + i;
+ _walkNodes[i]._gridY1 = _pos.y - i;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x - gridIncr, _pos.y - gridIncr) && findPath2(_pos.x - gridIncr, _pos.y - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x - i;
+ _walkNodes[i]._gridY1 = _pos.y - i;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ ++gridIncr;
+ }
+
+ return done;
+}
+
+bool PlayerPlat::findPath4(int gridX, int gridY) {
+ bool result = false;
+
+ _walkNodesCount = 0;
+ _walkDirXIncr = 0;
+ _walkDirYIncr = 0;
+ _walkDeltaX = ABS(_walkDestX - gridX);
+ _walkDeltaY = ABS(_walkDestY - gridY);
+
+ if (_walkDeltaX)
+ _walkDirX = (_walkDestX - gridX) / _walkDeltaX;
+ else
+ _walkDirX = 0;
+
+ if (_walkDeltaY)
+ _walkDirY = (_walkDestY - gridY) / _walkDeltaY;
+ else
+ _walkDirY = 0;
+
+ while (_walkDirXIncr < _walkDeltaX && _walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirXIncr;
+ ++_walkDirYIncr;
+ } else if (_walkDeltaY - _walkDirYIncr > _walkDeltaX - _walkDirXIncr) {
+ if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else {
+ _walkDeltaX = _walkDirXIncr;
+ _walkDeltaY = _walkDirYIncr;
+ --_walkNodesCount;
+ }
+ } else {
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else {
+ _walkDeltaX = _walkDirXIncr;
+ _walkDeltaY = _walkDirYIncr;
+ --_walkNodesCount;
+ }
+ }
+ ++_walkNodesCount;
+ }
+
+ while (_walkDirXIncr < _walkDeltaX) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = _walkDestY;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDestY)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ ++_walkNodesCount;
+ } else {
+ _walkDeltaX = _walkDirXIncr;
+ }
+ }
+
+ while (_walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = _walkDestX;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDestX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ ++_walkNodesCount;
+ } else {
+ _walkDeltaY = _walkDirYIncr;
+ }
+ }
+
+ if (gridX + _walkDirX * _walkDirXIncr != _walkDestX || gridY + _walkDirY * _walkDirYIncr != _walkDestY) {
+ _walkDestX = gridX + _walkDirX * _walkDirXIncr;
+ _walkDestY = gridY + _walkDirY * _walkDirYIncr;
+ result = false;
+ } else {
+ result = true;
+ }
+
+ return result;
+}
+
+void PlayerPlat::makeRoom() {
+ int rndGridX, rndGridY;
+ do {
+ rndGridY = _vm->getRandom(_vm->_gridMaxY);
+ rndGridX = _vm->getRandom(_vm->_gridMaxX);
+ } while (ABS(rndGridX - _pos.x) > 4 || ABS(rndGridY - _pos.y) > 3 ||
+ _vm->isPointBlocked(rndGridX, rndGridY));
+ walkTo(Common::Point(rndGridX, rndGridY), -1, -1, 1);
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/menu.cpp b/engines/gnap/menu.cpp
new file mode 100644
index 0000000000..2bfe7300df
--- /dev/null
+++ b/engines/gnap/menu.cpp
@@ -0,0 +1,888 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/savefile.h"
+#include "common/translation.h"
+
+#include "gui/saveload.h"
+#include "graphics/thumbnail.h"
+
+#include "gnap/gnap.h"
+#include "gnap/datarchive.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+
+namespace Gnap {
+
+void GnapEngine::createMenuSprite() {
+ _menuBackgroundSurface = _gameSys->createSurface(0x10002);
+}
+
+void GnapEngine::freeMenuSprite() {
+ _gameSys->removeSpriteDrawItem(_menuBackgroundSurface, 260);
+ delayTicksCursor(5);
+ deleteSurface(&_menuBackgroundSurface);
+}
+
+void GnapEngine::initMenuHotspots1() {
+ int curId = 0;
+
+ for (int i = 0; i < 3; ++i) {
+ int top = 74 * i + 69;
+ for (int j = 0; j < 3; ++j) {
+ int left = 87 * j + 262;
+ _hotspots[curId]._rect = Common::Rect(left, top, left + 79, top + 66);
+ _hotspots[curId]._flags = SF_NONE;
+ ++curId;
+ }
+ }
+
+ _hotspots[curId]._rect = Common::Rect(330, 350, 430, 460);
+ _hotspots[curId]._flags = SF_GRAB_CURSOR;
+
+ ++curId;
+ _hotspots[curId]._rect = Common::Rect(180, 15, 620, 580);
+ _hotspots[curId]._flags = SF_NONE;
+
+ ++curId;
+ _hotspots[curId]._rect = Common::Rect(0, 0, 799, 599);
+ _hotspots[curId]._flags = SF_NONE;
+
+ _hotspotsCount = curId + 1;
+}
+
+void GnapEngine::initMenuHotspots2() {
+ int curId = 0;
+
+ for (int i = 0; i < 4; ++i) {
+ int top = 48 * i + 85;
+ _hotspots[curId]._rect = Common::Rect(312, top, 465, top + 37);
+ _hotspots[curId]._flags = SF_GRAB_CURSOR;
+ ++curId;
+ }
+
+ _hotspots[curId]._rect = Common::Rect(500, 72, 527, 99);
+ _hotspots[curId]._flags = SF_DISABLED;
+
+ ++curId;
+ _hotspots[curId]._rect = Common::Rect(330, 350, 430, 460);
+ _hotspots[curId]._flags = SF_GRAB_CURSOR;
+
+ ++curId;
+ _hotspots[curId]._rect = Common::Rect(180, 15, 620, 580);
+ _hotspots[curId]._flags = SF_NONE;
+
+ ++curId;
+ _hotspots[curId]._rect = Common::Rect(0, 0, 799, 599);
+ _hotspots[curId]._flags = SF_NONE;
+
+ _hotspotsCount = curId + 1;
+}
+
+void GnapEngine::initMenuQuitQueryHotspots() {
+ _hotspots[0]._rect = Common::Rect(311, 197, 377, 237);
+ _hotspots[0]._flags = SF_GRAB_CURSOR;
+
+ _hotspots[1]._rect = Common::Rect(403, 197, 469, 237);
+ _hotspots[1]._flags = SF_GRAB_CURSOR;
+
+ _hotspots[2]._rect = Common::Rect(330, 350, 430, 460);
+ _hotspots[2]._flags = SF_GRAB_CURSOR;
+
+ _hotspots[3]._rect = Common::Rect(180, 15, 620, 580);
+ _hotspots[3]._flags = SF_NONE;
+
+ _hotspots[4]._rect = Common::Rect(0, 0, 799, 599);
+ _hotspots[4]._flags = SF_NONE;
+
+ _hotspotsCount = 5;
+}
+
+void GnapEngine::initSaveLoadHotspots() {
+ int curId = 0;
+
+ for (int i = 0; i < 7; ++i ) {
+ int top = 31 * i + 74;
+ _hotspots[curId]._rect = Common::Rect(288, top, 379, top + 22);
+ _hotspots[curId]._flags = SF_GRAB_CURSOR;
+ ++curId;
+ }
+
+ if (_menuStatus == 2) {
+ _hotspots[curId]._rect = Common::Rect(416, 160, 499, 188);
+ _hotspots[curId]._flags = SF_GRAB_CURSOR;
+ ++curId;
+ }
+
+ _hotspots[curId]._rect = Common::Rect(416, 213, 499, 241);
+ _hotspots[curId]._flags = SF_GRAB_CURSOR;
+
+ ++curId;
+ _hotspots[curId]._rect = Common::Rect(330, 350, 430, 460);
+ _hotspots[curId]._flags = SF_GRAB_CURSOR;
+
+ ++curId;
+ _hotspots[curId]._rect = Common::Rect(180, 15, 620, 580);
+ _hotspots[curId]._flags = SF_NONE;
+
+ ++curId;
+ _hotspots[curId]._rect = Common::Rect(0, 0, 799, 599);
+ _hotspots[curId]._flags = SF_NONE;
+
+ _hotspotsCount = curId + 1;
+}
+
+void GnapEngine::drawInventoryFrames() {
+ for (int i = 0; i < 9; ++i)
+ _gameSys->drawSpriteToSurface(_menuBackgroundSurface, _hotspots[i]._rect.left - 93, _hotspots[i]._rect.top, 0x10001);
+}
+
+void GnapEngine::insertInventorySprites() {
+ for (int i = 0; i < 9; ++i) {
+ _menuInventoryIndices[i] = -1;
+ _gameSys->removeSpriteDrawItem(_menuInventorySprites[_sceneClickedHotspot], 261);
+ _menuInventorySprites[i] = 0;
+ }
+
+ _menuSpritesIndex = 0;
+
+ for (int index = 0; index < 30 && _menuSpritesIndex < 9; ++index) {
+ if (invHas(index)) {
+ _gameSys->drawSpriteToSurface(_menuBackgroundSurface,
+ _hotspots[_menuSpritesIndex]._rect.left - 93, _hotspots[_menuSpritesIndex]._rect.top, 0x10000);
+ _menuInventorySprites[_menuSpritesIndex] = _gameSys->createSurface(getInventoryItemSpriteNum(index) | 0x10000);
+ if (index != _grabCursorSpriteIndex) {
+ _menuInventoryIndices[_menuSpritesIndex] = index;
+ _gameSys->insertSpriteDrawItem(_menuInventorySprites[_menuSpritesIndex],
+ _hotspots[_menuSpritesIndex]._rect.left + ((79 - _menuInventorySprites[_menuSpritesIndex]->w) / 2),
+ _hotspots[_menuSpritesIndex]._rect.top + ((66 - _menuInventorySprites[_menuSpritesIndex]->h) / 2),
+ 261);
+ }
+ _hotspots[_menuSpritesIndex]._flags = SF_GRAB_CURSOR;
+ ++_menuSpritesIndex;
+ }
+ }
+}
+
+void GnapEngine::removeInventorySprites() {
+ for (int i = 0; i < _menuSpritesIndex; ++i)
+ if (_menuInventorySprites[i])
+ _gameSys->removeSpriteDrawItem(_menuInventorySprites[i], 261);
+ delayTicksCursor(5);
+ for (int j = 0; j < _menuSpritesIndex; ++j) {
+ if (_menuInventorySprites[j]) {
+ deleteSurface(&_menuInventorySprites[j]);
+ _menuInventorySprites[j] = 0;
+ _menuInventoryIndices[j] = -1;
+ }
+ }
+ _menuSpritesIndex = 0;
+}
+
+void GnapEngine::runMenu() {
+ _spriteHandle = nullptr;
+ _cursorSprite = nullptr;
+ _menuSprite1 = nullptr;
+ _menuSprite2 = nullptr;
+ _menuSaveLoadSprite = nullptr;
+ _menuQuitQuerySprite = nullptr;
+
+ _menuStatus = 0;
+ _menuDone = false;
+
+ delete _tempThumbnail;
+ _tempThumbnail = new Common::MemoryWriteStreamDynamic;
+ Graphics::saveThumbnail(*_tempThumbnail);
+
+ createMenuSprite();
+ insertDeviceIconActive();
+
+ for (int i = 0; i < 7; ++i) {
+ _savegameFilenames[i][0] = 0;
+ _savegameSprites[i] = nullptr;
+ }
+
+ if (_menuStatus == 0) {
+ invAdd(kItemMagazine);
+ setGrabCursorSprite(-1);
+ hideCursor();
+ initMenuHotspots1();
+ drawInventoryFrames();
+ insertInventorySprites();
+ _gameSys->insertSpriteDrawItem(_menuBackgroundSurface, 93, 0, 260);
+ showCursor();
+ // SetCursorPos(400, 300);
+ setVerbCursor(GRAB_CURSOR);
+ // pollMessages();
+ }
+
+ _timers[2] = 10;
+
+ while (!isKeyStatus1(Common::KEYCODE_BACKSPACE) && !isKeyStatus1(Common::KEYCODE_ESCAPE) && !_sceneDone && !_menuDone) {
+ updateCursorByHotspot();
+
+ switch (_menuStatus) {
+ case 0:
+ updateMenuStatusInventory();
+ break;
+ case 1:
+ updateMenuStatusMainMenu();
+ break;
+ case 2:
+ updateMenuStatusSaveGame();
+ break;
+ case 3:
+ updateMenuStatusLoadGame();
+ break;
+ case 4:
+ updateMenuStatusQueryQuit();
+ break;
+ }
+
+ gameUpdateTick();
+ }
+
+ removeInventorySprites();
+ if (_spriteHandle)
+ _gameSys->removeSpriteDrawItem(_spriteHandle, 261);
+ if (_menuSprite1)
+ _gameSys->removeSpriteDrawItem(_menuSprite1, 262);
+ if (_menuSprite2)
+ _gameSys->removeSpriteDrawItem(_menuSprite2, 262);
+ for (int i = 0; i < 7; ++i)
+ if (_savegameSprites[i])
+ _gameSys->removeSpriteDrawItem(_savegameSprites[i], 263);
+ if (_cursorSprite)
+ _gameSys->removeSpriteDrawItem(_cursorSprite, 264);
+ if (_menuSaveLoadSprite)
+ _gameSys->removeSpriteDrawItem(_menuSaveLoadSprite, 262);
+ if (_menuQuitQuerySprite)
+ _gameSys->removeSpriteDrawItem(_menuQuitQuerySprite, 262);
+ if (_menuBackgroundSurface)
+ _gameSys->removeSpriteDrawItem(_menuBackgroundSurface, 260);
+
+ delayTicksCursor(5);
+
+ deleteSurface(&_spriteHandle);
+ deleteSurface(&_menuSprite1);
+ deleteSurface(&_menuSprite2);
+ for (int i = 0; i < 7; ++i)
+ deleteSurface(&_savegameSprites[i]);
+ deleteSurface(&_cursorSprite);
+ deleteSurface(&_menuSaveLoadSprite);
+ deleteSurface(&_menuQuitQuerySprite);
+
+ _sceneClickedHotspot = -1;
+
+ _timers[2] = getRandom(20) + 30;
+ _timers[3] = getRandom(200) + 50;
+ _timers[0] = getRandom(75) + 75;
+ _timers[1] = getRandom(20) + 30;
+
+ clearAllKeyStatus1();
+
+ _mouseClickState._left = false;
+
+ removeDeviceIconActive();
+
+ freeMenuSprite();//??? CHECKME
+}
+
+void GnapEngine::updateMenuStatusInventory() {
+ static const struct {
+ int item1, item2, resultItem;
+ } kCombineItems[] = {
+ {kItemGrass, kItemMud, kItemDisguise},
+ {kItemDice, kItemQuarterWithHole, kItemDiceQuarterHole},
+ {kItemPill, kItemBucketWithBeer, kItemBucketWithPill}
+ };
+
+ updateGrabCursorSprite(0, 0);
+ _hotspots[0]._rect = Common::Rect(262, 69, 341, 135);
+ _sceneClickedHotspot = -1;
+ if (_timers[2] == 0)
+ _sceneClickedHotspot = getClickedHotspotId();
+ if (_sceneClickedHotspot == -1 || _sceneClickedHotspot >= _menuSpritesIndex) {
+ if (_sceneClickedHotspot == _hotspotsCount - 3) {
+ if (_grabCursorSpriteIndex == -1) {
+ _timers[2] = 10;
+ playSound(0x108F4, false);
+ _menuStatus = 1;
+ Common::Rect dirtyRect(_hotspots[0]._rect.left, _hotspots[0]._rect.top, _hotspots[2]._rect.right, _hotspots[_hotspotsCount - 4]._rect.bottom);
+ drawInventoryFrames();
+ initMenuHotspots2();
+ removeInventorySprites();
+ if (!_menuSprite1)
+ _menuSprite1 = _gameSys->createSurface(0x104F8);
+ _gameSys->insertSpriteDrawItem(_menuSprite1, 288, 79, 262);
+ _gameSys->insertDirtyRect(dirtyRect);
+ } else {
+ playSound(0x108F5, false);
+ }
+ } else if (_sceneClickedHotspot == _hotspotsCount - 1) {
+ _timers[2] = 10;
+ playSound(0x108F5, false);
+ _menuDone = true;
+ }
+ } else if (_sceneClickedHotspot != -1 && _menuInventoryIndices[_sceneClickedHotspot] != -1 && _grabCursorSpriteIndex == -1) {
+ _gameSys->removeSpriteDrawItem(_menuInventorySprites[_sceneClickedHotspot], 261);
+ setGrabCursorSprite(_menuInventoryIndices[_sceneClickedHotspot]);
+ _menuInventoryIndices[_sceneClickedHotspot] = -1;
+ } else if (_sceneClickedHotspot != -1 && _menuInventoryIndices[_sceneClickedHotspot] == -1 && _grabCursorSpriteIndex != -1) {
+ _menuInventoryIndices[_sceneClickedHotspot] = _grabCursorSpriteIndex;
+ _gameSys->insertSpriteDrawItem(_menuInventorySprites[_sceneClickedHotspot],
+ _hotspots[_sceneClickedHotspot]._rect.left + ((79 - _menuInventorySprites[_sceneClickedHotspot]->w) / 2),
+ _hotspots[_sceneClickedHotspot]._rect.top + (66 - _menuInventorySprites[_sceneClickedHotspot]->h) / 2,
+ 261);
+ setGrabCursorSprite(-1);
+ } else if (_sceneClickedHotspot != -1 && _menuInventoryIndices[_sceneClickedHotspot] != -1 && _grabCursorSpriteIndex != -1) {
+ int combineIndex = -1;
+ for (int i = 0; i < ARRAYSIZE(kCombineItems); ++i) {
+ if ((_grabCursorSpriteIndex == kCombineItems[i].item1 && _menuInventoryIndices[_sceneClickedHotspot] == kCombineItems[i].item2) ||
+ (_grabCursorSpriteIndex == kCombineItems[i].item2 && _menuInventoryIndices[_sceneClickedHotspot] == kCombineItems[i].item1)) {
+ combineIndex = i;
+ break;
+ }
+ }
+ if (combineIndex >= 0) {
+ invRemove(kCombineItems[combineIndex].item1);
+ invRemove(kCombineItems[combineIndex].item2);
+ invAdd(kCombineItems[combineIndex].resultItem);
+ playSound(0x108AE, false);
+ deleteSurface(&_spriteHandle); // CHECKME
+ _spriteHandle = _gameSys->createSurface(0x10001);
+ _gameSys->insertSpriteDrawItem(_spriteHandle, _hotspots[_menuSpritesIndex - 1]._rect.left, _hotspots[_menuSpritesIndex - 1]._rect.top, 261);
+ setGrabCursorSprite(kCombineItems[combineIndex].resultItem);
+ removeInventorySprites();
+ insertInventorySprites();
+ delayTicksCursor(5);
+ } else {
+ playSound(0x108F5, false);
+ }
+ }
+}
+
+void GnapEngine::updateMenuStatusMainMenu() {
+ _hotspots[0]._rect = Common::Rect(312, 85, 465, 122);
+ _sceneClickedHotspot = -1;
+ if (!_timers[2])
+ _sceneClickedHotspot = getClickedHotspotId();
+
+ if (_sceneClickedHotspot != 1 && _sceneClickedHotspot != 0) {
+ if (_sceneClickedHotspot != 2 && _hotspotsCount - 1 != _sceneClickedHotspot) {
+ if (_sceneClickedHotspot == 3) {
+ // Quit
+ _timers[2] = 10;
+ playSound(0x108F4, false);
+ _gameSys->removeSpriteDrawItem(_menuSprite1, 262);
+ initMenuQuitQueryHotspots();
+ _menuStatus = 4;
+ if (!_menuQuitQuerySprite)
+ _menuQuitQuerySprite = _gameSys->createSurface(0x104FC);
+ _gameSys->insertSpriteDrawItem(_menuQuitQuerySprite, 254, 93, 262);
+ } else if (_sceneClickedHotspot == 4) {
+ // Pause ?
+ playSound(0x108F4, false);
+ Common::Rect dirtyRect(0, 0, 799, 599);
+ hideCursor();
+ _largeSprite = _gameSys->allocSurface(800, 600);
+
+ for (int i = 0; i < 3; ++i) {
+ _timers[2] = 10;
+
+ if (i == 0) {
+ _gameSys->drawSpriteToSurface(_largeSprite, 0, 0, 0x1078D);
+ _gameSys->insertSpriteDrawItem(_largeSprite, 0, 0, 300);
+ playMidi("pause.mid");
+ } else if (i == 1) {
+ _gameSys->drawSpriteToSurface(_largeSprite, 0, 0, 0x1078E);
+ _gameSys->insertDirtyRect(dirtyRect);
+ } else if (i == 2) {
+ _gameSys->drawSpriteToSurface(_largeSprite, 0, 0, 0x1078F);
+ _gameSys->insertDirtyRect(dirtyRect);
+ }
+
+ while (!_mouseClickState._left && !isKeyStatus1(Common::KEYCODE_ESCAPE) && !isKeyStatus1(Common::KEYCODE_RETURN)
+ && !isKeyStatus1(Common::KEYCODE_SPACE) && !_timers[2] && !_gameDone)
+ gameUpdateTick();
+
+ playSound(0x108F5, false);
+ _mouseClickState._left = false;
+ clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ clearKeyStatus1(Common::KEYCODE_RETURN);
+ clearKeyStatus1(Common::KEYCODE_SPACE);
+ }
+
+ _gameSys->removeSpriteDrawItem(_largeSprite, 300);
+ delayTicksCursor(5);
+ deleteSurface(&_largeSprite);
+ showCursor();
+ } else if (_hotspotsCount - 3 == _sceneClickedHotspot) {
+ // Button - Return to the inventory
+ _timers[2] = 10;
+ playSound(0x108F4, false);
+ initMenuHotspots1();
+ _menuStatus = 0;
+ if (_menuSprite1)
+ _gameSys->removeSpriteDrawItem(_menuSprite1, 262);
+ insertInventorySprites();
+ Common::Rect dirtyRect(_hotspots[0]._rect.left, _hotspots[0]._rect.top, _hotspots[2]._rect.right, _hotspots[_hotspotsCount - 4]._rect.bottom);
+ _gameSys->insertDirtyRect(dirtyRect);
+ }
+ } else {
+ // Resume
+ playSound(0x108F5, false);
+ _menuDone = true;
+ }
+ } else {
+ // Save / Load
+#if 1
+ _timers[2] = 10;
+ playSound(0x108F4, false);
+
+ if (_sceneClickedHotspot == 1) {
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
+ int16 savegameId = dialog->runModalWithCurrentTarget();
+ Common::String savegameDescription = dialog->getResultString();
+ delete dialog;
+
+ if (savegameId != -1) {
+ saveGameState(savegameId, savegameDescription);
+ }
+ } else {
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
+ int16 savegameId = dialog->runModalWithCurrentTarget();
+ delete dialog;
+
+ if (savegameId != -1) {
+ loadGameState(savegameId);
+ _wasSavegameLoaded = true;
+ _menuDone = true;
+ _sceneDone = true;
+ playSound(0x108F4, false);
+ } else {
+ playSound(0x108F5, false);
+ }
+ }
+ }
+#else
+ // NOTE:
+ // This is the code for the original behavior.
+ // It's currently not working prolery, but could be
+ // fixed to replace the ScummVM screens currently
+ // used.
+ _timers[2] = 10;
+ playSound(0x108F4, false);
+ _gameSys->removeSpriteDrawItem(_menuSprite1, 262);
+ if (_menuSaveLoadSprite)
+ deleteSurface(&_menuSaveLoadSprite);
+ if (_sceneClickedHotspot == 1) {
+ // Save
+ _menuStatus = 2;
+ initSaveLoadHotspots();
+ _menuSaveLoadSprite = _gameSys->createSurface(0x104FB);
+ } else {
+ // Load
+ _menuStatus = 3;
+ initSaveLoadHotspots();
+ _menuSaveLoadSprite = _gameSys->createSurface(0x104FA);
+ }
+ _gameSys->insertSpriteDrawItem(_menuSaveLoadSprite, 403, 72, 262);
+ if (!_menuSprite2)
+ _menuSprite2 = _gameSys->createSurface(0x104F9);
+ _gameSys->insertSpriteDrawItem(_menuSprite2, 277, 66, 262);
+ for (int i = 0; i < 7; ++i) {
+ Common::String savegameDescription;
+ if (!_savegameSprites[i])
+ _savegameSprites[i] = _gameSys->allocSurface(111, 40);
+ if (readSavegameDescription(i + 1, savegameDescription) == 0)
+ strncpy(_savegameFilenames[i], savegameDescription.c_str(), 40);
+ _gameSys->drawTextToSurface(_savegameSprites[i], 0, 0, 255, 0, 0, _savegameFilenames[i]);
+ _gameSys->insertSpriteDrawItem(_savegameSprites[i], 288, _hotspots[i].top, 263);
+ }
+ _savegameIndex = -1;
+ }
+#endif
+}
+
+Common::Error GnapEngine::saveGameState(int slot, const Common::String &desc) {
+ Common::OutSaveFile *out = g_system->getSavefileManager()->openForSaving(
+ generateSaveName(slot));
+ if (!out)
+ return Common::kCreatingFileFailed;
+
+ GnapSavegameHeader header;
+ header._saveName = desc;
+ writeSavegameHeader(out, header);
+
+ Common::Serializer s(nullptr, out);
+ synchronize(s);
+
+ out->finalize();
+ delete out;
+
+ return Common::kNoError;
+}
+
+void GnapEngine::synchronize(Common::Serializer &s) {
+ if (s.isSaving()) {
+ s.syncAsSint32LE(_currentSceneNum);
+ s.syncAsSint32LE(_prevSceneNum);
+ s.syncAsSint32LE(_cursorValue);
+ s.syncAsUint32LE(_inventory);
+ s.syncAsUint32LE(_gameFlags);
+ } else {
+ s.syncAsSint32LE(_newSceneNum);
+ s.syncAsSint32LE(_currentSceneNum);
+ s.syncAsSint32LE(_newCursorValue);
+ s.syncAsUint32LE(_inventory);
+ s.syncAsUint32LE(_gameFlags);
+
+ if (isFlag(kGFUnk24))
+ _timers[9] = 600;
+ }
+}
+
+const char *const SAVEGAME_STR = "GNAP";
+#define SAVEGAME_STR_SIZE 4
+void GnapEngine::writeSavegameHeader(Common::OutSaveFile *out, GnapSavegameHeader &header) {
+ // Write out a savegame header
+ out->write(SAVEGAME_STR, SAVEGAME_STR_SIZE + 1);
+
+ out->writeByte(GNAP_SAVEGAME_VERSION);
+
+ // Write savegame name
+ out->writeString(header._saveName);
+ out->writeByte('\0');
+
+ // This implies the menu is used
+ // If we want to save/load at any time, then a check should be added
+ out->write(_tempThumbnail->getData(), _tempThumbnail->size());
+
+ // Write out the save date/time
+ TimeDate td;
+ g_system->getTimeAndDate(td);
+ out->writeSint16LE(td.tm_year + 1900);
+ out->writeSint16LE(td.tm_mon + 1);
+ out->writeSint16LE(td.tm_mday);
+ out->writeSint16LE(td.tm_hour);
+ out->writeSint16LE(td.tm_min);
+}
+
+bool GnapEngine::readSavegameHeader(Common::InSaveFile *in, GnapSavegameHeader &header) {
+ char saveIdentBuffer[SAVEGAME_STR_SIZE + 1];
+ header._thumbnail = nullptr;
+
+ // Validate the header Id
+ in->read(saveIdentBuffer, SAVEGAME_STR_SIZE + 1);
+ if (strncmp(saveIdentBuffer, SAVEGAME_STR, SAVEGAME_STR_SIZE))
+ return false;
+
+ header._version = in->readByte();
+ if (header._version > GNAP_SAVEGAME_VERSION)
+ return false;
+
+ // Read in the string
+ header._saveName.clear();
+ char ch;
+ while ((ch = (char)in->readByte()) != '\0')
+ header._saveName += ch;
+
+ // Get the thumbnail, saved in v2 or later
+ if (header._version == 1)
+ header._thumbnail = nullptr;
+ else {
+ header._thumbnail = Graphics::loadThumbnail(*in);
+ if (!header._thumbnail)
+ return false;
+ }
+
+ // Read in save date/time
+ header._year = in->readSint16LE();
+ header._month = in->readSint16LE();
+ header._day = in->readSint16LE();
+ header._hour = in->readSint16LE();
+ header._minute = in->readSint16LE();
+
+ return true;
+}
+
+Common::Error GnapEngine::loadGameState(int slot) {
+ Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(
+ generateSaveName(slot));
+ if (!saveFile)
+ return Common::kReadingFailed;
+
+ Common::Serializer s(saveFile, nullptr);
+
+ // Load the savegame header
+ GnapSavegameHeader header;
+ if (!readSavegameHeader(saveFile, header))
+ error("Invalid savegame");
+
+ if (header._thumbnail) {
+ header._thumbnail->free();
+ delete header._thumbnail;
+ }
+
+ synchronize(s);
+ delete saveFile;
+
+ _loadGameSlot = slot;
+ return Common::kNoError;
+}
+
+Common::String GnapEngine::generateSaveName(int slot) {
+ return Common::String::format("%s.%03d", _targetName.c_str(), slot);
+}
+
+void GnapEngine::updateMenuStatusSaveGame() {
+#if 0
+ // NOTE:
+ // This is the code for the original screen game.
+ // It could be eventually fixed and could replace
+ // the ScummVM screens currently used.
+
+ char v43[30];
+ int v46;
+ v43[0] = '\0';
+ _hotspots[0]._x1 = 288;
+ _hotspots[0]._y1 = 74;
+ _hotspots[0]._x2 = 379;
+ _hotspots[0]._y2 = 96;
+ _sceneClickedHotspot = -1;
+
+ if (!_timers[2])
+ _sceneClickedHotspot = getClickedHotspotId();
+
+ if (_hotspotsCount - 3 == _sceneClickedHotspot) {
+ // Button
+ _timers[2] = 10;
+ playSound(0x108F4, false);
+ _menuStatus = 1;
+ warning("writeSavegame(_savegameIndex + 1, (int)&_savegameFilenames[30 * _savegameIndex], 1);");
+ } else if (_hotspotsCount - 4 == _sceneClickedHotspot) {
+ // Cancel
+ _timers[2] = 10;
+ playSound(0x108F5, false);
+ _menuStatus = 1;
+ if (strcmp(v43, _savegameFilenames[_savegameIndex]) && _savegameIndex != -1) {
+ strcpy(_savegameFilenames[_savegameIndex], v43);
+ if (_savegameSprites[_savegameIndex] != nullptr) {
+ _gameSys->removeSpriteDrawItem(_savegameSprites[_savegameIndex], 263);
+ delayTicksCursor(5);
+ warning("memFreeHandle(_savegameSprites[_savegameIndex]);");
+ }
+ int v16 = _gameSys->getSpriteWidthById(0x104F9);
+ warning("_savegameSprites[_savegameIndex] = allocSprite(v16, 40, 128, 0);");
+ }
+ } else if (_hotspotsCount - 5 == _sceneClickedHotspot) {
+ // OK
+ _timers[2] = 10;
+ playSound(0x108F4, false);
+ if (_savegameIndex != -1)
+ warning("writeSavegame(_savegameIndex + 1, (int)&_savegameFilenames[30 * _savegameIndex], 1);");
+ _menuStatus = 1;
+ } else if (_hotspotsCount - 1 == _sceneClickedHotspot) {
+ // in background
+ _menuDone = true;
+ } else if (_sceneClickedHotspot != -1 && _hotspotsCount - 2 != _sceneClickedHotspot) {
+ // Savegame name
+ _timers[2] = 10;
+ playSound(0x108F4, false);
+ if (strcmp(v43, _savegameFilenames[_savegameIndex]) & (_savegameIndex != -1)) {
+ strcpy(_savegameFilenames[_savegameIndex], v43);
+ if (_savegameSprites[_savegameIndex] != nullptr) {
+ _gameSys->removeSpriteDrawItem(_savegameSprites[_savegameIndex], 263);
+ delayTicksCursor(5);
+ warning("memFreeHandle(_savegameSprites[_savegameIndex]);");
+ }
+ int v18 = _gameSys->getSpriteWidthById(0x104F9);
+ _savegameSprites[_savegameIndex] = _gameSys->allocSurface(v18, 40);
+ _gameSys->drawTextToSurface(_savegameSprites[_savegameIndex], 0, 0, 255, 0, 0, _savegameFilenames[_savegameIndex]);
+ _gameSys->insertSpriteDrawItem(_savegameSprites[_savegameIndex], 288, _hotspots[_savegameIndex]._y1, 263);
+ }
+ _savegameIndex = _sceneClickedHotspot;
+ v46 = strlen(_savegameFilenames[_sceneClickedHotspot]);
+ strcpy(v43, _savegameFilenames[_sceneClickedHotspot]);
+ if (_cursorSprite == nullptr) {
+ int v19 = _gameSys->getTextHeight("_");
+ int v20 = _gameSys->getTextWidth("_");
+ _cursorSprite = _gameSys->allocSurface(v20, v19);
+ _gameSys->drawTextToSurface(_cursorSprite, 0, 0, 255, 0, 0, "_");
+ } else {
+ _gameSys->removeSpriteDrawItem(_cursorSprite, 264);
+ }
+ int v21 = _hotspots[_savegameIndex]._x2;
+ int v22 = v21 - _gameSys->getTextWidth("_");
+ if (v22 > _gameSys->getTextWidth(_savegameFilenames[_savegameIndex]) + 288) {
+ int v25 = _gameSys->getTextWidth(_savegameFilenames[_savegameIndex]) + 288;
+ _gameSys->insertSpriteDrawItem(_cursorSprite, v25, _hotspots[_savegameIndex]._y1, 264);
+ } else {
+ int v23 = _hotspots[_savegameIndex]._x2;
+ int v24 = v23 - _gameSys->getTextWidth("_");
+ _gameSys->insertSpriteDrawItem(_cursorSprite, v24, _hotspots[_savegameIndex]._y1, 264);
+ }
+ }
+
+ updateEvents();
+ Common::Event event;
+ _eventMan->pollEvent(event);
+
+ Common::KeyCode keycode = event.kbd.keycode;
+ if (_savegameIndex != -1 && keycode) {
+ if ((keycode < Common::KEYCODE_a || keycode > Common::KEYCODE_z) && (keycode < Common::KEYCODE_0 || keycode > Common::KEYCODE_9) && keycode != Common::KEYCODE_SPACE) {
+ if (keycode == Common::KEYCODE_BACKSPACE) {
+ if (v46 > 0)
+ --v46;
+ _savegameFilenames[_savegameIndex][v46] = '\0';
+ if (_savegameSprites[_savegameIndex] != nullptr) {
+ _gameSys->removeSpriteDrawItem(_savegameSprites[_savegameIndex], 263);
+ warning("memFreeHandle(_savegameSprites[_savegameIndex]);");
+ }
+ int v32 = _gameSys->getSpriteWidthById(0x104F9);
+ _savegameSprites[_savegameIndex] = _gameSys->allocSurface(v32, 40);
+ _gameSys->drawTextToSurface(_savegameSprites[_savegameIndex], 0, 0, 255, 0, 0, _savegameFilenames[_savegameIndex]);
+ _gameSys->insertSpriteDrawItem(_savegameSprites[_savegameIndex], 288, _hotspots[_savegameIndex]._y1, 263);
+ _gameSys->removeSpriteDrawItem(_cursorSprite, 264);
+ int v33 = _hotspots[_savegameIndex]._y1;
+ int v34 = _gameSys->getTextWidth(_savegameFilenames[_savegameIndex]);
+ _gameSys->insertSpriteDrawItem(_cursorSprite, _hotspots[_savegameIndex]._x1 + v34, v33, 264);
+ } else if (keycode == Common::KEYCODE_RETURN) {
+ _menuStatus = 1;
+ warning("writeSavegame(_savegameIndex + 1, (int)&_savegameFilenames[30 * _savegameIndex], 1);");
+ }
+ } else {
+ _savegameFilenames[_savegameIndex][v46] = event.kbd.ascii;
+ if (v46 < 28)
+ ++v46;
+ _savegameFilenames[_savegameIndex][v46] = '\0';
+ if (_gameSys->getTextWidth(_savegameFilenames[_savegameIndex]) > 91) {
+ --v46;
+ _savegameFilenames[_savegameIndex][v46] = '\0';
+ }
+ _gameSys->drawTextToSurface(_savegameSprites[_savegameIndex], 0, 0, 255, 0, 0, _savegameFilenames[_savegameIndex]);
+ int v26 = _gameSys->getTextWidth(_savegameFilenames[_savegameIndex]);
+ Common::Rect rect;
+ rect.right = _hotspots[_savegameIndex]._x1 + v26;
+ int v27 = rect.right;
+ rect.left = v27 - 2 * _gameSys->getTextWidth("W");
+ rect.top = _hotspots[_savegameIndex]._y1;
+ rect.bottom = _hotspots[_savegameIndex]._y2;
+ _gameSys->insertDirtyRect(rect);
+ _gameSys->removeSpriteDrawItem(_cursorSprite, 264);
+ int v28 = _hotspots[_savegameIndex]._x2;
+ int v29 = _gameSys->getTextWidth("_");
+ if (v28 - v29 > rect.right)
+ _gameSys->insertSpriteDrawItem(_cursorSprite, rect.right, rect.top, 264);
+ else {
+ int v30 = _hotspots[_savegameIndex]._x2;
+ int v31 = v30 - _gameSys->getTextWidth("_");
+ _gameSys->insertSpriteDrawItem(_cursorSprite, v31, rect.top, 264);
+ }
+ clearKeyStatus1(8);
+ }
+ }
+
+// warning("keybChar = 0;");
+ if (_menuStatus == 1 || _menuDone) {
+ _gameSys->removeSpriteDrawItem(_menuSprite2, 262);
+ _gameSys->removeSpriteDrawItem(_menuSaveLoadSprite, 262);
+ for (int i = 0; i < 7; ++i)
+ _gameSys->removeSpriteDrawItem(_savegameSprites[i], 263);
+ _gameSys->removeSpriteDrawItem(_cursorSprite, 264);
+ if (!_menuDone) {
+ initMenuHotspots2();
+ _gameSys->insertSpriteDrawItem(_menuSprite1, 288, 79, 262);
+ }
+ }
+#endif
+}
+
+void GnapEngine::updateMenuStatusLoadGame() {
+ _hotspots[0]._rect = Common::Rect(288, 74, 379, 96);
+ _sceneClickedHotspot = -1;
+ if (!_timers[2])
+ _sceneClickedHotspot = getClickedHotspotId();
+ if (_sceneClickedHotspot != -1 && _hotspotsCount - 2 != _sceneClickedHotspot) {
+ _timers[2] = 10;
+ if (_hotspotsCount - 4 <= _sceneClickedHotspot) {
+ playSound(0x108F5, false);
+ _gameSys->removeSpriteDrawItem(_menuSprite2, 262);
+ _gameSys->removeSpriteDrawItem(_menuSaveLoadSprite, 262);
+ for (int i = 0; i < 7; ++i)
+ _gameSys->removeSpriteDrawItem(_savegameSprites[i], 263);
+ if (_hotspotsCount - 1 == _sceneClickedHotspot) {
+ _menuDone = true;
+ } else {
+ _menuStatus = 1;
+ initMenuHotspots2();
+ _gameSys->insertSpriteDrawItem(_menuSprite1, 288, 79, 262);
+ }
+ } else if (loadSavegame(_sceneClickedHotspot + 1)) {
+ playSound(0x108F5, false);
+ } else {
+ playSound(0x108F4, false);
+ _sceneDone = true;
+ }
+ }
+}
+
+void GnapEngine::updateMenuStatusQueryQuit() {
+ _hotspots[0]._rect = Common::Rect(311, 197, 377, 237);
+ _sceneClickedHotspot = -1;
+
+ if (!_timers[2])
+ _sceneClickedHotspot = getClickedHotspotId();
+
+ /* _sceneClickedHotspot
+ 0 Yes
+ 1 No
+ 2 Button
+ 3 Display
+ 4 Background
+ */
+
+ if (_sceneClickedHotspot == 0) {
+ // Quit the game
+ playSound(0x108F5, false);
+ _gameSys->removeSpriteDrawItem(_menuQuitQuerySprite, 262);
+ _sceneDone = true;
+ _gameDone = true;
+ } else if (_sceneClickedHotspot == 4) {
+ // Exit the device
+ playSound(0x108F4, false);
+ _gameSys->removeSpriteDrawItem(_menuQuitQuerySprite, 262);
+ _menuDone = true;
+ } else if (_sceneClickedHotspot != -1) {
+ // Return to the main menu
+ playSound(0x108F4, false);
+ _gameSys->removeSpriteDrawItem(_menuQuitQuerySprite, 262);
+ _timers[2] = 10;
+ _menuStatus = 1;
+ initMenuHotspots2();
+ _gameSys->insertSpriteDrawItem(_menuSprite1, 288, 79, 262);
+ }
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/module.mk b/engines/gnap/module.mk
new file mode 100644
index 0000000000..ab507cbf94
--- /dev/null
+++ b/engines/gnap/module.mk
@@ -0,0 +1,32 @@
+MODULE := engines/gnap
+
+MODULE_OBJS := \
+ character.o \
+ datarchive.o \
+ debugger.o \
+ detection.o \
+ gamesys.o \
+ gnap.o \
+ grid.o \
+ menu.o \
+ music.o \
+ resource.o \
+ sound.o \
+ scenes/arcade.o \
+ scenes/groupcs.o \
+ scenes/group0.o \
+ scenes/group1.o \
+ scenes/group2.o \
+ scenes/group3.o \
+ scenes/group4.o \
+ scenes/group5.o \
+ scenes/intro.o \
+ scenes/scenecore.o
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_GNAP), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/gnap/music.cpp b/engines/gnap/music.cpp
new file mode 100644
index 0000000000..af33786a8f
--- /dev/null
+++ b/engines/gnap/music.cpp
@@ -0,0 +1,104 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+// MIDI and digital music class
+
+#include "audio/mididrv.h"
+#include "audio/midiparser.h"
+#include "common/debug.h"
+#include "common/file.h"
+
+#include "gnap/music.h"
+#include "gnap/gnap.h"
+
+namespace Gnap {
+
+MusicPlayer::MusicPlayer(const char *filename) : _filename(filename) {
+
+ MidiPlayer::createDriver();
+
+ int ret = _driver->open();
+ if (ret == 0) {
+ if (_nativeMT32)
+ _driver->sendMT32Reset();
+ else
+ _driver->sendGMReset();
+
+ _driver->setTimerCallback(this, &timerCallback);
+ }
+}
+
+void MusicPlayer::sendToChannel(byte channel, uint32 b) {
+ if (!_channelsTable[channel]) {
+ _channelsTable[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
+ // If a new channel is allocated during the playback, make sure
+ // its volume is correctly initialized.
+ if (_channelsTable[channel])
+ _channelsTable[channel]->volume(_channelsVolume[channel] * _masterVolume / 255);
+ }
+
+ if (_channelsTable[channel])
+ _channelsTable[channel]->send(b);
+}
+
+void MusicPlayer::playSMF(bool loop) {
+ Common::StackLock lock(_mutex);
+
+ stop();
+
+ // Load MIDI resource data
+ Common::File musicFile;
+ musicFile.open(_filename);
+ if (!musicFile.isOpen()) {
+ debugC(2, kDebugMusic, "Cannot open music file %s", _filename.c_str());
+ return;
+ }
+ int midiMusicSize = musicFile.size();
+ free(_midiData);
+ _midiData = (byte *)malloc(midiMusicSize);
+ musicFile.read(_midiData, midiMusicSize);
+ musicFile.close();
+
+ MidiParser *parser = MidiParser::createParser_SMF();
+ if (parser->loadMusic(_midiData, midiMusicSize)) {
+ parser->setTrack(0);
+ parser->setMidiDriver(this);
+ parser->setTimerRate(_driver->getBaseTempo());
+ parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
+
+ _parser = parser;
+
+ syncVolume();
+
+ _isLooping = loop;
+ _isPlaying = true;
+ } else {
+ debugC(2, kDebugMusic, "Cannot play music file %s", _filename.c_str());
+ delete parser;
+ }
+}
+
+void MusicPlayer::stop() {
+ Audio::MidiPlayer::stop();
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/music.h b/engines/gnap/music.h
new file mode 100644
index 0000000000..c5938937eb
--- /dev/null
+++ b/engines/gnap/music.h
@@ -0,0 +1,50 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+// Music class
+
+#ifndef GNAP_MUSIC_H
+#define GNAP_MUSIC_H
+
+#include "audio/midiplayer.h"
+
+namespace Gnap {
+
+// Taken from Draci, which took it from MADE, which took it from SAGA.
+
+class MusicPlayer : public Audio::MidiPlayer {
+public:
+ MusicPlayer(const char *filename);
+
+ void playSMF(bool loop);
+ void stop();
+
+ // Overload Audio::MidiPlayer method
+ virtual void sendToChannel(byte channel, uint32 b);
+
+protected:
+ Common::String _filename;
+};
+
+} // End of namespace Gnap
+
+#endif
diff --git a/engines/gnap/resource.cpp b/engines/gnap/resource.cpp
new file mode 100644
index 0000000000..8244213a7f
--- /dev/null
+++ b/engines/gnap/resource.cpp
@@ -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.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "gnap/gnap.h"
+#include "gnap/resource.h"
+
+namespace Gnap {
+
+// SequenceFrame
+
+void SequenceFrame::loadFromStream(Common::MemoryReadStream &stream) {
+ _duration = stream.readUint16LE();
+ _isScaled = (stream.readUint16LE() != 0);
+ _rect.left = stream.readUint32LE();
+ _rect.top = stream.readUint32LE();
+ _rect.right = stream.readUint32LE();
+ _rect.bottom = stream.readUint32LE();
+ _spriteId = stream.readUint32LE();
+ _soundId = stream.readUint32LE();
+
+ // Skip an unused value
+ stream.readUint32LE();
+
+ debugC(kDebugBasic, "SequenceFrame() spriteId: %d; soundId: %d", _spriteId, _soundId);
+}
+
+// SequenceAnimation
+
+void SequenceAnimation::loadFromStream(Common::MemoryReadStream &stream) {
+ // Skip two unused values
+ stream.readUint32LE();
+
+ _additionalDelay = stream.readUint32LE();
+ _framesCount = stream.readUint16LE();
+ _maxTotalDuration = stream.readUint16LE();
+ debugC(kDebugBasic, "SequenceAnimation() framesCount: %d", _framesCount);
+ frames = new SequenceFrame[_framesCount];
+ for (int i = 0; i < _framesCount; ++i)
+ frames[i].loadFromStream(stream);
+}
+
+// SequenceResource
+SequenceResource::SequenceResource(byte *data, uint32 size) {
+ Common::MemoryReadStream stream(data, size, DisposeAfterUse::NO);
+
+ // Skip an unused value
+ stream.readUint32LE();
+
+ _sequenceId = stream.readUint32LE();
+ _defaultId = stream.readUint32LE();
+ _sequenceId2 = stream.readUint32LE();
+ _defaultId2 = stream.readUint32LE();
+ _flags = stream.readUint32LE();
+ _totalDuration = stream.readUint32LE();
+ _xOffs = stream.readUint16LE();
+ _yOffs = stream.readUint16LE();
+ _animationsCount = stream.readUint32LE();
+ _animations = new SequenceAnimation[_animationsCount];
+ debugC(kDebugBasic, "SequenceResource() _animationsCount: %d", _animationsCount);
+ for (int i = 0; i < _animationsCount; ++i) {
+ uint32 animationOffs = stream.readUint32LE();
+ debugC(kDebugBasic, "animationOffs: %08X", animationOffs);
+ uint32 oldOffs = stream.pos();
+ stream.seek(animationOffs);
+ _animations[i].loadFromStream(stream);
+ stream.seek(oldOffs);
+ }
+}
+
+SequenceResource::~SequenceResource() {
+ delete[] _animations;
+}
+
+// SpriteResource
+SpriteResource::SpriteResource(byte *data, uint32 size) {
+ _data = data;
+ _width = READ_LE_UINT16(_data);
+ _height = READ_LE_UINT16(_data + 2);
+ _unknownVal1 = READ_LE_UINT16(_data + 4);
+ _unknownVal2 = READ_LE_UINT16(_data + 6);
+ _transparent = (READ_LE_UINT16(_data + 8) != 0);
+ _colorsCount = READ_LE_UINT16(_data + 10);
+ _palette = (uint32 *)(_data + 12);
+ _pixels = _data + 12 + _colorsCount * 4;
+ debugC(kDebugBasic, "SpriteResource() width: %d; height: %d; colorsCount: %d", _width, _height, _colorsCount);
+}
+
+SpriteResource::~SpriteResource() {
+ delete[] _data;
+}
+
+// SoundResource
+SoundResource::SoundResource(byte *data, uint32 size) {
+ _data = data;
+ _size = size;
+}
+
+SoundResource::~SoundResource() {
+ delete[] _data;
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/resource.h b/engines/gnap/resource.h
new file mode 100644
index 0000000000..f4a3669eda
--- /dev/null
+++ b/engines/gnap/resource.h
@@ -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.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 GNAP_RESOURCE_H
+#define GNAP_RESOURCE_H
+
+#include "common/array.h"
+#include "common/events.h"
+#include "common/file.h"
+#include "common/memstream.h"
+#include "common/str.h"
+#include "common/stream.h"
+#include "common/substream.h"
+#include "common/system.h"
+
+#include "graphics/surface.h"
+
+#include "gnap/datarchive.h"
+
+namespace Gnap {
+
+enum {
+ kResTypeSprite = 0,
+ kResTypeBitmap = 1,
+ kResTypeSound = 2,
+ kResTypeSequence = 3
+};
+
+struct SequenceFrame {
+ int16 _duration;
+ bool _isScaled;
+ Common::Rect _rect;
+ int32 _spriteId;
+ int32 _soundId;
+ void loadFromStream(Common::MemoryReadStream &stream);
+};
+
+struct SequenceAnimation {
+ int32 _additionalDelay;
+ int16 _framesCount;
+ int16 _maxTotalDuration;
+ SequenceFrame *frames;
+
+ SequenceAnimation() : frames(nullptr), _additionalDelay(0), _framesCount(0), _maxTotalDuration(0) {}
+ ~SequenceAnimation() { delete[] frames; }
+ void loadFromStream(Common::MemoryReadStream &stream);
+};
+
+class SequenceResource {
+public:
+ SequenceResource(byte *data, uint32 size);
+ ~SequenceResource();
+public:
+ int32 _sequenceId;
+ int32 _defaultId;
+ int32 _sequenceId2;
+ uint32 _defaultId2;
+ uint32 _flags;
+ int32 _totalDuration;
+ int16 _xOffs;
+ int16 _yOffs;
+ int32 _animationsCount;
+ SequenceAnimation *_animations;
+};
+
+class SpriteResource {
+public:
+ SpriteResource(byte *data, uint32 size);
+ ~SpriteResource();
+public:
+ byte *_data;
+ byte *_pixels;
+ uint32 *_palette;
+ int16 _width, _height;
+ uint16 _unknownVal1;
+ uint16 _unknownVal2;
+ bool _transparent;
+ uint16 _colorsCount;
+};
+
+class SoundResource {
+public:
+ SoundResource(byte *data, uint32 size);
+ ~SoundResource();
+public:
+ byte *_data;
+ uint32 _size;
+};
+
+template <class ResourceClass, int ResourceType, bool FreeAfterLoad>
+class ResourceCacheTemplate {
+public:
+
+ ResourceCacheTemplate(DatManager *dat) : _dat(dat) {
+ }
+
+ ~ResourceCacheTemplate() {
+ }
+
+ ResourceClass *get(int resourceId) {
+ Resource *resource = find(resourceId);
+ if (!resource) {
+ debug(9, "Loading resource type %d with ID %08X from disk", ResourceType, resourceId);
+ resource = new Resource(load(resourceId));
+ _cache[resourceId] = resource;
+ } else {
+ debug(9, "Resource type %d with ID %08X was in cache", ResourceType, resourceId);
+ }
+ resource->_isLocked = true;
+ return resource->_obj;
+ }
+
+ void release(int resourceId) {
+ Resource *resource = find(resourceId);
+ if (resource)
+ resource->_isLocked = false;
+ }
+
+ void purge(bool force = false) {
+ for (CacheMapIterator it = _cache.begin(); it != _cache.end(); ++it) {
+ Resource *resource = it->_value;
+ if (force || !resource->_isLocked) {
+ delete resource;
+ _cache.erase(it);
+ }
+ }
+ }
+
+protected:
+
+ struct Resource {
+ ResourceClass *_obj;
+ bool _isLocked;
+ Resource(ResourceClass *obj) : _obj(obj), _isLocked(false) {}
+ ~Resource() { delete _obj; }
+ };
+
+ typedef Common::HashMap<int, Resource *> CacheMap;
+ typedef typename CacheMap::iterator CacheMapIterator;
+
+ DatManager *_dat;
+ CacheMap _cache;
+
+ Resource *find(int resourceId) {
+ CacheMapIterator it = _cache.find(resourceId);
+ if (it != _cache.end())
+ return it->_value;
+ return nullptr;
+ }
+
+ ResourceClass *load(int resourceId) {
+ if (_dat->getResourceType(resourceId) != ResourceType)
+ error("ResourceCache::load() Wrong resource type: Expected %d, got %d", ResourceType, _dat->getResourceType(resourceId));
+
+ byte *resourceData = _dat->loadResource(resourceId);
+ uint32 resourceSize = _dat->getResourceSize(resourceId);
+ ResourceClass *obj = new ResourceClass(resourceData, resourceSize);
+ if (FreeAfterLoad)
+ delete[] resourceData;
+ return obj;
+ }
+
+};
+
+typedef ResourceCacheTemplate<SpriteResource, kResTypeSprite, false> SpriteCache;
+typedef ResourceCacheTemplate<SoundResource, kResTypeSound, false> SoundCache;
+typedef ResourceCacheTemplate<SequenceResource, kResTypeSequence, true> SequenceCache;
+
+} // End of namespace Gnap
+
+#endif // GNAP_RESOURCE_H
diff --git a/engines/gnap/scenes/arcade.cpp b/engines/gnap/scenes/arcade.cpp
new file mode 100644
index 0000000000..028a9006d0
--- /dev/null
+++ b/engines/gnap/scenes/arcade.cpp
@@ -0,0 +1,2729 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/arcade.h"
+
+namespace Gnap {
+
+static const ObstacleDef kObstacleDefs[] = {
+ {0xB4, 15}, {0xCB, 14}, {0xCD, 13}, {0xCF, 15}, {0xBA, 14},
+ {0xCD, 13}, {0xCF, 12}, {0xCB, 15}, {0xBD, 13}, {0xCF, 12},
+ {0xCD, 11}, {0xCB, 15}, {0xB7, 12}, {0xCD, 11}, {0xCB, 10},
+ {0xCF, 15}, {0xCF, 14}, {0xBD, 13}, {0xCF, 12}, {0xCD, 11},
+ {0xCB, 15}, {0xCB, 13}, {0xB4, 12}, {0xCB, 11}, {0xCD, 10},
+ {0xCF, 15}, {0xCD, 12}, {0xBA, 12}, {0xCD, 12}, {0xCF, 12},
+ {0xCB, 15}, {0xCB, 9}, {0xCD, 9}, {0xCF, 9}, {0xCD, 9},
+ {0xCB, 9}, {0xCD, 9}, {0xCF, 5}, {0xBD, 13}, {0xCF, 8},
+ {0xCB, 8}, {0xCD, 15}, {0xB4, 1}, {0xBD, 7}, {0xCF, 7},
+ {0xCD, 7}, {0xCB, 7}, {0xCD, 7}, {0xCF, 15}, {0xCF, 15}
+};
+
+Scene49::Scene49(GnapEngine *vm) : Scene(vm) {
+ _scoreBarFlash = false;
+ _scoreBarPos = -1;
+ _scoreLevel = -1;
+ _obstacleIndex = -1;
+ _truckSequenceId = -1;
+ _truckId = -1;
+ _truckLaneNum = -1;
+
+ for (int i = 0; i < 5; i++) {
+ _obstacles[i]._currSequenceId = -1;
+ _obstacles[i]._closerSequenceId = -1;
+ _obstacles[i]._passedSequenceId = -1;
+ _obstacles[i]._splashSequenceId = -1;
+ _obstacles[i]._collisionSequenceId = -1;
+ _obstacles[i]._prevId = -1;
+ _obstacles[i]._currId = -1;
+ _obstacles[i]._laneNum = -1;
+ }
+}
+
+int Scene49::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ for (int i = 0; i < 5; ++i)
+ gameSys.setAnimation(0, 0, i + 2);
+ _vm->_timers[2] = 0;
+ _vm->_timers[0] = 0;
+ _vm->_timers[1] = 0;
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _vm->clearKeyStatus1(Common::KEYCODE_RIGHT);
+ _vm->clearKeyStatus1(Common::KEYCODE_LEFT);
+ return 0xD5;
+}
+
+void Scene49::updateHotspots() {
+ _vm->_hotspotsCount = 0;
+}
+
+void Scene49::checkObstacles() {
+ if (_vm->_timers[2] == 0) {
+ if (_vm->_timers[3] == 0) {
+ for (int i = 0; i < 5; ++i)
+ clearObstacle(i);
+ }
+
+ for (int j = 0; j < 5; ++j) {
+ if (_obstacles[j]._currSequenceId == 0) {
+ _vm->_timers[3] = 35;
+ _obstacles[j]._currSequenceId = kObstacleDefs[_obstacleIndex]._sequenceId;
+ switch (_obstacles[j]._currSequenceId) {
+ case 0xB4:
+ _obstacles[j]._laneNum = 1;
+ _obstacles[j]._closerSequenceId = 180;
+ _obstacles[j]._passedSequenceId = 181;
+ _obstacles[j]._splashSequenceId = 182;
+ _obstacles[j]._collisionSequenceId = 192;
+ break;
+ case 0xB7:
+ _obstacles[j]._laneNum = 2;
+ _obstacles[j]._closerSequenceId = 183;
+ _obstacles[j]._passedSequenceId = 184;
+ _obstacles[j]._splashSequenceId = 185;
+ _obstacles[j]._collisionSequenceId = 193;
+ break;
+ case 0xBD:
+ _obstacles[j]._laneNum = 3;
+ _obstacles[j]._closerSequenceId = 189;
+ _obstacles[j]._passedSequenceId = 190;
+ _obstacles[j]._splashSequenceId = 191;
+ _obstacles[j]._collisionSequenceId = 195;
+ break;
+ case 0xBA:
+ _obstacles[j]._laneNum = 2;
+ _obstacles[j]._closerSequenceId = 186;
+ _obstacles[j]._passedSequenceId = 187;
+ _obstacles[j]._splashSequenceId = 188;
+ _obstacles[j]._collisionSequenceId = 194;
+ break;
+ case 0xCB:
+ _obstacles[j]._laneNum = 1;
+ _obstacles[j]._closerSequenceId = 203;
+ _obstacles[j]._passedSequenceId = 204;
+ _obstacles[j]._splashSequenceId = 0;
+ _obstacles[j]._collisionSequenceId = 209;
+ break;
+ case 0xCD:
+ _obstacles[j]._laneNum = 2;
+ _obstacles[j]._closerSequenceId = 205;
+ _obstacles[j]._passedSequenceId = 206;
+ _obstacles[j]._splashSequenceId = 0;
+ _obstacles[j]._collisionSequenceId = 210;
+ break;
+ case 0xCF:
+ _obstacles[j]._laneNum = 3;
+ _obstacles[j]._closerSequenceId = 207;
+ _obstacles[j]._passedSequenceId = 208;
+ _obstacles[j]._splashSequenceId = 0;
+ _obstacles[j]._collisionSequenceId = 211;
+ break;
+ }
+ _obstacles[j]._prevId = _truckId;
+ _obstacles[j]._currId = _obstacles[j]._prevId;
+ _vm->_gameSys->setAnimation(_obstacles[j]._currSequenceId, _obstacles[j]._currId, j + 2);
+ _vm->_gameSys->insertSequence(_obstacles[j]._currSequenceId, _obstacles[j]._currId, 0, 0, kSeqNone, 0, 0, -50);
+ _vm->_timers[2] = kObstacleDefs[_obstacleIndex]._ticks;
+ ++_obstacleIndex;
+ if (_obstacleIndex == 50)
+ _obstacleIndex = 0;
+ break;
+ }
+ }
+ }
+}
+
+void Scene49::updateObstacle(int id) {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ Scene49Obstacle &obstacle = _obstacles[id];
+ obstacle._currId = obstacle._prevId;
+
+ switch (obstacle._laneNum) {
+ case 1:
+ obstacle._prevId = _truckId + 1;
+ break;
+ case 2:
+ if (_truckLaneNum != 2 && _truckLaneNum != 3)
+ obstacle._prevId = _truckId - 1;
+ else
+ obstacle._prevId = _truckId + 1;
+ break;
+ case 3:
+ if (_truckLaneNum != 1 && _truckLaneNum != 2)
+ obstacle._prevId = _truckId;
+ else
+ obstacle._prevId = _truckId - 1;
+ break;
+ }
+
+ if (obstacle._currSequenceId == obstacle._closerSequenceId) {
+ if (_truckLaneNum == obstacle._laneNum) {
+ if (obstacle._splashSequenceId) {
+ gameSys.setAnimation(obstacle._collisionSequenceId, obstacle._prevId, id + 2);
+ gameSys.insertSequence(obstacle._collisionSequenceId, obstacle._prevId,
+ obstacle._currSequenceId, obstacle._currId,
+ kSeqSyncWait, 0, 0, -50);
+ obstacle._currSequenceId = obstacle._collisionSequenceId;
+ _vm->playSound(0xE0, false);
+ increaseScore(30);
+ } else if ((obstacle._laneNum == 1 && _truckSequenceId == 0xB0) ||
+ (obstacle._laneNum == 2 && (_truckSequenceId == 0xB1 || _truckSequenceId == 0xB2)) ||
+ (obstacle._laneNum == 3 && _truckSequenceId == 0xB3)) {
+ gameSys.setAnimation(obstacle._passedSequenceId, obstacle._prevId, id + 2);
+ gameSys.insertSequence(obstacle._passedSequenceId, obstacle._prevId,
+ obstacle._currSequenceId, obstacle._currId,
+ kSeqSyncWait, 0, 0, -50);
+ obstacle._currSequenceId = obstacle._passedSequenceId;
+ } else {
+ gameSys.setAnimation(obstacle._collisionSequenceId, 256, 0);
+ gameSys.setAnimation(obstacle._passedSequenceId, obstacle._prevId, id + 2);
+ gameSys.insertSequence(obstacle._passedSequenceId, obstacle._prevId,
+ obstacle._currSequenceId, obstacle._currId,
+ kSeqSyncWait, 0, 0, -50);
+ gameSys.insertSequence(obstacle._collisionSequenceId, 256,
+ _truckSequenceId, _truckId,
+ kSeqSyncExists, 0, 0, -50);
+ _truckSequenceId = obstacle._collisionSequenceId;
+ _truckId = 256;
+ obstacle._currSequenceId = obstacle._passedSequenceId;
+ _vm->playSound(0xE1, false);
+ decreaseScore(30);
+ }
+ } else {
+ gameSys.setAnimation(obstacle._passedSequenceId, obstacle._prevId, id + 2);
+ gameSys.insertSequence(obstacle._passedSequenceId, obstacle._prevId,
+ obstacle._currSequenceId, obstacle._currId,
+ kSeqSyncWait, 0, 0, -50);
+ obstacle._currSequenceId = obstacle._passedSequenceId;
+ }
+ } else if (obstacle._currSequenceId == obstacle._passedSequenceId) {
+ if (_truckLaneNum == obstacle._laneNum) {
+ if (obstacle._splashSequenceId) {
+ gameSys.setAnimation(obstacle._collisionSequenceId, obstacle._prevId, id + 2);
+ gameSys.insertSequence(obstacle._collisionSequenceId, obstacle._prevId,
+ obstacle._currSequenceId, obstacle._currId,
+ kSeqSyncWait, 0, 0, -50);
+ obstacle._currSequenceId = obstacle._collisionSequenceId;
+ _vm->playSound(0xE0, false);
+ increaseScore(30);
+ }
+ } else if (obstacle._splashSequenceId) {
+ gameSys.setAnimation(obstacle._splashSequenceId, obstacle._prevId, id + 2);
+ gameSys.insertSequence(obstacle._splashSequenceId, obstacle._prevId,
+ obstacle._currSequenceId, obstacle._currId,
+ kSeqSyncWait, 0, 0, -50);
+ obstacle._currSequenceId = obstacle._splashSequenceId;
+ }
+ } else {
+ gameSys.setAnimation(0, 0, id + 2);
+ clearObstacle(id);
+ }
+}
+
+void Scene49::increaseScore(int amount) {
+ if (_scoreBarPos + amount <= 556) {
+ _scoreBarPos += amount;
+ _vm->_gameSys->fillSurface(nullptr, _scoreBarPos, 508, amount, 22, 255, 0, 0);
+ }
+
+ _scoreLevel = (_scoreBarPos + amount >= 556) ? 1 : 0;
+}
+
+void Scene49::decreaseScore(int amount) {
+ if (_scoreBarPos >= 226 && _scoreLevel == 0) {
+ if (_scoreBarFlash)
+ refreshScoreBar();
+ _vm->_gameSys->fillSurface(nullptr, _scoreBarPos, 508, amount, 22, 89, 0, 5);
+ _scoreBarPos -= amount;
+ _scoreLevel = 0;
+ }
+}
+
+void Scene49::refreshScoreBar() {
+ if (_scoreBarFlash)
+ _vm->_gameSys->fillSurface(nullptr, 226, 508, 330, 22, 255, 0, 0);
+ else
+ _vm->_gameSys->fillSurface(nullptr, 226, 508, 330, 22, 89, 0, 5);
+ _scoreBarFlash = !_scoreBarFlash;
+}
+
+void Scene49::clearObstacle(int index) {
+ _obstacles[index]._currSequenceId = 0;
+ _obstacles[index]._closerSequenceId = 0;
+ _obstacles[index]._passedSequenceId = 0;
+ _obstacles[index]._splashSequenceId = 0;
+ _obstacles[index]._collisionSequenceId = 0;
+ _obstacles[index]._prevId = 0;
+ _obstacles[index]._currId = 0;
+ _obstacles[index]._laneNum = 0;
+}
+
+void Scene49::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ bool animToggle6 = false;
+ bool animToggle5 = false;
+ bool animToggle4 = false;
+ bool animToggle3 = false;
+ bool streetAnimToggle = false;
+ bool bgAnimToggle = false;
+
+ _vm->playSound(0xE2, true);
+ _vm->setSoundVolume(0xE2, 75);
+
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+
+ _scoreBarPos = 196;
+ _scoreLevel = 0;
+ _scoreBarFlash = false;
+
+ switch (_vm->getRandom(3)) {
+ case 0:
+ _truckSequenceId = 0xAD;
+ _truckLaneNum = 1;
+ break;
+ case 1:
+ _truckSequenceId = 0xAE;
+ _truckLaneNum = 2;
+ break;
+ case 2:
+ _truckSequenceId = 0xAF;
+ _truckLaneNum = 3;
+ break;
+ }
+
+ int bgWidth1 = gameSys.getSpriteWidthById(0x5E);
+ int bgX1 = 600;
+
+ int bgWidth2 = gameSys.getSpriteWidthById(0x5F);
+ int bgX2 = 400;
+
+ int bgWidth3 = gameSys.getSpriteWidthById(4);
+ int bgX3 = 700;
+
+ int bgWidth4 = gameSys.getSpriteWidthById(5);
+ int bgX4 = 500;
+
+ int bgWidth5 = gameSys.getSpriteWidthById(6);
+ int bgX5 = 300;
+
+ int bgWidth6 = gameSys.getSpriteWidthById(7);
+ int bgX6 = 100;
+
+ gameSys.setAnimation(0xC8, 251, 1);
+ gameSys.setAnimation(_truckSequenceId, 256, 0);
+ gameSys.insertSequence(0xC9, 256, 0, 0, kSeqNone, 0, 600, 85);
+ gameSys.insertSequence(0xCA, 257, 0, 0, kSeqNone, 0, 400, 100);
+ gameSys.insertSequence(0xC4, 256, 0, 0, kSeqNone, 0, 700, 140);
+ gameSys.insertSequence(0xC5, 257, 0, 0, kSeqNone, 0, 500, 160);
+ gameSys.insertSequence(0xC6, 258, 0, 0, kSeqNone, 0, 300, 140);
+ gameSys.insertSequence(0xC7, 259, 0, 0, kSeqNone, 0, 100, 140);
+ gameSys.insertSequence(0xC8, 251, 0, 0, kSeqNone, 0, 0, -50);
+ gameSys.insertSequence(_truckSequenceId, 256, 0, 0, kSeqNone, 0, 0, -50);
+
+ _vm->_timers[0] = 2;
+
+ for (int i = 0; i < 5; ++i)
+ clearObstacle(i);
+
+ _obstacleIndex = 0;
+
+ _vm->_timers[2] = _vm->getRandom(20) + 10;
+
+ _truckId = 256;
+ _vm->_timers[3] = 35;
+
+ while (!_vm->_sceneDone) {
+ if (_vm->_timers[0] == 0) {
+ // Update background animations (clouds etc.)
+ --bgX1;
+ bgX2 -= 2;
+ bgX3 -= 5;
+ --bgX4;
+ --bgX5;
+ --bgX6;
+ if (bgX1 <= -bgWidth1)
+ bgX1 = 799;
+ if (bgX2 <= -bgWidth2)
+ bgX2 = 799;
+ if (bgX3 <= -bgWidth3)
+ bgX3 = 799;
+ if (bgX4 <= -bgWidth4)
+ bgX4 = 799;
+ if (bgX5 <= -bgWidth5)
+ bgX5 = 799;
+ if (bgX6 <= -bgWidth6)
+ bgX6 = 799;
+ bgAnimToggle = !bgAnimToggle;
+ gameSys.insertSequence(0xC9, (bgAnimToggle ? 1 : 0) + 256, 0xC9, (bgAnimToggle ? 0 : 1) + 256, kSeqSyncWait, 0, bgX1, 85);
+ gameSys.insertSequence(0xCA, (bgAnimToggle ? 1 : 0) + 257, 0xCA, (bgAnimToggle ? 0 : 1) + 257, kSeqSyncWait, 0, bgX2, 100);
+ gameSys.insertSequence(0xC4, (bgAnimToggle ? 1 : 0) + 256, 0xC4, (bgAnimToggle ? 0 : 1) + 256, kSeqSyncWait, 0, bgX3, 140);
+ gameSys.insertSequence(0xC5, (bgAnimToggle ? 1 : 0) + 257, 0xC5, (bgAnimToggle ? 0 : 1) + 257, kSeqSyncWait, 0, bgX4, 160);
+ gameSys.insertSequence(0xC6, (bgAnimToggle ? 1 : 0) + 258, 0xC6, (bgAnimToggle ? 0 : 1) + 258, kSeqSyncWait, 0, bgX5, 140);
+ gameSys.insertSequence(0xC7, (bgAnimToggle ? 1 : 0) + 259, 0xC7, (bgAnimToggle ? 0 : 1) + 259, kSeqSyncWait, 0, bgX6, 140);
+ _vm->_timers[0] = 2;
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ streetAnimToggle = !streetAnimToggle;
+ gameSys.setAnimation(0xC8, (streetAnimToggle ? 1 : 0) + 251, 1);
+ gameSys.insertSequence(0xC8, (streetAnimToggle ? 1 : 0) + 251, 200, (streetAnimToggle ? 0 : 1) + 251, kSeqSyncWait, 0, 0, -50);
+ }
+
+ checkObstacles();
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ switch (_truckSequenceId) {
+ case 0xB1:
+ _truckLaneNum = 1;
+ break;
+ case 0xB0:
+ case 0xB3:
+ _truckLaneNum = 2;
+ break;
+ case 0xB2:
+ _truckLaneNum = 3;
+ break;
+ }
+ animToggle3 = !animToggle3;
+ if (_truckLaneNum == 1) {
+ gameSys.setAnimation(0xAD, (animToggle3 ? 1 : 0) + 256, 0);
+ gameSys.insertSequence(0xAD, (animToggle3 ? 1 : 0) + 256, _truckSequenceId, _truckId, kSeqSyncWait, 0, 0, -50);
+ _truckSequenceId = 0xAD;
+ } else if (_truckLaneNum == 2) {
+ gameSys.setAnimation(0xAE, (animToggle3 ? 1 : 0) + 256, 0);
+ gameSys.insertSequence(0xAE, (animToggle3 ? 1 : 0) + 256, _truckSequenceId, _truckId, kSeqSyncWait, 0, 0, -50);
+ _truckSequenceId = 0xAE;
+ } else {
+ gameSys.setAnimation(0xAF, (animToggle3 ? 1 : 0) + 256, 0);
+ gameSys.insertSequence(0xAF, (animToggle3 ? 1 : 0) + 256, _truckSequenceId, _truckId, kSeqSyncWait, 0, 0, -50);
+ _truckSequenceId = 0xAF;
+ }
+ _truckId = (animToggle3 ? 1 : 0) + 256;
+ if (_scoreLevel == 1) {
+ if (!gameSys.isSequenceActive(0xD4, 266)) {
+ gameSys.setAnimation(0xD4, 266, 8);
+ gameSys.insertSequence(0xD4, 266, 0, 0, kSeqNone, 0, 0, -50);
+ }
+ ++_scoreLevel;
+ _vm->_timers[1] = 2;
+ animToggle4 = false;
+ animToggle5 = false;
+ animToggle6 = false;
+ _scoreBarFlash = false;
+ }
+ }
+
+ if (_scoreLevel != 0 && !_vm->_timers[1]) {
+ refreshScoreBar();
+ _vm->_timers[1] = 8;
+ if (animToggle6) {
+ if (animToggle5) {
+ if (animToggle4 && !gameSys.isSequenceActive(212, 266))
+ gameSys.insertSequence(212, 266, 0, 0, kSeqNone, 0, 0, -50);
+ animToggle4 = !animToggle4;
+ }
+ animToggle5 = !animToggle5;
+ }
+ animToggle6 = !animToggle6;
+ }
+
+ updateAnimations();
+
+ if (clearKeyStatus()) {
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 2;
+ _vm->_newCursorValue = 1;
+ }
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_RIGHT)) {
+ // Steer right
+ if (_truckSequenceId == 0xB3)
+ _truckLaneNum = 2;
+ if (_truckSequenceId == 0xB1)
+ _truckLaneNum = 1;
+ if (_truckLaneNum != 3 && _truckLaneNum != 2) {
+ if (_scoreLevel) {
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 47;
+ }
+ } else {
+ int steerSequenceId = (_truckLaneNum == 3) ? 0xB3 : 0xB1;
+ if (_truckSequenceId == 0xAE || _truckSequenceId == 0xAF) {
+ gameSys.setAnimation(steerSequenceId, 256, 0);
+ gameSys.insertSequence(steerSequenceId, 256, _truckSequenceId, _truckId, kSeqSyncExists, 0, 0, -50);
+ _truckSequenceId = steerSequenceId;
+ _truckId = 256;
+ }
+ }
+ _vm->clearKeyStatus1(Common::KEYCODE_RIGHT);
+ }
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_LEFT)) {
+ // Steer left
+ if (_truckSequenceId == 0xB0)
+ _truckLaneNum = 2;
+ if (_truckSequenceId == 0xB2)
+ _truckLaneNum = 3;
+ if (_truckLaneNum == 1 || _truckLaneNum == 2) {
+ int steerSequenceId = (_truckLaneNum == 1) ? 0xB0 : 0xB2;
+ if (_truckSequenceId == 0xAD || _truckSequenceId == 0xAE) {
+ gameSys.setAnimation(steerSequenceId, 256, 0);
+ gameSys.insertSequence(steerSequenceId, 256, _truckSequenceId, _truckId, kSeqSyncExists, 0, 0, -50);
+ _truckSequenceId = steerSequenceId;
+ _truckId = 256;
+ }
+ }
+ _vm->clearKeyStatus1(Common::KEYCODE_LEFT);
+ }
+ _vm->gameUpdateTick();
+ }
+ _vm->stopSound(0xE2);
+}
+
+void Scene49::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ for (int i = 0; i < 5; ++i) {
+ if (gameSys.getAnimationStatus(i + 2) == 2) {
+ if (_obstacles[i]._currSequenceId)
+ updateObstacle(i);
+ }
+ }
+
+ if (gameSys.getAnimationStatus(8) == 2) {
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 47;
+ }
+}
+
+/*****************************************************************************/
+
+Scene50::Scene50(GnapEngine *vm) : Scene(vm) {
+ _fightDone = false;
+
+ _roundNum = -1;
+ _timeRemaining = -1;
+ _leftTongueRoundsWon = -1;
+ _rightTongueRoundsWon = -1;
+ _leftTongueSequenceId = -1;
+ _leftTongueId = -1;
+ _leftTongueNextSequenceId = -1;
+ _leftTongueNextId = -1;
+ _rightTongueSequenceId = -1;
+ _rightTongueId = -1;
+ _rightTongueNextSequenceId = -1;
+ _rightTongueNextId = -1;
+ _leftTongueEnergy = -1;
+ _rightTongueEnergy = -1;
+
+ _timesPlayed = 0;
+ _timesPlayedModifier = 0;
+ _attackCounter = 0;
+ _leftTongueEnergyBarPos = 10;
+ _leftTongueNextIdCtr = 0;
+ _rightTongueEnergyBarPos = 10;
+ _rightTongueNextIdCtr = 0;
+}
+
+int Scene50::init() {
+ return 0xC7;
+}
+
+void Scene50::updateHotspots() {
+ _vm->_hotspotsCount = 0;
+}
+
+bool Scene50::tongueWinsRound(int tongueNum) {
+ if (tongueNum == 1)
+ ++_leftTongueRoundsWon;
+ else
+ ++_rightTongueRoundsWon;
+ playWinBadgeAnim(tongueNum);
+ bool fightOver = _rightTongueRoundsWon == 2 || _leftTongueRoundsWon == 2;
+ playWinAnim(tongueNum, fightOver);
+ return fightOver;
+}
+
+void Scene50::playWinAnim(int tongueNum, bool fightOver) {
+ if (tongueNum == 1) {
+ if (fightOver) {
+ _vm->_gameSys->insertSequence(0xAD, 140, 0xAC, 140, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xB4, 100, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xBD, 100, _rightTongueSequenceId, _rightTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xBC, 100, 0xBD, 100, kSeqSyncWait, 0, 0, 0);
+ _leftTongueSequenceId = 0xB4;
+ _rightTongueSequenceId = 0xBC;
+ _rightTongueId = 100;
+ _leftTongueId = 100;
+ _vm->_gameSys->setAnimation(0xB4, 100, 6);
+ _vm->_gameSys->setAnimation(_rightTongueSequenceId, 100, 5);
+ waitForAnim(6);
+ waitForAnim(5);
+ _vm->invAdd(kItemGum);
+ _vm->setFlag(kGFUnk13);
+ } else {
+ _vm->_gameSys->insertSequence(0xB4, 100, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xBD, 100, _rightTongueSequenceId, _rightTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xBC, 100, 0xBD, 100, kSeqSyncWait, 0, 0, 0);
+ _leftTongueSequenceId = 0xB4;
+ _rightTongueSequenceId = 0xBC;
+ _rightTongueId = 100;
+ _leftTongueId = 100;
+ _vm->_gameSys->setAnimation(0xB4, 100, 6);
+ _vm->_gameSys->setAnimation(_rightTongueSequenceId, 100, 5);
+ waitForAnim(6);
+ waitForAnim(5);
+ }
+ } else {
+ _vm->_gameSys->insertSequence(0xBE, 100, _rightTongueSequenceId, _rightTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->setAnimation(0xBE, 100, 5);
+ waitForAnim(5);
+ _vm->_gameSys->insertSequence(0xBF, 100, 0xBE, 100, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xB5, 100, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0);
+ _rightTongueSequenceId = 0xBF;
+ _leftTongueSequenceId = 0xB5;
+ _rightTongueId = 100;
+ _leftTongueId = 100;
+ _vm->_gameSys->setAnimation(0xB5, 100, 6);
+ _vm->_gameSys->setAnimation(_rightTongueSequenceId, 100, 5);
+ waitForAnim(6);
+ waitForAnim(5);
+ }
+ _vm->delayTicksA(1, 7);
+}
+
+void Scene50::delayTicks() {
+ _vm->delayTicksA(3, 7);
+}
+
+void Scene50::initRound() {
+ _leftTongueEnergy = 10;
+ _rightTongueEnergy = 10;
+ _fightDone = false;
+ _vm->_timers[3] = getRightTongueActionTicks();
+ _vm->_timers[4] = 0;
+ _vm->_timers[6] = 0;
+ _vm->_gameSys->fillSurface(nullptr, 91, 73, 260, 30, 212, 0, 0);
+ _vm->_gameSys->fillSurface(nullptr, 450, 73, 260, 30, 212, 0, 0);
+ _timeRemaining = 40;
+ drawCountdown(40);
+}
+
+bool Scene50::updateCountdown() {
+ if (!_vm->_timers[5]) {
+ --_timeRemaining;
+ if (_timeRemaining < 0) {
+ return true;
+ } else {
+ _vm->_timers[5] = 15;
+ drawCountdown(_timeRemaining);
+ }
+ }
+ return false;
+}
+
+void Scene50::drawCountdown(int value) {
+ char str[8];
+ sprintf(str, "%02d", value);
+ _vm->_gameSys->fillSurface(nullptr, 371, 505, 50, 27, 0, 0, 0);
+ _vm->_gameSys->drawTextToSurface(nullptr, 381, 504, 255, 255, 255, str);
+}
+
+void Scene50::playTonguesIdle() {
+ _vm->_gameSys->insertSequence(0xBA, 100, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xC2, 100, _rightTongueSequenceId, _rightTongueId, kSeqSyncWait, 0, 0, 0);
+ _leftTongueSequenceId = 0xBA;
+ _rightTongueSequenceId = 0xC2;
+ _rightTongueNextSequenceId = -1;
+ _leftTongueNextSequenceId = -1;
+ _leftTongueId = 100;
+ _rightTongueId = 100;
+ _vm->_gameSys->setAnimation(0xC2, 100, 5);
+ _vm->_gameSys->setAnimation(_leftTongueSequenceId, _leftTongueId, 6);
+}
+
+void Scene50::playRoundAnim(int roundNum) {
+ int sequenceId = 0;
+
+ switch (roundNum) {
+ case 1:
+ sequenceId = 0xAF;
+ break;
+ case 2:
+ sequenceId = 0xB0;
+ break;
+ case 3:
+ sequenceId = 0xB1;
+ break;
+ }
+
+ _vm->_gameSys->insertSequence(sequenceId, 256, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_gameSys->setAnimation(sequenceId, 256, 7);
+ waitForAnim(7);
+
+ _vm->_gameSys->insertSequence(0xAB, 256, sequenceId, 256, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->setAnimation(0xAB, 256, 7);
+ waitForAnim(7);
+}
+
+bool Scene50::updateEnergyBars(int newLeftBarPos, int newRightBarPos) {
+ if (newLeftBarPos != _leftTongueEnergyBarPos) {
+ if (newLeftBarPos < 0)
+ newLeftBarPos = 0;
+ _leftTongueEnergyBarPos = newLeftBarPos;
+ _vm->_gameSys->fillSurface(nullptr, 26 * newLeftBarPos + 91, 73, 260 - 26 * newLeftBarPos, 30, 0, 0, 0);
+ }
+
+ if (newRightBarPos != _rightTongueEnergyBarPos) {
+ if (newRightBarPos < 0)
+ newRightBarPos = 0;
+ _rightTongueEnergyBarPos = newRightBarPos;
+ if (newRightBarPos != 10)
+ _vm->_gameSys->fillSurface(nullptr, 26 * (9 - newRightBarPos) + 450, 73, 26, 30, 0, 0, 0);
+ }
+
+ if (newLeftBarPos * newRightBarPos > 0)
+ return false;
+
+ _leftTongueEnergyBarPos = 10;
+ _rightTongueEnergyBarPos = 10;
+ return true;
+}
+
+void Scene50::waitForAnim(int animationIndex) {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ while (gameSys.getAnimationStatus(animationIndex) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ gameSys.setAnimation(0, 0, animationIndex);
+}
+
+int Scene50::checkInput() {
+ int sequenceId = -1;
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_RIGHT)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_RIGHT);
+ sequenceId = 0xB6;
+ } else if (_vm->isKeyStatus1(Common::KEYCODE_LEFT)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_LEFT);
+ sequenceId = 0xB3;
+ } else if (_vm->isKeyStatus1(Common::KEYCODE_ESCAPE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _fightDone = true;
+ }
+
+ return sequenceId;
+}
+
+int Scene50::getRightTongueAction() {
+ int sequenceId = -1;
+
+ if (!_vm->_timers[3]) {
+ _vm->_timers[3] = getRightTongueActionTicks();
+ if (_rightTongueEnergy >= _leftTongueEnergy) {
+ switch (_vm->getRandom(5)) {
+ case 0:
+ sequenceId = 0xBE;
+ break;
+ case 1:
+ sequenceId = 0xBE;
+ break;
+ case 2:
+ sequenceId = 0xBB;
+ break;
+ case 3:
+ sequenceId = 0xBB;
+ break;
+ case 4:
+ sequenceId = 0xBB;
+ break;
+ }
+ } else {
+ switch (_vm->getRandom(4)) {
+ case 0:
+ sequenceId = 0xBE;
+ break;
+ case 1:
+ sequenceId = 0xBB;
+ break;
+ case 2:
+ sequenceId = 0xBE;
+ break;
+ case 3:
+ sequenceId = 0xBE;
+ break;
+ }
+ }
+ }
+
+ return sequenceId;
+}
+
+void Scene50::updateAnimations() {
+ if (!_vm->_timers[4])
+ _attackCounter = 0;
+
+ if (_vm->_gameSys->getAnimationStatus(5) == 2) {
+ if (_rightTongueSequenceId == 0xBE) {
+ if (_leftTongueSequenceId != 0xB3 && _leftTongueSequenceId != 0xB8)
+ _rightTongueNextSequenceId = 0xBF;
+ else
+ _rightTongueNextSequenceId = 0xC0;
+ }
+ if (_rightTongueNextSequenceId == -1)
+ _rightTongueNextSequenceId = 0xC2;
+ if (_rightTongueNextSequenceId == 0xBF) {
+ _leftTongueNextId = getLeftTongueNextId();
+ _rightTongueNextId = getRightTongueNextId();
+ _vm->_gameSys->setAnimation(_rightTongueNextSequenceId, _rightTongueNextId, 5);
+ _vm->_gameSys->setAnimation(0xB9, _leftTongueNextId, 6);
+ _vm->_gameSys->insertSequence(_rightTongueNextSequenceId, _rightTongueNextId, _rightTongueSequenceId, _rightTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xB9, _leftTongueNextId, _leftTongueSequenceId, _leftTongueId, kSeqSyncExists, 0, 0, 0);
+ _rightTongueSequenceId = _rightTongueNextSequenceId;
+ _rightTongueNextSequenceId = -1;
+ _leftTongueSequenceId = 0xB9;
+ _leftTongueNextSequenceId = -1;
+ _rightTongueId = _rightTongueNextId;
+ _leftTongueId = _leftTongueNextId;
+ _leftTongueEnergy -= _vm->getRandom(1) + 1;
+ } else {
+ _rightTongueNextId = getRightTongueNextId();
+ _vm->_gameSys->setAnimation(_rightTongueNextSequenceId, _rightTongueNextId, 5);
+ _vm->_gameSys->insertSequence(_rightTongueNextSequenceId, _rightTongueNextId, _rightTongueSequenceId, _rightTongueId, kSeqSyncWait, 0, 0, 0);
+ _rightTongueSequenceId = _rightTongueNextSequenceId;
+ _rightTongueNextSequenceId = -1;
+ _rightTongueId = _rightTongueNextId;
+ }
+ }
+
+ if (_vm->_gameSys->getAnimationStatus(6) == 2) {
+ if (_leftTongueSequenceId == 0xB6) {
+ ++_attackCounter;
+ if (_timesPlayedModifier + 3 <= _attackCounter) {
+ _leftTongueNextSequenceId = 0xB8;
+ } else {
+ _vm->_timers[4] = 20;
+ if (_rightTongueSequenceId != 0xBB && _rightTongueSequenceId != 0xC0 && _vm->getRandom(7) != _roundNum)
+ _leftTongueNextSequenceId = 0xB7;
+ else
+ _leftTongueNextSequenceId = 0xB8;
+ }
+ }
+ if (_leftTongueNextSequenceId == 0xB3)
+ --_attackCounter;
+ if (_leftTongueNextSequenceId == -1)
+ _leftTongueNextSequenceId = 0xBA;
+ if (_leftTongueNextSequenceId == 0xB7) {
+ _leftTongueNextId = getLeftTongueNextId();
+ _rightTongueNextId = getRightTongueNextId();
+ _vm->_gameSys->setAnimation(_leftTongueNextSequenceId, _leftTongueNextId, 6);
+ _vm->_gameSys->setAnimation(0xC1, _rightTongueNextId, 5);
+ _vm->_gameSys->insertSequence(_leftTongueNextSequenceId, _leftTongueNextId, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xC1, _rightTongueNextId, _rightTongueSequenceId, _rightTongueId, kSeqSyncExists, 0, 0, 0);
+ _leftTongueSequenceId = _leftTongueNextSequenceId;
+ _leftTongueNextSequenceId = -1;
+ _rightTongueSequenceId = 0xC1;
+ _rightTongueNextSequenceId = -1;
+ _rightTongueId = _rightTongueNextId;
+ _leftTongueId = _leftTongueNextId;
+ --_rightTongueEnergy;
+ } else if (_leftTongueNextSequenceId != 0xB8 || _rightTongueSequenceId != 0xC2) {
+ _leftTongueNextId = getLeftTongueNextId();
+ _vm->_gameSys->setAnimation(_leftTongueNextSequenceId, _leftTongueNextId, 6);
+ _vm->_gameSys->insertSequence(_leftTongueNextSequenceId, _leftTongueNextId, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0);
+ _leftTongueSequenceId = _leftTongueNextSequenceId;
+ _leftTongueNextSequenceId = -1;
+ _leftTongueId = _leftTongueNextId;
+ } else {
+ _leftTongueNextId = getLeftTongueNextId();
+ _rightTongueNextId = getRightTongueNextId();
+ _vm->_gameSys->setAnimation(0xBB, _rightTongueNextId, 5);
+ _vm->_gameSys->setAnimation(_leftTongueNextSequenceId, _leftTongueNextId, 6);
+ _vm->_gameSys->insertSequence(_leftTongueNextSequenceId, _leftTongueNextId, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xBB, _rightTongueNextId, _rightTongueSequenceId, _rightTongueId, kSeqSyncExists, 0, 0, 0);
+ _rightTongueSequenceId = 0xBB;
+ _rightTongueId = _rightTongueNextId;
+ _rightTongueNextSequenceId = -1;
+ _leftTongueSequenceId = _leftTongueNextSequenceId;
+ _leftTongueNextSequenceId = -1;
+ _leftTongueId = _leftTongueNextId;
+ }
+ }
+}
+
+int Scene50::getRightTongueActionTicks() {
+ return 15 - 5 * _roundNum + 1;
+}
+
+int Scene50::getLeftTongueNextId() {
+ _leftTongueNextIdCtr = (_leftTongueNextIdCtr + 1) % 3;
+ return _leftTongueNextIdCtr + 100;
+}
+
+int Scene50::getRightTongueNextId() {
+ _rightTongueNextIdCtr = (_rightTongueNextIdCtr + 1) % 3;
+ return _rightTongueNextIdCtr + 100;
+}
+
+void Scene50::playWinBadgeAnim(int tongueNum) {
+ int sequenceId;
+
+ if (tongueNum == 1) {
+ if (_leftTongueRoundsWon == 1)
+ sequenceId = 0xC3;
+ else
+ sequenceId = 0xC4;
+ } else {
+ if (_rightTongueRoundsWon == 1)
+ sequenceId = 0xC5;
+ else
+ sequenceId = 0xC6;
+ }
+
+ _vm->_gameSys->setAnimation(sequenceId, 120, 7);
+ _vm->_gameSys->insertSequence(sequenceId, 120, 0, 0, kSeqNone, 0, 0, 0);
+ waitForAnim(7);
+}
+
+void Scene50::run() {
+ ++_timesPlayed;
+ _timesPlayedModifier = _timesPlayed / 4;
+ _leftTongueRoundsWon = 0;
+ _rightTongueRoundsWon = 0;
+ // initFont();
+ _leftTongueSequenceId = 186;
+ _rightTongueSequenceId = 194;
+ _rightTongueNextSequenceId = -1;
+ _leftTongueNextSequenceId = -1;
+ _leftTongueId = 100;
+ _rightTongueId = 100;
+
+ _vm->_gameSys->setAnimation(194, 100, 5);
+ _vm->_gameSys->setAnimation(_leftTongueSequenceId, _leftTongueId, 6);
+ _vm->_gameSys->insertSequence(_leftTongueSequenceId, _leftTongueId, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_gameSys->insertSequence(_rightTongueSequenceId, _rightTongueId, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_gameSys->insertSequence(172, 140, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+
+ initRound();
+
+ _roundNum = 1;
+
+ _vm->setGrabCursorSprite(-1);
+ _vm->hideCursor();
+
+ _vm->delayTicksA(1, 7);
+
+ playRoundAnim(_roundNum);
+
+ _vm->_timers[5] = 15;
+
+ while (!_fightDone && !_vm->_gameDone) {
+ int playerSequenceId = checkInput();
+ if (playerSequenceId != -1)
+ _leftTongueNextSequenceId = playerSequenceId;
+
+ int rightSequenceId = getRightTongueAction();
+ if (rightSequenceId != -1)
+ _rightTongueNextSequenceId = rightSequenceId;
+
+ updateAnimations();
+
+ if (updateCountdown() ||
+ updateEnergyBars(_leftTongueEnergy, _rightTongueEnergy)) {
+ bool v0;
+ if (_rightTongueEnergy < _leftTongueEnergy)
+ v0 = tongueWinsRound(1);
+ else
+ v0 = tongueWinsRound(2);
+ if (v0) {
+ delayTicks();
+ _fightDone = true;
+ } else {
+ ++_roundNum;
+ initRound();
+ playTonguesIdle();
+ updateEnergyBars(_leftTongueEnergy, _rightTongueEnergy);
+ playRoundAnim(_roundNum);
+ _vm->_timers[5] = 15;
+ }
+ }
+ _vm->gameUpdateTick();
+ }
+
+ _vm->_gameSys->setAnimation(0, 0, 7);
+ _vm->_gameSys->setAnimation(0, 0, 6);
+ _vm->_gameSys->setAnimation(0, 0, 5);
+ _vm->_gameSys->setAnimation(0, 0, 3);
+
+ _vm->showCursor();
+}
+
+/*****************************************************************************/
+
+static const int kDigitSequenceIds[] = {
+ 0xCA, 0xCB, 0xCC, 0xCD, 0xCE,
+ 0xCF, 0xD0, 0xD1, 0xD2, 0xD3
+};
+
+static const int kDigitPositions[4] = {
+ 0, 34, 83, 119
+};
+
+/*
+ 0xBA Falling banana peel
+ 0xBC Banana peel goes away
+ 0xBD Falling coin
+ 0xBE Fallen coin
+ 0xC0 Falling banknote
+ 0xB6 Platypus tripping (right)
+ 0xB7 Platypus tripping (left)
+ 0x76 Platypus jumping (right)
+*/
+
+Scene51::Scene51(GnapEngine *vm) : Scene(vm) {
+ _dropLoseCash = false;
+
+ _cashAmount = -1;
+ _guySequenceId = -1;
+ _guyNextSequenceId = -1;
+ _itemsCaughtCtr = -1;
+ _dropSpeedTicks = -1;
+ _nextDropItemKind = -1;
+ _itemInsertX = -1;
+ _itemInsertDirection = -1;
+ _platypusSequenceId = -1;
+ _platypusNextSequenceId = -1;
+ _platypusJumpSequenceId = -1;
+ _itemsCtr = -1;
+ _itemsCtr1 = -1;
+ _itemsCtr2 = -1;
+
+ for (int i = 0; i < 4; i++) {
+ _digits[i] = 0;
+ _digitSequenceIds[i] = -1;
+ }
+
+ for (int i = 0; i < 6; i++) {
+ _items[i]._currSequenceId = -1;
+ _items[i]._droppedSequenceId = 0;
+ _items[i]._x = 0;
+ _items[i]._y = 0;
+ _items[i]._collisionX = 0;
+ _items[i]._canCatch = false;
+ _items[i]._isCollision = false;
+ _items[i]._x2 = 0;
+ _items[i]._id = -1;
+ }
+}
+
+int Scene51::init() {
+ _vm->_gameSys->setAnimation(0, 0, 0);
+ for (int i = 0; i < 6; ++i)
+ _vm->_gameSys->setAnimation(0, 0, i + 1);
+ return 0xD4;
+}
+
+void Scene51::updateHotspots() {
+ _vm->_hotspotsCount = 0;
+}
+
+void Scene51::clearItem(Scene51Item *item) {
+ item->_currSequenceId = 0;
+ item->_droppedSequenceId = 0;
+ item->_x = 0;
+ item->_y = 0;
+ item->_x2 = 0;
+ item->_collisionX = 0;
+ item->_canCatch = false;
+}
+
+void Scene51::dropNextItem() {
+ if (_vm->_timers[0])
+ return;
+
+ int index = 0;
+ while (index < 6 && _items[index]._currSequenceId)
+ ++index;
+
+ if (index == 6)
+ return;
+
+ switch (_nextDropItemKind) {
+ case 0:
+ if (_vm->getRandom(10) != 0 || _itemsCtr2 >= 2) {
+ _items[index]._currSequenceId = 0xBD;
+ } else {
+ --_itemsCtr1;
+ _items[index]._currSequenceId = 0xBA;
+ ++_itemsCtr2;
+ }
+ break;
+
+ case 1:
+ if (_vm->getRandom(8) != 0 || _itemsCtr2 >= 2) {
+ if (_vm->getRandom(5) == 0) {
+ if (_itemInsertDirection)
+ _itemInsertX -= 70;
+ else
+ _itemInsertX += 70;
+ }
+ _items[index]._currSequenceId = 0xBD;
+ } else {
+ --_itemsCtr1;
+ _items[index]._currSequenceId = 0xBA;
+ ++_itemsCtr2;
+ }
+ break;
+
+ case 2:
+ if (_vm->getRandom(6) != 0 || _itemsCtr2 >= 2) {
+ _items[index]._currSequenceId = 0xBD;
+ } else {
+ --_itemsCtr1;
+ _items[index]._currSequenceId = 0xBA;
+ ++_itemsCtr2;
+ }
+ break;
+
+ case 3:
+ case 4:
+ if (_itemsCtr == 0)
+ _itemsCtr1 = 3;
+ _items[index]._currSequenceId = 0xC0;
+ break;
+
+ case 5:
+ case 6:
+ if (_vm->getRandom(5) != 0 || _itemsCtr2 >= 2) {
+ if (_vm->getRandom(5) != 0)
+ _items[index]._currSequenceId = 0xBD;
+ else
+ _items[index]._currSequenceId = 0xC0;
+ } else {
+ --_itemsCtr1;
+ _items[index]._currSequenceId = 0xBA;
+ ++_itemsCtr2;
+ }
+ break;
+
+ case 7:
+ if (_vm->getRandom(5) != 0 || _itemsCtr2 >= 2) {
+ if (_vm->getRandom(5) == 0) {
+ if (_itemInsertDirection)
+ _itemInsertX -= 40;
+ else
+ _itemInsertX += 40;
+ }
+ if (_vm->getRandom(9) != 0)
+ _items[index]._currSequenceId = 0xBD;
+ else
+ _items[index]._currSequenceId = 0xC0;
+ } else {
+ --_itemsCtr1;
+ _items[index]._currSequenceId = 0xBA;
+ ++_itemsCtr2;
+ }
+ break;
+
+ default:
+ if (_vm->getRandom(4) != 0 || _itemsCtr2 >= 2) {
+ if (_vm->getRandom(9) != 0)
+ _items[index]._currSequenceId = 0xBD;
+ else
+ _items[index]._currSequenceId = 0xC0;
+ } else {
+ --_itemsCtr1;
+ _items[index]._currSequenceId = 0xBA;
+ ++_itemsCtr2;
+ }
+ break;
+ }
+
+ if (_itemInsertDirection) {
+ _itemInsertX -= 73;
+ if (_itemInsertX < 129) {
+ _itemInsertX += 146;
+ _itemInsertDirection = 0;
+ }
+ } else {
+ _itemInsertX += 73;
+ if (_itemInsertX > 685) {
+ _itemInsertX -= 146;
+ _itemInsertDirection = 1;
+ }
+ }
+
+ if (_itemInsertX > 685)
+ _itemInsertX = 685;
+
+ if (_itemInsertX < 129)
+ _itemInsertX = 129;
+
+ if (_items[index]._currSequenceId == 0xBA) {
+ _items[index]._x2 = _vm->getRandom(350) + 200;
+ _items[index]._x = _items[index]._x2 - 362;
+ _items[index]._y = 15;
+ _items[index]._id = 249 - index;
+ } else {
+ _items[index]._collisionX = _itemInsertX;
+ _items[index]._x = _items[index]._collisionX - 395;
+ if (_items[index]._currSequenceId == 0xC0)
+ _items[index]._x -= 65;
+ _items[index]._id = index + 250;
+ _items[index]._canCatch = true;
+ }
+
+ _vm->_gameSys->setAnimation(_items[index]._currSequenceId, _items[index]._id, index + 1);
+ _vm->_gameSys->insertSequence(_items[index]._currSequenceId, _items[index]._id, 0, 0,
+ kSeqNone, 0, _items[index]._x, _items[index]._y);
+
+ _vm->_timers[0] = _dropSpeedTicks;
+
+ if (_nextDropItemKind >= 3)
+ _vm->_timers[0] = 20;
+
+ if (_nextDropItemKind >= 5)
+ _vm->_timers[0] = 5;
+
+ if (_nextDropItemKind == 8)
+ _vm->_timers[0] = 4;
+
+ ++_itemsCtr;
+}
+
+void Scene51::updateItemAnimations() {
+ for (int i = 0; i < 6; ++i) {
+ if (_vm->_gameSys->getAnimationStatus(i + 1) == 2)
+ updateItemAnimation(&_items[i], i);
+ }
+}
+
+int Scene51::checkCollision(int sequenceId) {
+ if (!isJumping(sequenceId))
+ return false;
+
+ bool jumpingLeft = false, jumpingRight = false;
+ int v8 = 0, v4 = 0;
+ int result = 0;
+
+ bool checkFl = false;
+ for (int i = 0; i < 6; i++)
+ checkFl |= _items[i]._isCollision;
+
+ if (!checkFl)
+ return false;
+
+ if (isJumpingRight(sequenceId)) {
+ v8 = getPosRight(sequenceId);
+ v4 = getPosRight(sequenceId + 1);
+ jumpingRight = true;
+ } else if (isJumpingLeft(sequenceId)) {
+ v4 = getPosLeft(sequenceId - 1) + 33;
+ v8 = getPosLeft(sequenceId) + 33;
+ jumpingLeft = true;
+ }
+
+ if (jumpingRight || jumpingLeft) {
+ int v5 = 0;
+ int i;
+ for (i = 0; i < 6; ++i) {
+ if (_items[i]._isCollision) {
+ if (jumpingRight && _items[i]._x2 > v8 && _items[i]._x2 < v4) {
+ v5 = v8 - 359;
+ if (v5 == 0)
+ v5 = 1;
+ _platypusNextSequenceId = 0xB6;
+ break;
+ } else if (jumpingLeft && _items[i]._x2 < v4 && _items[i]._x2 > v8) {
+ v5 = v8 - 344;
+ if (v5 == 0)
+ v5 = 1;
+ _platypusNextSequenceId = 0xB7;
+ break;
+ }
+ }
+ }
+ if (v5) {
+ _vm->_gameSys->setAnimation(0xBC, _items[i]._id, i + 1);
+ _vm->_gameSys->insertSequence(0xBC, _items[i]._id, _items[i]._currSequenceId, _items[i]._id, kSeqSyncWait, 0, _items[i]._x, 15);
+ _items[i]._isCollision = false;
+ _items[i]._currSequenceId = 0xBC;
+ --_itemsCtr2;
+ }
+ result = v5;
+ }
+
+ return result;
+}
+
+void Scene51::updateItemAnimation(Scene51Item *item, int index) {
+
+ switch (item->_currSequenceId) {
+ case 0xBD:
+ case 0xC0:
+ case 0xC1:
+ // Falling coin and banknote
+ if (!itemIsCaught(item)) {
+ if (_dropLoseCash) {
+ if (item->_currSequenceId == 0xBD)
+ _cashAmount -= 2;
+ else
+ _cashAmount -= 25;
+ if (_cashAmount < 0)
+ _cashAmount = 0;
+ updateCash(_cashAmount);
+ }
+ item->_droppedSequenceId = item->_currSequenceId + 1;
+ if (item->_currSequenceId != 0xC0) {
+ item->_canCatch = false;
+ _dropLoseCash = true;
+ _itemsCtr = 0;
+ _vm->_timers[0] = 10;
+ }
+ if (item->_droppedSequenceId) {
+ _vm->_gameSys->setAnimation(item->_droppedSequenceId, item->_id, index + 1);
+ _vm->_gameSys->insertSequence(item->_droppedSequenceId, item->_id, item->_currSequenceId, item->_id, kSeqSyncWait, 0, item->_x, item->_y);
+ item->_currSequenceId = item->_droppedSequenceId;
+ item->_y = 0;
+ }
+ } else {
+ _vm->_gameSys->removeSequence(item->_currSequenceId, item->_id, true);
+ _vm->_gameSys->setAnimation(0, 0, index + 1);
+ _vm->playSound(0xDA, false);
+ if (incCashAmount(item->_currSequenceId) == 1995) {
+ winMinigame();
+ _vm->_sceneDone = true;
+ } else {
+ clearItem(item);
+ ++_itemsCaughtCtr;
+ if (_itemsCaughtCtr == 5)
+ --_dropSpeedTicks;
+ if (_itemsCaughtCtr == 8)
+ --_dropSpeedTicks;
+ if (_itemsCaughtCtr == 11)
+ --_dropSpeedTicks;
+ if (_itemsCaughtCtr == 14)
+ --_dropSpeedTicks;
+ if (_itemsCaughtCtr >= 15 && _dropSpeedTicks > 4)
+ --_dropSpeedTicks;
+ if (_itemsCtr1 <= _itemsCaughtCtr) {
+ ++_nextDropItemKind;
+ _dropSpeedTicks = 10;
+ _itemsCtr = 0;
+ _itemsCtr1 = 20;
+ _dropLoseCash = false;
+ _itemsCaughtCtr = 0;
+ removeCollidedItems();
+ }
+ }
+ }
+ break;
+
+ case 0xBE:
+ // Fallen coin
+ item->_droppedSequenceId = item->_currSequenceId + 1;
+ if (item->_droppedSequenceId) {
+ _vm->_gameSys->setAnimation(item->_droppedSequenceId, item->_id, index + 1);
+ _vm->_gameSys->insertSequence(item->_droppedSequenceId, item->_id, item->_currSequenceId, item->_id, kSeqSyncWait, 0, item->_x, item->_y);
+ item->_currSequenceId = item->_droppedSequenceId;
+ item->_y = 0;
+ }
+ break;
+
+ case 0xBF:
+ case 0xC2:
+ // Bouncing coin and banknote
+ _vm->_gameSys->setAnimation(0, 0, index + 1);
+ _vm->_gameSys->removeSequence(item->_currSequenceId, item->_id, true);
+ clearItem(item);
+ break;
+
+ case 0xBA:
+ // Falling banana peel
+ item->_droppedSequenceId = 0xBB;
+ item->_y = 15;
+ if (item->_droppedSequenceId) {
+ _vm->_gameSys->setAnimation(item->_droppedSequenceId, item->_id, index + 1);
+ _vm->_gameSys->insertSequence(item->_droppedSequenceId, item->_id, item->_currSequenceId, item->_id, kSeqSyncWait, 0, item->_x, item->_y);
+ item->_currSequenceId = item->_droppedSequenceId;
+ item->_y = 0;
+ }
+ break;
+
+ case 0xBB:
+ item->_isCollision = true;
+ item->_droppedSequenceId = 0;
+ _vm->_gameSys->setAnimation(0, 0, index + 1);
+ break;
+
+ case 0xBC:
+ _vm->_gameSys->removeSequence(item->_currSequenceId, item->_id, true);
+ _vm->_gameSys->setAnimation(0, 0, index + 1);
+ clearItem(item);
+ break;
+
+ default:
+ if (item->_droppedSequenceId) {
+ _vm->_gameSys->setAnimation(item->_droppedSequenceId, item->_id, index + 1);
+ _vm->_gameSys->insertSequence(item->_droppedSequenceId, item->_id, item->_currSequenceId, item->_id, kSeqSyncWait, 0, item->_x, item->_y);
+ item->_currSequenceId = item->_droppedSequenceId;
+ item->_y = 0;
+ }
+ break;
+ }
+}
+
+void Scene51::removeCollidedItems() {
+ for (int i = 0; i < 6; ++i) {
+ if (_items[i]._isCollision) {
+ _vm->_gameSys->removeSequence(_items[i]._currSequenceId, _items[i]._id, true);
+ _vm->_gameSys->setAnimation(0, 0, i + 1);
+ clearItem(&_items[i]);
+ }
+ }
+ _itemsCtr2 = 0;
+}
+
+int Scene51::itemIsCaught(Scene51Item *item) {
+ if (!item->_canCatch)
+ return 0;
+
+ if (isJumpingRight(_platypusJumpSequenceId)) {
+ int v4 = getPosRight(_platypusJumpSequenceId) + 97;
+ if (item->_collisionX < v4 && v4 - item->_collisionX < 56)
+ return 1;
+ } else {
+ int v2 = getPosLeft(_platypusJumpSequenceId);
+ if (item->_collisionX > v2 && item->_collisionX - v2 < 56)
+ return 1;
+ }
+
+ if (item->_currSequenceId == 0xC1) {
+ int v3 = item->_collisionX + 100;
+ if (isJumpingRight(_platypusJumpSequenceId)) {
+ if (ABS(getPosRight(_platypusJumpSequenceId) + 46 - v3) < 56)
+ return 1;
+ } else if (ABS(getPosLeft(_platypusJumpSequenceId) + 46 - v3) < 56) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+bool Scene51::isJumpingRight(int sequenceId) {
+ return sequenceId >= 0x76 && sequenceId <= 0x95;
+}
+
+bool Scene51::isJumpingLeft(int sequenceId) {
+ return sequenceId >= 0x96 && sequenceId <= 0xB5;
+}
+
+bool Scene51::isJumping(int sequenceId) {
+ return sequenceId >= 0x76 && sequenceId <= 0xB5;
+}
+
+void Scene51::waitForAnim(int animationIndex) {
+ while (_vm->_gameSys->getAnimationStatus(animationIndex) != 2 && _vm->_gameDone) {
+ updateItemAnimations();
+ _vm->gameUpdateTick();
+ }
+}
+
+int Scene51::getPosRight(int sequenceId) {
+ static const int kRightPosTbl[] = {
+ 131, 159, 178, 195, 203, 219, 238, 254,
+ 246, 274, 293, 310, 318, 334, 353, 369,
+ 362, 390, 409, 426, 434, 450, 469, 485,
+ 477, 505, 524, 541, 549, 565, 584, 600
+ };
+
+ if (sequenceId >= 118 && sequenceId <= 149)
+ return kRightPosTbl[sequenceId - 118];
+ return -1;
+}
+
+int Scene51::getPosLeft(int sequenceId) {
+ static const int kLeftPosTbl[] = {
+ 580, 566, 550, 536, 526, 504, 488, 469,
+ 460, 446, 430, 416, 406, 384, 368, 349,
+ 342, 328, 312, 298, 288, 266, 250, 231,
+ 220, 206, 190, 176, 166, 144, 128, 109
+ };
+
+ if (sequenceId >= 150 && sequenceId <= 181)
+ return kLeftPosTbl[sequenceId - 150];
+ return -1;
+}
+
+void Scene51::playIntroAnim() {
+ int soundCtr = 0;
+
+ _platypusSequenceId = 0x76;
+ _platypusNextSequenceId = 0x76;
+
+ for (int i = 0; i < 6; ++i)
+ clearItem(&_items[i]);
+
+ _items[0]._currSequenceId = 0xBA;
+ _items[0]._x2 = 320;
+ _items[0]._x = -42;
+ _items[0]._y = 15;
+ _items[0]._id = 249;
+ _items[0]._isCollision = true;
+
+ _vm->_gameSys->insertSequence(_platypusSequenceId, 256, 0, 0, kSeqNone, 0, -179, 0);
+ _vm->_gameSys->insertSequence(0xBA, 249, 0, 0, kSeqNone, 0, _items[0]._x, _items[0]._y);
+ _vm->_gameSys->setAnimation(0xBA, 249, 1);
+ _vm->_gameSys->setAnimation(_platypusSequenceId, 256, 0);
+
+ while (_platypusSequenceId < 0x80) {
+ waitForAnim(0);
+ ++_platypusNextSequenceId;
+ _vm->_gameSys->setAnimation(_platypusNextSequenceId, 256, 0);
+ _vm->_gameSys->insertSequence(_platypusNextSequenceId, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, -179, 0);
+ _platypusSequenceId = _platypusNextSequenceId;
+ ++soundCtr;
+ if (soundCtr % 4 == 0)
+ _vm->playSound(0xD6, false);
+ }
+
+ _platypusNextSequenceId = 0x75;
+
+ while (_platypusSequenceId != 0x84) {
+ waitForAnim(0);
+ ++_platypusNextSequenceId;
+ int oldSequenceId = _platypusNextSequenceId;
+ int v0 = checkCollision(_platypusNextSequenceId);
+ _vm->_gameSys->setAnimation(_platypusNextSequenceId, 256, 0);
+ _vm->_gameSys->insertSequence(_platypusNextSequenceId, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, v0, 0);
+ _platypusSequenceId = _platypusNextSequenceId;
+ if (v0) {
+ _platypusNextSequenceId = oldSequenceId;
+ } else {
+ ++soundCtr;
+ if (soundCtr % 4 == 0)
+ _vm->playSound(0xD6, false);
+ }
+ }
+ waitForAnim(0);
+}
+
+void Scene51::updateGuyAnimation() {
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(20) + 60;
+
+ switch (_vm->getRandom(5)) {
+ case 0:
+ _guyNextSequenceId = 0xC3;
+ break;
+ case 1:
+ _guyNextSequenceId = 0xC4;
+ break;
+ case 2:
+ _guyNextSequenceId = 0xC5;
+ break;
+ case 3:
+ _guyNextSequenceId = 0xC6;
+ break;
+ case 4:
+ _guyNextSequenceId = 0xC7;
+ break;
+ }
+
+ _vm->_gameSys->insertSequence(_guyNextSequenceId, 39, _guySequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ _guySequenceId = _guyNextSequenceId;
+ _guyNextSequenceId = -1;
+ }
+}
+
+int Scene51::incCashAmount(int sequenceId) {
+ switch (sequenceId) {
+ case 0xBD:
+ _cashAmount += 10;
+ break;
+ case 0xC0:
+ case 0xC1:
+ _cashAmount += 100;
+ break;
+ case 0xB6:
+ case 0xB7:
+ _cashAmount -= 10 * _vm->getRandom(5) + 50;
+ if (_cashAmount < 0)
+ _cashAmount = 0;
+ break;
+ }
+ if (_cashAmount > 1995)
+ _cashAmount = 1995;
+ updateCash(_cashAmount);
+ return _cashAmount;
+}
+
+void Scene51::winMinigame() {
+ updateCash(1995);
+ _vm->playSound(0xDA, false);
+ _vm->delayTicksA(1, 5);
+ _vm->_newSceneNum = 48;
+ _vm->invRemove(kItemBanana);
+}
+
+void Scene51::playCashAppearAnim() {
+ _vm->_gameSys->setAnimation(0xC8, 252, 0);
+ _vm->_gameSys->insertSequence(0xC8, 252, 0, 0, kSeqNone, 0, -20, -20);
+
+ while (_vm->_gameSys->getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+}
+
+void Scene51::updateCash(int amount) {
+ drawDigit(amount / 1000, 0);
+ drawDigit(amount / 100 % 10, 1);
+ drawDigit(amount / 10 % 10, 2);
+ drawDigit(amount % 10, 3);
+}
+
+void Scene51::drawDigit(int digit, int position) {
+ if (digit != _digits[position]) {
+ _vm->_gameSys->insertSequence(kDigitSequenceIds[digit], 253 + position,
+ _digitSequenceIds[position], 253 + position,
+ kSeqSyncWait, 0, kDigitPositions[position] - 20, -20);
+ _digitSequenceIds[position] = kDigitSequenceIds[digit];
+ _digits[position] = digit;
+ }
+}
+
+void Scene51::initCashDisplay() {
+ for (int position = 0; position < 4; ++position) {
+ _digits[position] = 0;
+ _digitSequenceIds[position] = kDigitSequenceIds[0];
+ _vm->_gameSys->insertSequence(kDigitSequenceIds[0], 253 + position, 0, 0, kSeqNone, 0, kDigitPositions[position] - 20, -20);
+ }
+ _cashAmount = 0;
+}
+
+void Scene51::run() {
+ int soundCtr = 0;
+ bool isIdle = true;
+
+ _itemsCtr = 0;
+ _vm->_newSceneNum = _vm->_prevSceneNum;
+ _cashAmount = 0;
+ _platypusJumpSequenceId = 0x84;
+ _vm->endSceneInit();
+
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+
+ _guySequenceId = 0xC3;
+ _guyNextSequenceId = -1;
+
+ _vm->_gameSys->insertSequence(0xC3, 39, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_timers[4] = _vm->getRandom(20) + 60;
+
+ playCashAppearAnim();
+ initCashDisplay();
+ playIntroAnim();
+
+ _platypusNextSequenceId = 0x74;
+ _vm->_gameSys->setAnimation(0x74, 256, 0);
+ _vm->_gameSys->insertSequence(_platypusNextSequenceId, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosRight(_platypusJumpSequenceId) - 362, 0);
+ _platypusSequenceId = _platypusNextSequenceId;
+
+ _itemInsertDirection = 0;
+ _itemInsertX = 685;
+ _dropSpeedTicks = 10;
+ _nextDropItemKind = 0;
+
+ for (int i = 0; i < 6; ++i)
+ clearItem(&_items[i]);
+
+ _itemInsertX = _vm->getRandom(556) + 129;
+ _vm->_timers[0] = 15;
+
+ _itemsCaughtCtr = 0;
+ _dropLoseCash = false;
+ _itemsCtr1 = 20;
+
+ _vm->clearKeyStatus1(Common::KEYCODE_RIGHT);
+ _vm->clearKeyStatus1(Common::KEYCODE_LEFT);
+ _vm->clearKeyStatus1(Common::KEYCODE_UP);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+
+ bool isCollision = false;
+ bool startWalk = true;
+
+ while (!_vm->_sceneDone) {
+ if (clearKeyStatus())
+ _vm->_sceneDone = true;
+
+ _vm->gameUpdateTick();
+
+ updateGuyAnimation();
+ dropNextItem();
+ updateItemAnimations();
+
+ if (_vm->isKeyStatus2(Common::KEYCODE_UP) || _vm->isKeyStatus2(Common::KEYCODE_SPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_UP);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ if (isJumpingRight(_platypusJumpSequenceId)) {
+ waitForAnim(0);
+ _vm->_gameSys->setAnimation(0xB8, 256, 0);
+ _vm->_gameSys->insertSequence(0xB8, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosRight(_platypusJumpSequenceId) - 348, 0);
+ _platypusSequenceId = 0xB8;
+ waitForAnim(0);
+ _platypusNextSequenceId += 6;
+ if (_platypusNextSequenceId > 0x95)
+ _platypusNextSequenceId = 0x95;
+ _platypusJumpSequenceId = _platypusNextSequenceId;
+ } else {
+ waitForAnim(0);
+ _vm->_gameSys->setAnimation(0xB9, 256, 0);
+ _vm->_gameSys->insertSequence(0xB9, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosLeft(_platypusJumpSequenceId) - 338, 0);
+ _platypusSequenceId = 0xB9;
+ waitForAnim(0);
+ _platypusNextSequenceId += 6;
+ if (_platypusNextSequenceId > 0xB5)
+ _platypusNextSequenceId = 0xB5;
+ _platypusJumpSequenceId = _platypusNextSequenceId;
+ }
+ isIdle = false;
+ }
+
+ while (_vm->isKeyStatus2(Common::KEYCODE_RIGHT) && _platypusNextSequenceId != 0x96 && !_vm->_gameDone) {
+ if (_platypusNextSequenceId == 0xB6)
+ _platypusNextSequenceId = 0x76;
+ updateItemAnimations();
+ if (startWalk) {
+ _platypusNextSequenceId = 0x86;
+ startWalk = false;
+ }
+
+ if (_vm->_gameSys->getAnimationStatus(0) == 2) {
+ int collisionX = checkCollision(_platypusNextSequenceId);
+ if (collisionX)
+ incCashAmount(_platypusNextSequenceId);
+ _vm->_gameSys->setAnimation(_platypusNextSequenceId, 256, 0);
+ _vm->_gameSys->insertSequence(_platypusNextSequenceId, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, collisionX, 0);
+ _platypusSequenceId = _platypusNextSequenceId;
+ if (collisionX) {
+ isCollision = true;
+ ++_platypusJumpSequenceId;
+ _platypusNextSequenceId = _platypusJumpSequenceId;
+ } else {
+ _platypusJumpSequenceId = _platypusNextSequenceId;
+ }
+ if (isJumpingRight(_platypusJumpSequenceId)) {
+ ++_platypusNextSequenceId;
+ if (!isCollision) {
+ if (_vm->isKeyStatus2(Common::KEYCODE_UP) || _vm->isKeyStatus2(Common::KEYCODE_SPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_UP);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ waitForAnim(0);
+ _vm->_gameSys->setAnimation(0xB8, 256, 0);
+ _vm->_gameSys->insertSequence(0xB8, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosRight(_platypusJumpSequenceId) - 348, 0);
+ _platypusSequenceId = 0xB8;
+ waitForAnim(0);
+ _platypusNextSequenceId += 6;
+ if (_platypusNextSequenceId > 0x95)
+ _platypusNextSequenceId = 0x95;
+ _platypusJumpSequenceId = _platypusNextSequenceId;
+ } else {
+ ++soundCtr;
+ if (soundCtr % 4 == 0)
+ _vm->playSound(0xD6, false);
+ }
+ }
+ } else {
+ _platypusNextSequenceId = 150 - (_platypusJumpSequenceId - 150);
+ }
+ isCollision = false;
+ isIdle = false;
+ }
+ _vm->gameUpdateTick();
+ }
+
+ while (_vm->isKeyStatus2(Common::KEYCODE_LEFT) && _platypusNextSequenceId != 0xB6 && !_vm->_gameDone) {
+ updateItemAnimations();
+ if (startWalk) {
+ _platypusNextSequenceId = 0xA5;
+ startWalk = false;
+ }
+
+ if (_vm->_gameSys->getAnimationStatus(0) == 2) {
+ int collisionX = checkCollision(_platypusNextSequenceId);
+ if (collisionX)
+ incCashAmount(_platypusNextSequenceId);
+ _vm->_gameSys->setAnimation(_platypusNextSequenceId, 256, 0);
+ _vm->_gameSys->insertSequence(_platypusNextSequenceId, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, collisionX, 0);
+ _platypusSequenceId = _platypusNextSequenceId;
+ if (collisionX) {
+ isCollision = true;
+ ++_platypusJumpSequenceId;
+ _platypusNextSequenceId = _platypusJumpSequenceId;
+ } else {
+ _platypusJumpSequenceId = _platypusNextSequenceId;
+ }
+ if (isJumpingLeft(_platypusJumpSequenceId)) {
+ ++_platypusNextSequenceId;
+ if (!isCollision) {
+ if (_vm->isKeyStatus2(Common::KEYCODE_UP) || _vm->isKeyStatus2(Common::KEYCODE_SPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_UP);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ waitForAnim(0);
+ _vm->_gameSys->setAnimation(0xB9, 256, 0);
+ _vm->_gameSys->insertSequence(0xB9, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosLeft(_platypusJumpSequenceId) - 338, 0);
+ _platypusSequenceId = 0xB9;
+ waitForAnim(0);
+ _platypusNextSequenceId += 6;
+ if (_platypusNextSequenceId > 0xB5)
+ _platypusNextSequenceId = 0xB5;
+ _platypusJumpSequenceId = _platypusNextSequenceId;
+ } else {
+ ++soundCtr;
+ if (soundCtr % 4 == 0)
+ _vm->playSound(0xD6, false);
+ }
+ }
+ } else {
+ _platypusNextSequenceId = 182 - (_platypusJumpSequenceId - 118);
+ }
+ isCollision = false;
+ isIdle = false;
+ }
+ _vm->gameUpdateTick();
+ }
+
+ if (!isIdle && _vm->_gameSys->getAnimationStatus(0) == 2) {
+ if (isJumpingRight(_platypusJumpSequenceId)) {
+ _vm->_gameSys->setAnimation(0x74, 256, 0);
+ _vm->_gameSys->insertSequence(0x74, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosRight(_platypusJumpSequenceId) - 362, 0);
+ _platypusSequenceId = 0x74;
+ } else {
+ _vm->_gameSys->setAnimation(0x75, 256, 0);
+ _vm->_gameSys->insertSequence(0x75, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosLeft(_platypusJumpSequenceId) - 341, 0);
+ _platypusSequenceId = 0x75;
+ }
+ waitForAnim(0);
+ isIdle = true;
+ }
+ }
+
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _vm->clearKeyStatus1(Common::KEYCODE_UP);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ _vm->clearKeyStatus1(Common::KEYCODE_RIGHT);
+ _vm->clearKeyStatus1(Common::KEYCODE_LEFT);
+
+ _vm->_gameSys->setAnimation(0, 0, 0);
+ for (int i = 0; i < 6; ++i)
+ _vm->_gameSys->setAnimation(0, 0, i + 1);
+
+ _vm->showCursor();
+}
+
+/*****************************************************************************/
+
+Scene52::Scene52(GnapEngine *vm) : Scene(vm) {
+ _gameScore = 0;
+ _aliensInitialized = false;
+ _alienDirection = 0;
+ _soundToggle = false;
+ _arcadeScreenBottom = 0;
+ _shipsLeft = 0;
+ _shipPosX = 0;
+ _shipCannonPosX = 0;
+ _shipCannonPosY = 0;
+ _shipCannonFiring = false;
+ _shipCannonFired = false;
+ _shipCannonWidth = 0;
+ _shipCannonHeight = 0;
+ _shipCannonTopY = 0;
+ _shipMidX = 0;
+ _shipMidY = 0;
+ _shipFlag = false;
+ _alienSpeed = 0;
+ _alienWidth = 0;
+ _alienHeight = 0;
+ _alienLeftX = 0;
+ _alienTopY = 0;
+ _alienRowDownCtr = 0;
+ _alienWave = false;
+ _alienSingle = false;
+ _alienCounter = 0;
+ _bottomAlienFlag = false;
+ _aliensCount = 0;
+ _nextUfoSequenceId = -1;
+ _ufoSequenceId = -1;
+}
+
+int Scene52::init() {
+ initAnims();
+ return 0x2B;
+}
+
+void Scene52::updateHotspots() {
+ _vm->_hotspotsCount = 0;
+}
+
+void Scene52::update() {
+ for (int rowNum = 0; rowNum < 7 && !_vm->_gameDone; ++rowNum) {
+ _vm->gameUpdateTick();
+ if (_vm->_gameSys->getAnimationStatus(_alienRowAnims[rowNum]) == 2) {
+ updateAlienRow(rowNum);
+ rowNum = 0;
+ }
+ }
+
+ if (_liveAlienRows == 0 && !_alienSingle) {
+ _alienWave = false;
+ _vm->playSound(0x30, false);
+ ++_alienCounter;
+ if (_alienCounter != 3) {
+ _vm->_timers[0] = 50;
+ _vm->_timers[2] = 100;
+ _alienRowDownCtr = 0;
+ _alienSingle = true;
+ }
+ }
+
+ if (_alienSingle && !_vm->_timers[0]) {
+ initAliens();
+ _alienSingle = false;
+ _vm->_timers[2] = 5;
+ _alienWave = true;
+ }
+
+ if ((_alienRowDownCtr || _liveAlienRows == 0) && !_alienSingle) {
+ moveDownAlienRow();
+ _alienRowDownCtr = 0;
+ }
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_UP) || _vm->isKeyStatus1(Common::KEYCODE_SPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ _vm->clearKeyStatus1(Common::KEYCODE_UP);
+ if (!_aliensCount)
+ fireShipCannon(_shipPosX);
+ }
+
+ if (_shipCannonFiring)
+ updateShipCannon();
+
+ fireAlienCannon();
+ updateAlienCannons();
+
+ if (_aliensCount == 1) {
+ _alienWave = false;
+ _vm->_timers[3] = 20;
+ _vm->_timers[2] = 100;
+ ++_aliensCount;
+ }
+
+ if (_aliensCount && !_vm->_timers[3]) {
+ updateAliens();
+ loseShip();
+ if (_shipsLeft != 0) {
+ _vm->_timers[3] = 40;
+ while (_vm->_timers[3] && !_vm->_gameDone) {
+ updateAlienCannons();
+ if (_shipCannonFiring)
+ updateShipCannon();
+ _vm->gameUpdateTick();
+ }
+ initAliens();
+ _shipPosX = (800 - _shipMidX) / 2;
+ _vm->_gameSys->setAnimation(_nextUfoSequenceId, 256, 7);
+ _vm->_gameSys->insertSequence(_nextUfoSequenceId, 256, 0, 0, kSeqNone, 0, _shipPosX, _arcadeScreenBottom);
+ _ufoSequenceId = _nextUfoSequenceId;
+ _vm->_timers[2] = 5;
+ _alienWave = true;
+ } else {
+ _vm->_sceneDone = true;
+ }
+ }
+
+ _nextUfoSequenceId = 34;
+ if (_ufoSequenceId != 34)
+ _shipFlag = true;
+
+ if (_shipFlag) {
+ if (_vm->_gameSys->getAnimationStatus(7) == 2) {
+ _vm->_gameSys->setAnimation(_nextUfoSequenceId, 256, 7);
+ _vm->_gameSys->insertSequence(_nextUfoSequenceId, 256, _ufoSequenceId, 256, kSeqSyncWait, 0, _shipPosX, _arcadeScreenBottom);
+ _ufoSequenceId = _nextUfoSequenceId;
+ }
+ _shipFlag = false;
+ }
+
+ if (_alienWave && !_vm->_timers[0]) {
+ playSound();
+ int delay = CLIP(_alienSpeed, 2, 10);
+ _vm->_timers[0] = delay;
+ }
+}
+
+void Scene52::initShipCannon(int bottomY) {
+ _shipCannonFired = false;
+ _shipCannonWidth = MAX(_vm->_gameSys->getSpriteWidthById(14), _vm->_gameSys->getSpriteWidthById(16));
+ _shipCannonHeight = MAX(_vm->_gameSys->getSpriteHeightById(14), _vm->_gameSys->getSpriteHeightById(16));
+ _shipCannonTopY = bottomY - _shipCannonHeight;
+ _shipCannonFiring = false;
+}
+
+void Scene52::initAlienCannons() {
+ for (int i = 0; i < 3; ++i) {
+ _alienCannonIds[i] = 0;
+ _alienCannonFired[i] = 0;
+ }
+ _alienCannonSequenceIds[0] = 30;
+ _alienCannonSequenceIds[1] = 31;
+ _alienCannonSequenceIds[2] = 32;
+}
+
+void Scene52::fireShipCannon(int posX) {
+ if (_vm->_timers[1])
+ return;
+
+ int cannonNum = getFreeShipCannon();
+ if (cannonNum != -1) {
+ _shipCannonPosX = _shipMidX / 2 + posX - _shipCannonWidth / 2;
+ _shipCannonPosY = _shipCannonTopY;
+ _vm->_gameSys->setAnimation(0x23, cannonNum + 256, cannonNum + 8);
+ _vm->_gameSys->insertSequence(0x23, cannonNum + 256, 0, 0, kSeqNone, 0, _shipCannonPosX, _shipCannonPosY);
+ _vm->playSound(0x2D, false);
+ if (shipCannonHitShield(cannonNum)) {
+ _vm->_gameSys->setAnimation(0, 0, cannonNum + 8);
+ _vm->_gameSys->removeSequence(0x23, cannonNum + 256, true);
+ } else {
+ _shipCannonFired = true;
+ _shipCannonPosY -= 13;
+ _shipCannonFiring = true;
+ }
+ _vm->_timers[1] = 5;
+ }
+}
+
+void Scene52::fireAlienCannon() {
+ if (_vm->_timers[2])
+ return;
+
+ int cannonNum = getFreeAlienCannon();
+ if (cannonNum != -1) {
+ int alienX1 = _alienLeftX + _alienRowXOfs[0];
+ int alienX2 = _alienLeftX + _alienRowXOfs[0] + 5 * _alienWidth - (_alienWidth / 2 - 15);
+ _alienCannonPosX[cannonNum] = _vm->getRandom(alienX2 - alienX1) + alienX1;
+ _alienCannonPosY[cannonNum] = 104;
+ _alienCannonFired[cannonNum] = 1;
+ _vm->_gameSys->setAnimation(_alienCannonSequenceIds[cannonNum], _alienCannonIds[cannonNum] + 256, cannonNum + 9);
+ _vm->_gameSys->insertSequence(_alienCannonSequenceIds[cannonNum], _alienCannonIds[cannonNum] + 256, 0, 0,
+ kSeqNone, 0, _alienCannonPosX[cannonNum], _alienCannonPosY[cannonNum]);
+ _alienCannonPosY[cannonNum] -= 13;
+ _vm->_timers[2] = 5;
+ }
+}
+
+int Scene52::getFreeShipCannon() {
+ if (!_shipCannonFired)
+ return 0;
+ return -1;
+}
+
+int Scene52::getFreeAlienCannon() {
+ for (int i = 0; i < 3; ++i)
+ if (!_alienCannonFired[i])
+ return i;
+ return -1;
+}
+
+void Scene52::updateShipCannon() {
+ if (_shipCannonFired && _vm->_gameSys->getAnimationStatus(8) == 2) {
+ _shipCannonPosY -= 13;
+ if (_shipCannonPosY - 13 >= 135) {
+ if (updateHitAlien()) {
+ _vm->_gameSys->setAnimation(0, 0, 8);
+ _vm->_gameSys->removeSequence(35, 256, true);
+ _shipCannonFired = false;
+ drawScore(_gameScore);
+ } else {
+ _vm->_gameSys->setAnimation(35, 256, 8);
+ _vm->_gameSys->insertSequence(35, 256, 35, 256, kSeqSyncWait, 0, _shipCannonPosX, _shipCannonPosY);
+ _shipCannonPosY -= 13;
+ }
+ } else {
+ _vm->_gameSys->setAnimation(0, 0, 8);
+ _vm->_gameSys->removeSequence(35, 256, true);
+ _shipCannonFired = false;
+ }
+ }
+}
+
+void Scene52::updateAlienCannons() {
+ for (int i = 0; i < 3; ++i) {
+ if (_alienCannonFired[i] && _vm->_gameSys->getAnimationStatus(i + 9) == 2) {
+ _alienCannonPosY[i] += 13;
+ if (_shipCannonHeight + _alienCannonPosY[i] + 13 <= 550) {
+ if (alienCannonHitShip(i)) {
+ _vm->_gameSys->setAnimation(0, 0, i + 9);
+ _alienCannonFired[i] = 0;
+ shipExplode();
+ } else if (alienCannonHitShield(i)) {
+ _alienCannonFired[i] = 0;
+ } else {
+ _vm->_gameSys->insertSequence(_alienCannonSequenceIds[i], 1 - _alienCannonIds[i] + 256, 0, 0,
+ kSeqNone, 0, _alienCannonPosX[i], _alienCannonPosY[i]);
+ _vm->_gameSys->setAnimation(_alienCannonSequenceIds[i], 1 - _alienCannonIds[i] + 256, i + 9);
+ _alienCannonIds[i] = 1 - _alienCannonIds[i];
+ _alienCannonPosY[i] += 13;
+ }
+ } else {
+ _vm->_gameSys->setAnimation(0, 0, i + 9);
+ _alienCannonFired[i] = 0;
+ }
+ }
+ }
+}
+
+void Scene52::initAliens() {
+ if (!_aliensInitialized) {
+ initAlienSize();
+ _aliensInitialized = true;
+ }
+
+ _liveAlienRows = 0;
+ _alienSpeed = 0;
+ _bottomAlienFlag = false;
+ _aliensCount = 0;
+ _alienSingle = false;
+ _alienRowDownCtr = 0;
+
+ initShields();
+
+ _alienRowKind[0] = -1;
+ _alienRowKind[1] = -1;
+ _alienRowKind[2] = -1;
+ _alienRowKind[3] = -1;
+ _alienRowKind[4] = _vm->getRandom(2) != 0 ? 24 : 27;
+ _alienRowKind[5] = _vm->getRandom(2) != 0 ? 25 : 28;
+ _alienRowKind[6] = _vm->getRandom(2) != 0 ? 26 : 29;
+
+ for (int i = 0; i < 7; ++i) {
+ _alienRowAnims[i] = i;
+ _alienRowXOfs[i] = 0;
+ initAlienRowKind(i, _alienRowKind[i]);
+ insertAlienRow(i);
+ }
+}
+
+void Scene52::initAlienRowKind(int rowNum, int alienKind) {
+ for (int i = 0; i < 5; ++i)
+ _items[rowNum][i] = alienKind;
+}
+
+void Scene52::insertAlienRow(int rowNum) {
+ if (_alienRowKind[rowNum] >= 0) {
+ insertAlienRowAliens(rowNum);
+ _alienRowIds[rowNum] = 256;
+ _vm->_gameSys->setAnimation(_alienRowKind[rowNum], _alienRowIds[rowNum], _alienRowAnims[rowNum]);
+ ++_liveAlienRows;
+ }
+}
+
+void Scene52::insertAlienRowAliens(int rowNum) {
+ int xOffs = _alienLeftX;
+ int yOffs = _alienTopY - 52 * rowNum - _alienHeight + 10;
+ for (int i = 0; i < 5; ++i) {
+ if (_items[rowNum][i] >= 0) {
+ _vm->_gameSys->insertSequence(_items[rowNum][i], i + 256, 0, 0, kSeqNone, 0, xOffs, yOffs);
+ ++_alienSpeed;
+ }
+ xOffs += _alienWidth;
+ }
+}
+
+void Scene52::updateAlienRow(int rowNum) {
+ if (_alienRowKind[rowNum] != -1 && !checkAlienRow(rowNum)) {
+ updateAlienRowXOfs();
+ _alienRowIds[rowNum] = -1;
+ int xOffs = _alienLeftX + _alienRowXOfs[rowNum];
+ int yOffs = _alienTopY - 52 * rowNum - _alienHeight + 10;
+ for (int i = 0; i < 5; ++i) {
+ if (_items[rowNum][i] >= 0) {
+ _vm->_gameSys->insertSequence(_items[rowNum][i], i + 256, _items[rowNum][i], i + 256, kSeqSyncWait, 0, xOffs, yOffs);
+ if (_alienRowIds[rowNum] == -1)
+ _alienRowIds[rowNum] = i + 256;
+ } else if (_items[rowNum][i] == -2) {
+ _vm->_gameSys->removeSequence(_alienRowKind[rowNum], i + 256, true);
+ _items[rowNum][i] = -1;
+ --_alienSpeed;
+ }
+ xOffs += _alienWidth;
+ }
+ if (_alienRowIds[rowNum] == -1) {
+ _vm->_gameSys->setAnimation(0, 0, _alienRowAnims[rowNum]);
+ // MessageBoxA(0, "No live aliens!", "Error 3:", 0x30u);
+ } else {
+ _vm->_gameSys->setAnimation(_alienRowKind[rowNum], _alienRowIds[rowNum], _alienRowAnims[rowNum]);
+ }
+ if (rowNum == 1) {
+ for (int j = 0; j < 3; ++j) {
+ if (_shieldSpriteIds[j] != -1) {
+ _vm->_gameSys->fillSurface(nullptr, _shieldPosX[j], _arcadeScreenBottom - 44, 33, 44, 0, 0, 0);
+ _shieldSpriteIds[j] = -1;
+ }
+ }
+ }
+ if (rowNum == 0 && _bottomAlienFlag)
+ shipExplode();
+ }
+}
+
+void Scene52::moveDownAlienRow() {
+ int v2[5], v3, v1, v0, v4;
+
+ for (int i = 0; i < 5; ++i)
+ v2[i] = _items[0][i];
+
+ v3 = _alienRowIds[0];
+ v1 = _alienRowAnims[0];
+ v0 = _alienRowKind[0];
+ v4 = _alienRowXOfs[0];
+
+ for (int j = 0; j < 7; ++j) {
+ for (int i = 0; i < 5; ++i)
+ _items[j][i] = _items[j + 1][i];
+ _alienRowIds[j] = _alienRowIds[j + 1];
+ _alienRowAnims[j] = _alienRowAnims[j + 1];
+ _alienRowKind[j] = _alienRowKind[j + 1];
+ _alienRowXOfs[j] = _alienRowXOfs[j + 1];
+ }
+
+ for (int i = 0; i < 5; ++i)
+ _items[6][i] = v2[i];
+
+ _alienRowIds[6] = v3;
+ _alienRowAnims[6] = v1;
+ _alienRowKind[6] = v0;
+ _alienRowXOfs[6] = v4;
+
+ updateAlien(6);
+ initAlienRowKind(6, _alienRowKind[6]);
+ insertAlienRow(6);
+
+ _bottomAlienFlag = _alienRowKind[0] > -1;
+}
+
+int Scene52::updateHitAlien() {
+ int result = 0, rowNum, ya;
+
+ int y = _shipCannonTopY - _shipCannonPosY;
+
+ if (y == 26) {
+ rowNum = 1;
+ ya = _shipCannonPosY + 26;
+ } else {
+ if (y % 52)
+ return 0;
+ rowNum = y / 52 + 1;
+ ya = _shipCannonPosY;
+ }
+
+ if (rowNum < 7) {
+ int hitAlienNum = getHitAlienNum(rowNum);
+ if (hitAlienNum != -1 && _items[rowNum][hitAlienNum] >= 0) {
+ _gameScore = ((_items[rowNum][hitAlienNum] - 24) % 3 + _gameScore + 1) % 1000;
+ _items[rowNum][hitAlienNum] = -2;
+ _vm->playSound(0x2C, false);
+ _vm->_gameSys->insertSequence(0x21, 266, 0, 0,
+ kSeqNone, 0, _alienLeftX + hitAlienNum * _alienWidth + _alienRowXOfs[rowNum] - 10, ya - _alienHeight);
+ result = 1;
+ }
+ }
+
+ return result;
+}
+
+int Scene52::getHitAlienNum(int rowNum) {
+ int result = -1;
+
+ int v3 = _alienLeftX + _alienRowXOfs[rowNum];
+
+ if (_shipCannonPosX >= v3) {
+ int v8 = _alienWidth / 2 - 15;
+ if (v3 + 5 * _alienWidth - v8 >= _shipCannonPosX) {
+ int v4 = v3 + _alienWidth;
+ if (_shipCannonPosX >= v4 - v8) {
+ int v5 = v4 + _alienWidth;
+ if (_shipCannonPosX >= v5 - v8) {
+ int v6 = v5 + _alienWidth;
+ if (_shipCannonPosX >= v6 - v8) {
+ int v7 = v6 + _alienWidth;
+ if (_shipCannonPosX >= v7 - v8) {
+ if (_shipCannonPosX >= v7 + _alienWidth - v8)
+ result = -1;
+ else
+ result = 4;
+ } else {
+ result = 3;
+ }
+ } else {
+ result = 2;
+ }
+ } else {
+ result = 1;
+ }
+ } else {
+ result = 0;
+ }
+ } else {
+ result = -1;
+ }
+ } else {
+ result = -1;
+ }
+ return result;
+}
+
+int Scene52::alienCannonHitShip(int cannonNum) {
+ int result = 0;
+
+ if (_aliensCount) {
+ result = 0;
+ } else {
+ int cannonY = _alienCannonPosY[cannonNum] - 13;
+ if (_arcadeScreenBottom <= cannonY) {
+ if (_shipMidY + _arcadeScreenBottom > cannonY) {
+ if (_alienCannonPosX[cannonNum] >= _shipPosX)
+ result = _alienCannonPosX[cannonNum] < _shipMidX + _shipPosX;
+ else
+ result = 0;
+ } else {
+ result = 0;
+ }
+ } else {
+ result = 0;
+ }
+ }
+ return result;
+}
+
+int Scene52::alienCannonHitShield(int cannonNum) {
+ int result = 0;
+
+ int v3 = _alienCannonPosY[cannonNum] + 39;
+ if (_arcadeScreenBottom - 44 > v3)
+ return 0;
+
+ if (_arcadeScreenBottom <= v3)
+ return 0;
+
+ if (_alienCannonPosX[cannonNum] < _shieldPosX[0])
+ return 0;
+
+ if (_alienCannonPosX[cannonNum] > _shieldPosX[2] + 33)
+ return 0;
+
+ int shieldNum = -1;
+ if (_alienCannonPosX[cannonNum] < _shieldPosX[0] + 33)
+ shieldNum = 0;
+
+ if (shieldNum < 0 && _alienCannonPosX[cannonNum] < _shieldPosX[1])
+ return 0;
+
+ if (shieldNum < 0 && _alienCannonPosX[cannonNum] < _shieldPosX[1] + 33)
+ shieldNum = 1;
+
+ if (shieldNum < 0) {
+ if (_alienCannonPosX[cannonNum] < _shieldPosX[2])
+ return 0;
+ shieldNum = 2;
+ }
+
+ if (_shieldSpriteIds[shieldNum] == -1) {
+ result = 0;
+ } else {
+ ++_shieldSpriteIds[shieldNum];
+ if (_shieldSpriteIds[shieldNum] <= 21) {
+ _vm->_gameSys->drawSpriteToBackground(_shieldPosX[shieldNum], _arcadeScreenBottom - 44, _shieldSpriteIds[shieldNum]);
+ } else {
+ _vm->_gameSys->fillSurface(nullptr, _shieldPosX[shieldNum], _arcadeScreenBottom - 44, 33, 44, 0, 0, 0);
+ _shieldSpriteIds[shieldNum] = -1;
+ }
+ _vm->_gameSys->setAnimation(0, 0, cannonNum + 9);
+ _vm->_gameSys->insertSequence(0x21, shieldNum + 257, 0, 0, kSeqNone, 0, _alienCannonPosX[cannonNum] - 18, _arcadeScreenBottom - 44);
+ _vm->playSound(0x2C, false);
+ result = 1;
+ }
+
+ return result;
+}
+
+bool Scene52::shipCannonHitShield(int cannonNum) {
+ bool result = false;
+
+ if (_shipCannonPosX < _shieldPosX[0])
+ return result;
+
+ if (_shipCannonPosX > _shieldPosX[2] + 33)
+ return result;
+
+ int shieldNum = -1;
+ if (_shipCannonPosX < _shieldPosX[0] + 33)
+ shieldNum = 0;
+
+ if (shieldNum < 0 && _shipCannonPosX < _shieldPosX[1])
+ return result;
+
+ if (shieldNum < 0 && _shipCannonPosX < _shieldPosX[1] + 33)
+ shieldNum = 1;
+
+ if (shieldNum < 0) {
+ if (_shipCannonPosX < _shieldPosX[2])
+ return result;
+ shieldNum = 2;
+ }
+
+ if (_shieldSpriteIds[shieldNum] == -1) {
+ result = false;
+ } else {
+ ++_shieldSpriteIds[shieldNum];
+ if (_shieldSpriteIds[shieldNum] <= 21) {
+ _vm->_gameSys->drawSpriteToBackground(_shieldPosX[shieldNum], _arcadeScreenBottom - 44, _shieldSpriteIds[shieldNum]);
+ } else {
+ _vm->_gameSys->fillSurface(nullptr, _shieldPosX[shieldNum], _arcadeScreenBottom - 44, 33, 44, 0, 0, 0);
+ _shieldSpriteIds[shieldNum] = -1;
+ }
+ _vm->_gameSys->insertSequence(0x21, shieldNum + 257, 0, 0, kSeqNone, 0, _shipCannonPosX - 18, _arcadeScreenBottom - 44);
+ _vm->playSound(0x2C, false);
+ result = true;
+ }
+
+ return result;
+}
+
+bool Scene52::shipCannonHitAlien() {
+ bool result = false;
+
+ if (_aliensCount || checkAlienRow(0))
+ return false;
+
+ int alienNextX = _alienLeftX + _alienRowXOfs[0];
+ if (_shipMidX + _shipPosX >= alienNextX) {
+ int startX = _alienWidth / 2 - 15;
+ if (alienNextX + 5 * _alienWidth - startX >= _shipPosX) {
+ int alienNextDeltaX = alienNextX + _alienWidth;
+ if (_items[0][0] <= -1 || alienNextDeltaX - startX <= _shipPosX) {
+ alienNextDeltaX += _alienWidth;
+ if (_items[0][1] <= -1 || alienNextDeltaX - startX <= _shipPosX) {
+ alienNextDeltaX += _alienWidth;
+ if (_items[0][2] <= -1 || alienNextDeltaX - startX <= _shipPosX) {
+ alienNextDeltaX += _alienWidth;
+ if (_items[0][3] <= -1 || alienNextDeltaX - startX <= _shipPosX) {
+ alienNextDeltaX += _alienWidth;
+ result = _items[0][4] > -1 && alienNextDeltaX - startX > _shipPosX;
+ } else {
+ result = true;
+ }
+ } else {
+ result = true;
+ }
+ } else {
+ result = true;
+ }
+ } else {
+ result = true;
+ }
+ } else {
+ result = false;
+ }
+ } else {
+ result = false;
+ }
+
+ return result;
+}
+
+void Scene52::shipExplode() {
+ if (!_aliensCount) {
+ _vm->_gameSys->setAnimation(0, 0, 7);
+ _vm->_gameSys->removeSequence(_ufoSequenceId, 256, true);
+ _vm->playSound(0x2C, false);
+ _vm->_gameSys->insertSequence(0x21, 266, 0, 0, kSeqNone, 0, _shipPosX, _arcadeScreenBottom);
+ _aliensCount = 1;
+ _vm->playSound(0x31, false);
+ }
+}
+
+bool Scene52::checkAlienRow(int rowNum) {
+ for (int i = 0; i < 5; ++i) {
+ if (_items[rowNum][i] >= 0)
+ return false;
+ }
+
+ bool found = false;
+ for (int j = 0; j < 5; ++j)
+ if (_items[rowNum][j] == -2) {
+ _vm->_gameSys->removeSequence(_alienRowKind[rowNum], j + 256, true);
+ _items[rowNum][j] = -1;
+ --_alienSpeed;
+ found = true;
+ }
+
+ if (found) {
+ _vm->_gameSys->setAnimation(0, 0, _alienRowAnims[rowNum]);
+ --_liveAlienRows;
+ }
+
+ if (_liveAlienRows < 0)
+ _liveAlienRows = 0;
+
+ return true;
+}
+
+void Scene52::updateAlienRowXOfs() {
+ int amount = 2 * (3 - _liveAlienRows) + 1;
+
+ if (_alienSpeed == 2)
+ amount *= 4;
+ else if (_alienSpeed == 1)
+ amount *= 10;
+
+ if (_alienDirection) {
+ for (int i = 0; i < 7; ++i) {
+ _alienRowXOfs[i] -= amount;
+ if (_alienRowXOfs[i] <= -100) {
+ _alienRowXOfs[i] = -100;
+ _alienDirection = 0;
+ ++_alienRowDownCtr;
+ }
+ }
+ } else {
+ for (int j = 0; j < 7; ++j) {
+ _alienRowXOfs[j] += amount;
+ if (_alienRowXOfs[j] >= 100) {
+ _alienRowXOfs[j] = 100;
+ _alienDirection = 1;
+ ++_alienRowDownCtr;
+ }
+ }
+ }
+}
+
+void Scene52::initAlienSize() {
+ _alienWidth = _vm->_gameSys->getSpriteWidthById(0);
+ if (_vm->_gameSys->getSpriteWidthById(1) > _alienWidth)
+ _alienWidth = _vm->_gameSys->getSpriteWidthById(1);
+ if (_vm->_gameSys->getSpriteWidthById(4) > _alienWidth)
+ _alienWidth = _vm->_gameSys->getSpriteWidthById(4);
+ if (_vm->_gameSys->getSpriteWidthById(5) > _alienWidth)
+ _alienWidth = _vm->_gameSys->getSpriteWidthById(5);
+ if (_vm->_gameSys->getSpriteWidthById(12) > _alienWidth)
+ _alienWidth = _vm->_gameSys->getSpriteWidthById(12);
+ if (_vm->_gameSys->getSpriteWidthById(13) > _alienWidth)
+ _alienWidth = _vm->_gameSys->getSpriteWidthById(13);
+
+ _alienHeight = _vm->_gameSys->getSpriteHeightById(0);
+ if (_vm->_gameSys->getSpriteHeightById(1) > _alienHeight)
+ _alienHeight = _vm->_gameSys->getSpriteHeightById(1);
+ if (_vm->_gameSys->getSpriteHeightById(4) > _alienHeight)
+ _alienHeight = _vm->_gameSys->getSpriteHeightById(4);
+ if (_vm->_gameSys->getSpriteHeightById(5) > _alienHeight)
+ _alienHeight = _vm->_gameSys->getSpriteHeightById(5);
+ if (_vm->_gameSys->getSpriteHeightById(12) > _alienHeight)
+ _alienHeight = _vm->_gameSys->getSpriteHeightById(12);
+ if (_vm->_gameSys->getSpriteHeightById(13) > _alienHeight)
+ _alienHeight = _vm->_gameSys->getSpriteHeightById(13);
+
+ _alienTopY = _shipCannonTopY + 52;
+ _alienLeftX = (800 - 5 * _alienWidth) / 2;
+}
+
+void Scene52::playSound() {
+ if (_soundToggle) {
+ _vm->playSound(0x2F, false);
+ _soundToggle = false;
+ } else {
+ _vm->playSound(0x2E, false);
+ _soundToggle = true;
+ }
+}
+
+void Scene52::updateAliens() {
+ for (int i = 0; i < 7; ++i)
+ updateAlien(i);
+}
+
+void Scene52::updateAlien(int rowNum) {
+ if (_alienRowKind[rowNum] >= 0 && !checkAlienRow(rowNum)) {
+ for (int i = 0; i < 5; ++i) {
+ if (_items[rowNum][i] >= 0)
+ _items[rowNum][i] = -2;
+ }
+ checkAlienRow(rowNum);
+ }
+}
+
+void Scene52::loseShip() {
+ --_shipsLeft;
+ if (_shipsLeft == 2) {
+ _vm->_gameSys->fillSurface(nullptr, 120, 140, _shipMidX, _shipMidY, 0, 0, 0);
+ } else if (_shipsLeft == 1) {
+ _vm->_gameSys->fillSurface(nullptr, 120, 185, _shipMidX, _shipMidY, 0, 0, 0);
+ }
+}
+
+void Scene52::initShields() {
+ for (int i = 0; i < 3; ++i) {
+ _vm->_gameSys->drawSpriteToBackground(_shieldPosX[i], _arcadeScreenBottom - 44, 17);
+ _shieldSpriteIds[i] = 17;
+ }
+}
+
+void Scene52::initAnims() {
+ for (int i = 0; i < 7; ++i)
+ _vm->_gameSys->setAnimation(0, 0, i);
+ _vm->_gameSys->setAnimation(0, 0, 7);
+ for (int j = 0; j < 1; ++j)
+ _vm->_gameSys->setAnimation(0, 0, j + 8);
+ for (int k = 0; k < 3; ++k)
+ _vm->_gameSys->setAnimation(0, 0, k + 9);
+}
+
+void Scene52::drawScore(int score) {
+ char str[4];
+ sprintf(str, "%03d", score);
+ _vm->_gameSys->fillSurface(nullptr, 420, 80, 48, 30, 0, 0, 0);
+ _vm->_gameSys->drawTextToSurface(nullptr, 420, 80, 255, 255, 255, str);
+}
+
+void Scene52::run() {
+ _vm->_timers[1] = 0;
+
+ _vm->hideCursor();
+
+ _gameScore = 0;
+ _vm->_gameSys->drawTextToSurface(nullptr, 300, 80, 255, 255, 255, "SCORE");
+ _vm->_gameSys->drawTextToSurface(nullptr, 468, 80, 255, 255, 255, "0");
+
+ drawScore(0);
+
+ _shipMidX = 33;
+ _shipMidY = _vm->_gameSys->getSpriteHeightById(15);
+ _shipPosX = (800 - _shipMidX) / 2;
+ _arcadeScreenBottom = 496;
+ _arcadeScreenRight = 595 - _shipMidX;
+ _arcadeScreenLeft = 210;
+ _shipsLeft = 3;
+ _alienCounter = 0;
+
+ _shieldPosX[0] = 247;
+ _shieldPosX[1] = 387;
+ _shieldPosX[2] = 525;
+
+ for (int i = 0; i < 3; ++i)
+ _shieldSpriteIds[i] = -1;
+
+ _vm->_gameSys->drawSpriteToBackground(120, 140, 0xF);
+ _vm->_gameSys->drawSpriteToBackground(120, 185, 0xF);
+
+ initShipCannon(_arcadeScreenBottom);
+ initAlienCannons();
+ initAliens();
+
+ _nextUfoSequenceId = 0x22;
+ _vm->_gameSys->setAnimation(0x22, 256, 7);
+ _vm->_gameSys->insertSequence(_nextUfoSequenceId, 256, 0, 0, kSeqNone, 0, _shipPosX, _arcadeScreenBottom);
+
+ _ufoSequenceId = _nextUfoSequenceId;
+
+ _vm->clearKeyStatus1(Common::KEYCODE_RIGHT);
+ _vm->clearKeyStatus1(Common::KEYCODE_LEFT);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ _vm->clearKeyStatus1(Common::KEYCODE_UP);
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+
+ _vm->_timers[2] = 5;
+ _shipFlag = false;
+
+ _vm->_timers[0] = 10;
+ _alienWave = true;
+
+ while (!_vm->_sceneDone) {
+ _vm->gameUpdateTick();
+
+ while (_vm->isKeyStatus2(Common::KEYCODE_RIGHT)) {
+ update();
+ if (_vm->_gameSys->getAnimationStatus(7) == 2) {
+ if (_shipPosX < _arcadeScreenRight) {
+ _shipPosX += 15;
+ if (_shipPosX > _arcadeScreenRight)
+ _shipPosX = _arcadeScreenRight;
+ _vm->_gameSys->setAnimation(_nextUfoSequenceId, 256, 7);
+ _vm->_gameSys->insertSequence(_nextUfoSequenceId, 256, _ufoSequenceId, 256, kSeqSyncWait, 0, _shipPosX, _arcadeScreenBottom);
+ _ufoSequenceId = _nextUfoSequenceId;
+ if (_bottomAlienFlag && shipCannonHitAlien())
+ shipExplode();
+ }
+ break;
+ }
+ }
+
+ while (_vm->isKeyStatus2(Common::KEYCODE_LEFT)) {
+ update();
+ if (_vm->_gameSys->getAnimationStatus(7) == 2) {
+ if (_shipPosX > _arcadeScreenLeft) {
+ _shipPosX -= 15;
+ if (_shipPosX < _arcadeScreenLeft)
+ _shipPosX = _arcadeScreenLeft;
+ _vm->_gameSys->setAnimation(_nextUfoSequenceId, 256, 7);
+ _vm->_gameSys->insertSequence(_nextUfoSequenceId, 256, _ufoSequenceId, 256, kSeqSyncWait, 0, _shipPosX, _arcadeScreenBottom);
+ _ufoSequenceId = _nextUfoSequenceId;
+ if (_bottomAlienFlag && shipCannonHitAlien())
+ shipExplode();
+ }
+ break;
+ }
+ }
+
+ update();
+
+ if (clearKeyStatus()) {
+ _alienWave = false;
+ _vm->_gameSys->waitForUpdate();
+ initAnims();
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ _vm->_sceneDone = true;
+ }
+ }
+ _vm->_gameSys->waitForUpdate();
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/arcade.h b/engines/gnap/scenes/arcade.h
new file mode 100644
index 0000000000..e472e00508
--- /dev/null
+++ b/engines/gnap/scenes/arcade.h
@@ -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.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 GNAP_ARCADE_H
+#define GNAP_ARCADE_H
+
+#include "gnap/debugger.h"
+
+namespace Gnap {
+
+class GnapEngine;
+class CutScene;
+
+struct Scene49Obstacle {
+ int _currSequenceId;
+ int _closerSequenceId;
+ int _passedSequenceId;
+ int _splashSequenceId;
+ int _collisionSequenceId;
+ int _prevId;
+ int _currId;
+ int _laneNum;
+};
+
+struct ObstacleDef {
+ int _sequenceId;
+ int _ticks;
+};
+
+class Scene49: public Scene {
+public:
+ Scene49(GnapEngine *vm);
+ ~Scene49() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _scoreBarPos;
+ int _scoreLevel;
+ bool _scoreBarFlash;
+ int _obstacleIndex;
+ Scene49Obstacle _obstacles[5];
+ int _truckSequenceId;
+ int _truckId;
+ int _truckLaneNum;
+
+ void checkObstacles();
+ void updateObstacle(int id);
+ void increaseScore(int amount);
+ void decreaseScore(int amount);
+ void refreshScoreBar();
+ void clearObstacle(int index);
+};
+
+/*****************************************************************************/
+
+class Scene50: public Scene {
+public:
+ Scene50(GnapEngine *vm);
+ ~Scene50() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ bool _fightDone;
+ int _timesPlayed;
+ int _timesPlayedModifier;
+ int _attackCounter;
+ int _roundNum;
+ int _timeRemaining;
+ int _leftTongueRoundsWon;
+ int _rightTongueRoundsWon;
+ int _leftTongueEnergyBarPos;
+ int _rightTongueEnergyBarPos;
+ int _leftTongueSequenceId;
+ int _leftTongueId;
+ int _leftTongueNextSequenceId;
+ int _leftTongueNextId;
+ int _leftTongueNextIdCtr;
+ int _rightTongueSequenceId;
+ int _rightTongueId;
+ int _rightTongueNextSequenceId;
+ int _rightTongueNextId;
+ int _rightTongueNextIdCtr;
+ int _leftTongueEnergy;
+ int _rightTongueEnergy;
+
+ bool tongueWinsRound(int tongueNum);
+ void playWinAnim(int tongueNum, bool fightOver);
+ void delayTicks();
+ void initRound();
+ bool updateCountdown();
+ void drawCountdown(int value);
+ void playTonguesIdle();
+ void playRoundAnim(int roundNum);
+ bool updateEnergyBars(int newLeftBarPos, int newRightBarPos);
+ void waitForAnim(int animationIndex);
+ int checkInput();
+ int getRightTongueAction();
+ int getRightTongueActionTicks();
+ int getLeftTongueNextId();
+ int getRightTongueNextId();
+ void playWinBadgeAnim(int tongueNum);
+};
+
+/*****************************************************************************/
+
+struct Scene51Item {
+ int _currSequenceId;
+ int _droppedSequenceId;
+ int _x, _y;
+ int _collisionX;
+ bool _canCatch;
+ bool _isCollision;
+ int _x2;
+ int _id;
+};
+
+class Scene51: public Scene {
+public:
+ Scene51(GnapEngine *vm);
+ ~Scene51() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations() {};
+ virtual void updateAnimationsCb() {};
+
+private:
+ bool _dropLoseCash;
+
+ int _cashAmount;
+ int _digits[4];
+ int _digitSequenceIds[4];
+ int _guySequenceId;
+ int _guyNextSequenceId;
+ int _itemsCaughtCtr;
+ int _dropSpeedTicks;
+ int _nextDropItemKind;
+ int _itemInsertX;
+ int _itemInsertDirection;
+ int _platypusSequenceId;
+ int _platypusNextSequenceId;
+ int _platypusJumpSequenceId;
+ int _itemsCtr;
+ int _itemsCtr1;
+ int _itemsCtr2;
+
+ Scene51Item _items[6];
+
+ void clearItem(Scene51Item *item);
+ void dropNextItem();
+ void updateItemAnimations();
+ int checkCollision(int sequenceId);
+ void updateItemAnimation(Scene51Item *item, int index);
+ void removeCollidedItems();
+ int itemIsCaught(Scene51Item *item);
+ bool isJumpingRight(int sequenceId);
+ bool isJumpingLeft(int sequenceId);
+ bool isJumping(int sequenceId);
+ void waitForAnim(int animationIndex);
+ int getPosRight(int sequenceId);
+ int getPosLeft(int sequenceId);
+ void playIntroAnim();
+ void updateGuyAnimation();
+ int incCashAmount(int sequenceId);
+ void winMinigame();
+ void playCashAppearAnim();
+ void updateCash(int amount);
+ void drawDigit(int digit, int position);
+ void initCashDisplay();
+};
+
+/*****************************************************************************/
+
+class Scene52: public Scene {
+public:
+ Scene52(GnapEngine *vm);
+ ~Scene52() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations() {};
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _liveAlienRows;
+ int _gameScore;
+ bool _soundToggle;
+ int _arcadeScreenLeft;
+ int _arcadeScreenRight;
+ int _arcadeScreenBottom;
+ int _shipsLeft;
+ int _shieldSpriteIds[3];
+ int _shieldPosX[3];
+ int _shipPosX;
+ int _shipCannonPosX, _shipCannonPosY;
+ bool _shipCannonFiring;
+ bool _shipCannonFired;
+ int _shipCannonWidth, _shipCannonHeight;
+ int _shipCannonTopY;
+ int _shipMidX, _shipMidY;
+ bool _shipFlag;
+ bool _aliensInitialized;
+ int _alienSpeed, _alienDirection;
+ int _alienWidth, _alienHeight;
+ int _alienLeftX, _alienTopY;
+ int _alienRowDownCtr;
+ int _alienRowKind[8];
+ int _alienRowAnims[8];
+ int _alienRowIds[8];
+ int _alienRowXOfs[8];
+ int _alienCannonFired[3];
+ int _alienCannonPosX[3];
+ int _alienCannonPosY[3];
+ int _alienCannonSequenceIds[3];
+ int _alienCannonIds[3];
+ bool _alienWave, _alienSingle;
+ int _alienCounter;
+ bool _bottomAlienFlag;
+ int _aliensCount;
+ int _items[8][5];
+ int _nextUfoSequenceId, _ufoSequenceId;
+
+ void update();
+ void initShipCannon(int bottomY);
+ void initAlienCannons();
+ void fireShipCannon(int posX);
+ void fireAlienCannon();
+ int getFreeShipCannon();
+ int getFreeAlienCannon();
+ void updateShipCannon();
+ void updateAlienCannons();
+ void initAliens();
+ void initAlienRowKind(int rowNum, int alienKind);
+ void insertAlienRow(int rowNum);
+ void insertAlienRowAliens(int rowNum);
+ void updateAlienRow(int rowNum);
+ void moveDownAlienRow();
+ int updateHitAlien();
+ int getHitAlienNum(int rowNum);
+ int alienCannonHitShip(int cannonNum);
+ int alienCannonHitShield(int cannonNum);
+ bool shipCannonHitShield(int cannonNum);
+ bool shipCannonHitAlien();
+ void shipExplode();
+ bool checkAlienRow(int rowNum);
+ void updateAlienRowXOfs();
+ void initAlienSize();
+ void playSound();
+ void updateAliens();
+ void updateAlien(int rowNum);
+ void loseShip();
+ void initShields();
+ void initAnims();
+ void drawScore(int score);
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_ARCADE_H
diff --git a/engines/gnap/scenes/group0.cpp b/engines/gnap/scenes/group0.cpp
new file mode 100644
index 0000000000..b2351b08ad
--- /dev/null
+++ b/engines/gnap/scenes/group0.cpp
@@ -0,0 +1,3570 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 "gnap/gnap.h"
+#include "gnap/character.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/group0.h"
+
+namespace Gnap {
+
+Scene01::Scene01(GnapEngine *vm) : Scene(vm) {
+ _pigsIdCtr = 0;
+ _smokeIdCtr = 0;
+ _spaceshipSurface = nullptr;
+}
+
+Scene01::~Scene01() {
+ delete _spaceshipSurface;
+}
+
+int Scene01::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 3);
+ return 0x88;
+}
+
+void Scene01::updateHotspots() {
+ _vm->setHotspot(kHS01Platypus, 0, 0, 0, 0, SF_DISABLED | SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS01ExitTruck, 780, 226, 800, 455, SF_EXIT_R_CURSOR | SF_WALKABLE, 10, 6);
+ _vm->setHotspot(kHS01Mud, 138, 282, 204, 318, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 5);
+ _vm->setHotspot(kHS01Pigs, 408, 234, 578, 326, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 4);
+ _vm->setHotspot(kHS01Spaceship, 0, 200, 94, 292, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 6);
+ _vm->setHotspot(kHS01WalkArea1, 0, 0, 162, 426);
+ _vm->setHotspot(kHS01WalkArea2, 162, 0, 237, 396);
+ _vm->setHotspot(kHS01WalkArea3, 237, 0, 319, 363);
+ _vm->setHotspot(kHS01WalkArea4, 520, 0, 800, 404);
+ _vm->setHotspot(kHS01WalkArea5, 300, 447, 800, 600);
+ _vm->setHotspot(kHS01WalkArea6, 678, 0, 800, 404);
+ _vm->setHotspot(kHS01WalkArea7, 0, 0, 520, 351);
+ _vm->setHotspot(kHS01WalkArea8, 0, 546, 300, 600);
+ _vm->setDeviceHotspot(kHS01Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS01Platypus]._flags = SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ if (_vm->isFlag(kGFMudTaken))
+ _vm->_hotspots[kHS01Mud]._flags = SF_WALKABLE | SF_DISABLED;
+ _vm->_hotspotsCount = 14;
+}
+
+void Scene01::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1091C, true);
+ _vm->startSoundTimerC(5);
+
+ gameSys.setAnimation(134, 20, 4);
+ gameSys.insertSequence(134, 20, 0, 0, kSeqNone, 0, 0, 0);
+
+ gameSys.setAnimation(0x7F, 40, 2);
+ gameSys.insertSequence(0x7F, 40, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+
+ if (!_vm->isFlag(kGFMudTaken))
+ gameSys.insertSequence(129, 40, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->_prevSceneNum == 2) {
+ gnap.initPos(11, 6, kDirBottomLeft);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(12, 6, kDirIdleRight);
+ _vm->endSceneInit();
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(Common::Point(9, 6), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(8, 6), -1, 0x107B9, 1);
+ } else {
+ gnap.initPos(1, 6, kDirBottomRight);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(1, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+ _vm->testWalk(0, 3, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS01Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS01Platypus:
+ if (gnap._actionStatus < 0 && _vm->isFlag(kGFPlatypus)) {
+ if (_vm->_grabCursorSpriteIndex == kItemDisguise) {
+ gnap.useDisguiseOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFKeysTaken))
+ gnap.playMoan1(plat._pos);
+ else
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS01Spaceship:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[4], 0, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1))
+ gnap._actionStatus = kAS01LookSpaceship;
+ break;
+ case GRAB_CURSOR:
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS01Mud:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[2], 2, 3);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(3, 3));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 3)) | 0x10000, 1);
+ gnap._actionStatus = kAS01TakeMud;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS01Pigs:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[3], 7, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(7, 2)) | 0x10000, 1);
+ gnap._actionStatus = kAS01LookPigs;
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(7, 2)) | 0x10000, 1);
+ gnap._actionStatus = kAS01UsePigs;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(7, 2)) | 0x10000, 1);
+ gnap._actionStatus = kAS01LookPigs;
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS01ExitTruck:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[1], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS01LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[1] + Common::Point(0, 1), -1, 0x107CD, 1);
+ _vm->_newSceneNum = 2;
+ }
+ break;
+
+ case kHS01WalkArea1:
+ case kHS01WalkArea2:
+ case kHS01WalkArea3:
+ case kHS01WalkArea4:
+ case kHS01WalkArea5:
+ case kHS01WalkArea6:
+ case kHS01WalkArea7:
+ case kHS01WalkArea8:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1091C))
+ _vm->playSound(0x1091C, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0 && _vm->isFlag(kGFPlatypus))
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (_vm->_timers[4] == 0) {
+ // Update bird animation
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+ if (_vm->getRandom(1) == 0)
+ gameSys.insertSequence(0x84, 180, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x83, 180, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ _vm->playSoundC();
+ }
+
+ _vm->checkGameKeys();
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene01::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS01LookSpaceship:
+ _spaceshipSurface = gameSys.createSurface(47);
+ gameSys.insertSpriteDrawItem(_spaceshipSurface, 0, 0, 255);
+ gameSys.setAnimation(133, 256, 0);
+ gameSys.insertSequence(133, 256, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._actionStatus = kAS01LookSpaceshipDone;
+ break;
+
+ case kAS01LookSpaceshipDone:
+ gameSys.removeSequence(133, 256, true);
+ gameSys.removeSpriteDrawItem(_spaceshipSurface, 255);
+ _vm->deleteSurface(&_spaceshipSurface);
+ gnap._actionStatus = -1;
+ break;
+
+ case kAS01LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+
+ case kAS01TakeMud:
+ gnap.playPullOutDevice(Common::Point(2, 3));
+ gnap.playUseDevice();
+ gameSys.insertSequence(128, 40, 129, 40, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(128, 40, 3);
+ gnap._actionStatus = -1;
+ break;
+
+ case kAS01LookPigs:
+ _vm->playSound(0x8A, false);
+ _vm->playSound(0x8B, false);
+ _vm->playSound(0x8C, false);
+ gnap._actionStatus = -1;
+ break;
+
+ case kAS01UsePigs:
+ gnap.playPullOutDevice(Common::Point(7, 2));
+ gnap.playUseDevice();
+ gameSys.insertSequence(135, 39, 0, 0, kSeqNone, 25, _vm->getRandom(140) - 40, 0);
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ gameSys.setAnimation(0, 0, 3);
+ _vm->invAdd(kItemMud);
+ _vm->setGrabCursorSprite(kItemMud);
+ _vm->setFlag(kGFMudTaken);
+ updateHotspots();
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2) {
+ _smokeIdCtr = (_smokeIdCtr + 1) % 2;
+ gameSys.setAnimation(0x86, _smokeIdCtr + 20, 4);
+ gameSys.insertSequence(0x86, _smokeIdCtr + 20,
+ 0x86, (_smokeIdCtr + 1) % 2 + 20,
+ kSeqSyncWait, 0, 0, 0);
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ _pigsIdCtr = (_pigsIdCtr + 1) % 2;
+ gameSys.setAnimation(0x7F, _pigsIdCtr + 40, 2);
+ gameSys.insertSequence(0x7F, _pigsIdCtr + 40,
+ 0x7F, (_pigsIdCtr + 1) % 2 + 40,
+ kSeqSyncWait, 0, 0, 0);
+ }
+}
+
+/*****************************************************************************/
+
+Scene02::Scene02(GnapEngine *vm) : Scene(vm) {
+ _truckGrillCtr = 0;
+ _nextChickenSequenceId = 0;
+ _currChickenSequenceId = 0;
+ _gnapTruckSequenceId = 0;
+}
+
+int Scene02::init() {
+ _vm->_gameSys->setAnimation(0, 0, 0);
+ return _vm->isFlag(kGFTruckKeysUsed) ? 0x15A : 0x15B;
+}
+
+void Scene02::updateHotspots() {
+ _vm->setHotspot(kHS02Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ if (!_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS02Platypus]._flags |= SF_DISABLED;
+ _vm->setHotspot(kHS02Chicken, 606, 455, 702, 568, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 8);
+ _vm->setHotspot(kHS02Truck1, 385, 258, 464, 304, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 5);
+ _vm->setHotspot(kHS02Truck2, 316, 224, 390, 376, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 6);
+ _vm->setHotspot(kHS02TruckGrill, 156, 318, 246, 390, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 2, 7);
+ _vm->setHotspot(kHS02ExitHouse, 480, 120, 556, 240, SF_EXIT_U_CURSOR, 7, 5);
+ _vm->setHotspot(kHS02ExitBarn, 610, 0, 800, 164, SF_EXIT_U_CURSOR, 10, 5);
+ _vm->setHotspot(kHS02ExitCreek, 780, 336, 800, 556, SF_EXIT_R_CURSOR | SF_WALKABLE, 10, 8);
+ _vm->setHotspot(kHS02ExitPigpen, 0, 300, 20, 600, SF_EXIT_L_CURSOR | SF_WALKABLE, 0, 8);
+ _vm->setHotspot(kHS02WalkArea1, 92, 140, 304, 430, SF_NONE, 3, 1);
+ _vm->setHotspot(kHS02WalkArea2, 0, 0, 800, 380);
+ _vm->setHotspot(kHS02WalkArea3, 0, 0, 386, 445);
+ _vm->setHotspot(kHS02WalkArea4, 386, 0, 509, 410);
+ _vm->setDeviceHotspot(kHS02Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 14;
+}
+
+void Scene02::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1091C, true);
+ _vm->startSoundTimerC(6);
+
+ _currChickenSequenceId = 0x14B;
+ gameSys.setAnimation(0x14B, 179, 2);
+ gameSys.insertSequence(0x14B, 179, 0, 0, kSeqNone, 0, 0, 0);
+
+ _nextChickenSequenceId = -1;
+ _vm->_timers[5] = _vm->getRandom(20) + 30;
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+
+ _vm->queueInsertDeviceIcon();
+
+ switch (_vm->_prevSceneNum) {
+ case 3:
+ gnap.initPos(11, 6, kDirBottomLeft);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(12, 6, kDirIdleRight);
+ _vm->endSceneInit();
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(Common::Point(9, 6), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(8, 6), -1, 0x107BA, 1);
+ break;
+ case 4:
+ gnap.initPos(_vm->_hotspotsWalkPos[6].x, _vm->_hotspotsWalkPos[6].y, kDirBottomLeft);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(_vm->_hotspotsWalkPos[6].x + 1, _vm->_hotspotsWalkPos[6].y, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(7, 6), 0, 0x107B9, 1);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(Common::Point(8, 6), 1, 0x107C2, 1);
+ updateHotspots();
+ gameSys.waitForUpdate();
+ break;
+ case 47:
+ _vm->clearFlag(kGFUnk25);
+ gnap.initPos(5, 6, kDirBottomLeft);
+ plat.initPos(6, 7, kDirIdleRight);
+ _vm->endSceneInit();
+ break;
+ case 49:
+ gnap.initPos(5, 6, kDirBottomRight);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(6, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ break;
+ default:
+ gnap.initPos(-1, 6, kDirBottomRight);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(-1, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(Common::Point(2, 7), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ break;
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 6, 7, 6, 8, 6);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS02Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS02Platypus:
+ if (gnap._actionStatus < 0 && _vm->isFlag(kGFPlatypus)) {
+ if (_vm->_grabCursorSpriteIndex == kItemDisguise) {
+ gnap.useDisguiseOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFKeysTaken))
+ gnap.playMoan1(plat._pos);
+ else
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS02Chicken:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemTwig) {
+ gnap._idleFacing = kDirUpRight;
+ Common::Point destPos = _vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot] + Common::Point(0, 1);
+ gnap.walkTo(destPos, 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS02UseTwigWithChicken;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[1] + Common::Point(0, 1), 9, 8);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2(Common::Point(9, 8));
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirBottomRight;
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[1], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1))
+ gnap._actionStatus = kAS02GrabChicken;
+ else
+ gnap._actionStatus = -1;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirBottomRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[1], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS02TalkChicken;
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS02Truck1:
+ case kHS02Truck2:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemKeys) {
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 2)) | 0x10000, 1)) {
+ _vm->setGrabCursorSprite(-1);
+ _vm->invRemove(kItemKeys);
+ if (_vm->isFlag(kGFTruckFilledWithGas))
+ gnap._actionStatus = kAS02UseTruckGas;
+ else
+ gnap._actionStatus = kAS02UseTruckNoGas;
+ }
+ } else if (_vm->_grabCursorSpriteIndex == kItemGas) {
+ _vm->_hotspots[kHS02WalkArea4]._flags |= SF_WALKABLE;
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 2)) | 0x10000, 1))
+ gnap._actionStatus = kAS02UseGasWithTruck;
+ _vm->_hotspots[kHS02WalkArea4]._flags &= ~SF_WALKABLE;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[2], 2, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(2, 2));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFTruckKeysUsed)) {
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 2)) | 0x10000, 1)) {
+ if (_vm->isFlag(kGFTruckFilledWithGas))
+ gnap._actionStatus = kAS02UseTruckGas;
+ else
+ gnap._actionStatus = kAS02UseTruckNoGas;
+ }
+ } else {
+ gnap._idleFacing = kDirIdleRight;
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 2)) | 0x10000, 1))
+ gnap._actionStatus = kAS02UseTruckNoKeys;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS02TruckGrill:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[4], 2, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2(Common::Point(2, 4));
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS02GrabTruckGrill;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS02ExitHouse:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[6], 0, 0x107AD, 1);
+ gnap._actionStatus = kAS02LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[6] + Common::Point(1, 0), -1, 0x107C1, 1);
+ updateHotspots();
+ _vm->_newSceneNum = 4;
+ }
+ break;
+
+ case kHS02ExitBarn:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[7], 0, 0x107AD, 1);
+ gnap._actionStatus = kAS02LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[7] + Common::Point(1, 0), -1, 0x107C1, 1);
+ updateHotspots();
+ _vm->_newSceneNum = 5;
+ }
+ break;
+
+ case kHS02ExitCreek:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[8], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS02LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[8], -1, 0x107CD, 1);
+ _vm->_newSceneNum = 3;
+ }
+ break;
+
+ case kHS02ExitPigpen:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[9], 0, 0x107AF, 1);
+ gnap._actionStatus = kAS02LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[9], -1, 0x107CF, 1);
+ _vm->_newSceneNum = 1;
+ }
+ break;
+
+ case kHS02WalkArea1:
+ case kHS02WalkArea2:
+ case kHS02WalkArea3:
+ case kHS02WalkArea4:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1091C))
+ _vm->playSound(0x1091C, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0 && _vm->isFlag(kGFPlatypus))
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ // Update bird animation
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+ if (_vm->getRandom(2) != 0)
+ gameSys.insertSequence(0x156, 256, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x154, 256, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ if (!_vm->_timers[5] && _nextChickenSequenceId == -1 && gnap._actionStatus != 7 && gnap._actionStatus != 8) {
+ if (_vm->getRandom(6) != 0) {
+ _nextChickenSequenceId = 0x14B;
+ _vm->_timers[5] = _vm->getRandom(20) + 30;
+ } else {
+ _nextChickenSequenceId = 0x14D;
+ _vm->_timers[5] = _vm->getRandom(20) + 50;
+ }
+ }
+ _vm->playSoundC();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene02::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ switch (gnap._actionStatus) {
+ case kAS02UseTruckNoKeys:
+ gameSys.insertSequence(0x14E, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x14E, gnap._id, 0);
+ gnap._sequenceId = 0x14E;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS02UseTruckNoKeysDone;
+ break;
+ case kAS02UseGasWithTruck:
+ gameSys.insertSequence(0x151, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x151, gnap._id, 0);
+ gnap._sequenceId = 0x151;
+ gnap._sequenceDatNum = 0;
+ _vm->invRemove(kItemGas);
+ _vm->setGrabCursorSprite(-1);
+ _vm->setFlag(kGFTruckFilledWithGas);
+ gnap._actionStatus = kAS02UseGasWithTruckDone;
+ break;
+ case kAS02UseTruckGas:
+ _vm->_timers[5] = 9999;
+ _vm->_timers[4] = 9999;
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+ if (!_vm->isFlag(kGFTruckKeysUsed)) {
+ gameSys.insertSequence(0x14F, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.waitForUpdate();
+ _vm->setFlag(kGFTruckKeysUsed);
+ gnap._sequenceId = 0x14F;
+ gnap._sequenceDatNum = 0;
+ _vm->invRemove(kItemKeys);
+ _vm->setGrabCursorSprite(-1);
+ }
+ _vm->_newSceneNum = 47;
+ _vm->_sceneDone = true;
+ break;
+ case kAS02UseTruckNoGas:
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+ _vm->_timers[4] = 250;
+ if (!_vm->isFlag(kGFTruckKeysUsed)) {
+ gameSys.insertSequence(0x14F, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.waitForUpdate();
+ _vm->setFlag(kGFTruckKeysUsed);
+ gnap._sequenceId = 0x14F;
+ gnap._sequenceDatNum = 0;
+ _vm->invRemove(kItemKeys);
+ _vm->setGrabCursorSprite(-1);
+ }
+ _vm->_newSceneNum = 47;
+ _vm->_sceneDone = true;
+ _vm->setFlag(kGFUnk25);
+ break;
+ case kAS02GrabTruckGrill:
+ switch (_truckGrillCtr) {
+ case 0:
+ _gnapTruckSequenceId = 0x158;
+ break;
+ case 1:
+ _gnapTruckSequenceId = 0x159;
+ break;
+ case 2:
+ _gnapTruckSequenceId = 0x157;
+ break;
+ }
+ _truckGrillCtr = (_truckGrillCtr + 1) % 3;
+ gameSys.insertSequence(_gnapTruckSequenceId, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_gnapTruckSequenceId, gnap._id, 0);
+ gnap._sequenceId = _gnapTruckSequenceId;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = -1;
+ break;
+ case kAS02LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS02TalkChicken:
+ _nextChickenSequenceId = 0x14C;
+ break;
+ case kAS02GrabChicken:
+ _nextChickenSequenceId = 0x150;
+ _vm->_timers[2] = 100;
+ break;
+ case kAS02GrabChickenDone:
+ gameSys.insertSequence(0x107B5, gnap._id, 0x150, 179, kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = 0x7B5;
+ gnap._sequenceDatNum = 1;
+ _currChickenSequenceId = 0x14B;
+ gameSys.setAnimation(0x14B, 179, 2);
+ gameSys.insertSequence(_currChickenSequenceId, 179, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._actionStatus = -1;
+ _vm->_timers[5] = 30;
+ break;
+ case kAS02UseTwigWithChicken:
+ gnap.playShowItem(5, 0, 0);
+ gameSys.insertSequence(0x155, 179, _currChickenSequenceId, 179, kSeqSyncExists, 0, 0, 0);
+ _currChickenSequenceId = 0x155;
+ _nextChickenSequenceId = -1;
+ gnap._actionStatus = -1;
+ break;
+ case kAS02UseTruckNoKeysDone:
+ case kAS02UseGasWithTruckDone:
+ default:
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ if (_nextChickenSequenceId == 0x150) {
+ gameSys.setAnimation(_nextChickenSequenceId, 179, 0);
+ gameSys.insertSequence(_nextChickenSequenceId, 179, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(_currChickenSequenceId, 179, true);
+ _nextChickenSequenceId = -1;
+ _currChickenSequenceId = -1;
+ gnap._actionStatus = kAS02GrabChickenDone;
+ _vm->_timers[5] = 500;
+ } else if (_nextChickenSequenceId == 0x14C) {
+ gameSys.setAnimation(_nextChickenSequenceId, 179, 2);
+ gameSys.insertSequence(_nextChickenSequenceId, 179, _currChickenSequenceId, 179, kSeqSyncWait, 0, 0, 0);
+ _currChickenSequenceId = _nextChickenSequenceId;
+ _nextChickenSequenceId = -1;
+ gnap._actionStatus = -1;
+ } else if (_nextChickenSequenceId != -1) {
+ gameSys.setAnimation(_nextChickenSequenceId, 179, 2);
+ gameSys.insertSequence(_nextChickenSequenceId, 179, _currChickenSequenceId, 179, kSeqSyncWait, 0, 0, 0);
+ _currChickenSequenceId = _nextChickenSequenceId;
+ _nextChickenSequenceId = -1;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene03::Scene03(GnapEngine *vm) : Scene(vm) {
+ _nextPlatSequenceId = -1;
+ _platypusScared = false;
+ _platypusHypnotized = false;
+ _nextFrogSequenceId = -1;
+ _currFrogSequenceId = -1;
+}
+
+int Scene03::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 5);
+ return 0x1CC;
+}
+
+void Scene03::updateHotspots() {
+ _vm->setHotspot(kHS03Platypus, 0, 0, 0, 0, SF_DISABLED | SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS03Grass, 646, 408, 722, 458, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 9, 6);
+ _vm->setHotspot(kHS03ExitTruck, 218, 64, 371, 224, SF_EXIT_U_CURSOR | SF_WALKABLE, 4, 4);
+ _vm->setHotspot(kHS03Creek, 187, 499, 319, 587, SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 7);
+ _vm->setHotspot(kHS03TrappedPlatypus, 450, 256, 661, 414, SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 2, 5);
+ _vm->setHotspot(kHS03WalkAreas1, 0, 500, 300, 600);
+ _vm->setHotspot(kHS03WalkAreas2, 300, 447, 800, 600);
+ _vm->setHotspot(kHS03PlatypusWalkArea, 235, 0, 800, 600);
+ _vm->setHotspot(kHS03WalkAreas3, 0, 0, 800, 354);
+ _vm->setDeviceHotspot(kHS03Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS03Platypus]._flags = SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ if (_vm->isFlag(kGFGrassTaken))
+ _vm->_hotspots[kHS03Grass]._flags = SF_WALKABLE | SF_DISABLED;
+ if (_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS03TrappedPlatypus]._flags = SF_DISABLED;
+ if (_vm->isFlag(kGFPlatypus) || _platypusHypnotized)
+ _vm->_hotspots[kHS03PlatypusWalkArea]._flags |= SF_WALKABLE;
+ _vm->_hotspotsCount = 10;
+}
+
+void Scene03::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x10925, true);
+ _vm->startSoundTimerC(7);
+
+ gameSys.insertSequence(0x1CA, 251, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x1CB, 251, 0, 0, kSeqLoop, 0, 0, 0);
+
+ _platypusHypnotized = false;
+ gnap.initPos(3, 4, kDirBottomRight);
+
+ gameSys.insertSequence(0x1C6, 253, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currFrogSequenceId = 0x1C6;
+ _nextFrogSequenceId = -1;
+ gameSys.setAnimation(0x1C6, 253, 2);
+
+ _vm->_timers[6] = _vm->getRandom(20) + 30;
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+ _vm->_timers[5] = _vm->getRandom(100) + 200;
+
+ if (_vm->isFlag(kGFPlatypus)) {
+ plat.initPos(5, 4, kDirIdleLeft);
+ } else {
+ _vm->_timers[1] = _vm->getRandom(40) + 20;
+ gameSys.setAnimation(0x1C2, 99, 1);
+ gameSys.insertSequence(0x1C2, 99, 0, 0, kSeqNone, 0, 0, 0);
+ plat._sequenceId = 0x1C2;
+ plat._sequenceDatNum = 0;
+ }
+
+ gameSys.insertSequence(0x1C4, 255, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (!_vm->isFlag(kGFGrassTaken))
+ gameSys.insertSequence(0x1B2, 253, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ _vm->endSceneInit();
+
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(Common::Point(4, 7), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(3, 6), -1, 0x107B9, 1);
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS03Platypus:
+ if (gnap._actionStatus < 0 && _vm->isFlag(kGFPlatypus)) {
+ if (_vm->_grabCursorSpriteIndex == kItemDisguise) {
+ gnap.useDisguiseOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFKeysTaken))
+ gnap.playMoan1(plat._pos);
+ else
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS03Grass:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFGrassTaken)) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 9, 6);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(9, 6));
+ break;
+ case GRAB_CURSOR:
+ gnap.playPullOutDevice(Common::Point(9, 6));
+ gnap.playUseDevice();
+ gameSys.insertSequence(0x1B3, 253, 0x1B2, 253, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x1B3, 253, 5);
+ _vm->_hotspots[kHS03Grass]._flags |= SF_WALKABLE | SF_DISABLED;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS03ExitTruck:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_hotspots[kHS03PlatypusWalkArea]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, 0x107AD, 1);
+ gnap._actionStatus = kAS03LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[2], -1, 0x107C2, 1);
+ _vm->_hotspots[kHS03PlatypusWalkArea]._flags &= ~SF_WALKABLE;
+ if (_vm->_cursorValue == 1)
+ _vm->_newSceneNum = 2;
+ else
+ _vm->_newSceneNum = 33;
+ }
+ break;
+
+ case kHS03Creek:
+ if (gnap._actionStatus == -1) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2(Common::Point(2, 8));
+ break;
+ case GRAB_CURSOR:
+ if (!_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS03PlatypusWalkArea]._flags |= SF_WALKABLE;
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[3] + Common::Point(1, 1)) | 0x10000, 1))
+ gnap._actionStatus = kAS03GrabCreek;
+ if (!_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS03PlatypusWalkArea]._flags &= ~SF_WALKABLE;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS03TrappedPlatypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypus)) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 8, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(8, 4));
+ break;
+ case GRAB_CURSOR:
+ if (_platypusHypnotized) {
+ gnap.walkTo(Common::Point(7, 6), 0, 0x107B5, 1);
+ gnap._actionStatus = kAS03FreePlatypus;
+ } else {
+ gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ if (_platypusScared)
+ gnap._actionStatus = kAS03GrabScaredPlatypus;
+ else
+ gnap._actionStatus = kAS03GrabPlatypus;
+ }
+ break;
+ case TALK_CURSOR:
+ if (_platypusHypnotized) {
+ gnap.playBrainPulsating(Common::Point(8, 4));
+ } else {
+ gnap._idleFacing = kDirBottomRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ if (_platypusScared)
+ gnap._actionStatus = kAS03HypnotizeScaredPlat;
+ else
+ gnap._actionStatus = kAS03HypnotizePlat;
+ }
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS03Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS03WalkAreas1:
+ case kHS03WalkAreas2:
+ case kHS03WalkAreas3:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ case kHS03PlatypusWalkArea:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypus) || _platypusHypnotized) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ } else {
+ gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, 0x107B5, 1);
+ if (_platypusScared)
+ gnap._actionStatus = kAS03GrabScaredPlatypus;
+ else
+ gnap._actionStatus = kAS03GrabPlatypus;
+ }
+ }
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x10925))
+ _vm->playSound(0x10925, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0 && _vm->isFlag(kGFPlatypus))
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[1] && !_platypusScared) {
+ _vm->_timers[1] = _vm->getRandom(40) + 20;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && !_vm->isFlag(kGFPlatypus) && !_platypusHypnotized)
+ _nextPlatSequenceId = 450;
+ }
+ if (!_vm->_timers[6]) {
+ _vm->_timers[6] = _vm->getRandom(20) + 30;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextFrogSequenceId == -1) {
+ if (_vm->getRandom(5) == 1)
+ _nextFrogSequenceId = 0x1C6;
+ else
+ _nextFrogSequenceId = 0x1C7;
+ }
+ }
+ if (!_vm->_timers[4]) {
+ // Update bird animation
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0)
+ gameSys.insertSequence(_vm->getRandom(2) != 0 ? 0x1C8 : 0x1C3, 253, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(100) + 200;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0) {
+ gameSys.setAnimation(0x1C5, 253, 4);
+ gameSys.insertSequence(0x1C5, 253, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ }
+ _vm->playSoundC();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[5] = _vm->getRandom(100) + 200;
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+ _vm->_timers[6] = _vm->getRandom(20) + 30;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene03::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS03LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS03FreePlatypus:
+ _nextPlatSequenceId = 0x1BC;
+ break;
+ case kAS03FreePlatypusDone:
+ gnap._actionStatus = -1;
+ plat._pos = Common::Point(6, 6);
+ plat._idleFacing = kDirIdleRight;
+ plat._id = 120;
+ gameSys.insertSequence(0x107CA, plat._id, 0x1BC, 99,
+ kSeqSyncWait, 0, 75 * plat._pos.x - plat._gridX, 48 * plat._pos.y - plat._gridY);
+ gameSys.insertSequence(0x1B7, 99, 0, 0, kSeqNone, 0, 0, 0);
+ plat._sequenceDatNum = 1;
+ plat._sequenceId = 0x7CA;
+ _vm->setFlag(kGFPlatypus);
+ _nextPlatSequenceId = -1;
+ updateHotspots();
+ break;
+ case kAS03HypnotizePlat:
+ gnap.playBrainPulsating();
+ _vm->addFullScreenSprite(0x106, 255);
+ gameSys.setAnimation(0x1C9, 256, 1);
+ gameSys.insertSequence(0x1C9, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(1) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->removeFullScreenSprite();
+ gameSys.setAnimation(0x1BA, 99, 1);
+ gameSys.insertSequence(0x1BA, 99, plat._sequenceId | (plat._sequenceDatNum << 16), 99, kSeqSyncExists, 0, 0, 0);
+ plat._sequenceDatNum = 0;
+ plat._sequenceId = 0x1BA;
+ gnap._actionStatus = -1;
+ _platypusHypnotized = true;
+ updateHotspots();
+ break;
+ case kAS03HypnotizeScaredPlat:
+ gnap.playBrainPulsating();
+ gameSys.insertSequence(0x1BF, 99, plat._sequenceId | (plat._sequenceDatNum << 16), 99, kSeqSyncExists, 0, 0, 0);
+ gameSys.setAnimation(0x1BF, 99, 1);
+ while (gameSys.getAnimationStatus(1) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->addFullScreenSprite(0x106, 255);
+ gameSys.setAnimation(0x1C9, 256, 1);
+ gameSys.insertSequence(0x1C9, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(1) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->removeFullScreenSprite();
+ gameSys.setAnimation(0x1BA, 99, 1);
+ gameSys.insertSequence(0x1BA, 99, 447, 99, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceDatNum = 0;
+ plat._sequenceId = 0x1BA;
+ gnap._actionStatus = -1;
+ _platypusHypnotized = true;
+ updateHotspots();
+ break;
+ case kAS03GrabPlatypus:
+ _nextPlatSequenceId = 0x1BD;
+ _platypusHypnotized = false;
+ break;
+ case kAS03GrabScaredPlatypus:
+ _nextPlatSequenceId = 0x1C0;
+ _platypusHypnotized = false;
+ break;
+ case kAS03GrabCreek:
+ gameSys.insertSequence(0x1B4, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x1B4, gnap._id, 0);
+ gnap._sequenceId = 0x1B4;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS03GrabCreekDone;
+ break;
+ default:
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ if (_nextPlatSequenceId == 0x1BD || _nextPlatSequenceId == 0x1C0) {
+ gameSys.setAnimation(0, 0, 1);
+ _platypusScared = true;
+ gameSys.insertSequence(0x1B5, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(_nextPlatSequenceId, 99, plat._sequenceId | (plat._sequenceDatNum << 16), 99, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x1B5;
+ gnap._sequenceDatNum = 0;
+ gnap._idleFacing = kDirIdleLeft;
+ plat._sequenceId = _nextPlatSequenceId;
+ plat._sequenceDatNum = 0;
+ gameSys.setAnimation(_nextPlatSequenceId, 99, 1);
+ _nextPlatSequenceId = -1;
+ gnap._actionStatus = -1;
+ } else if (_nextPlatSequenceId == 0x1BC) {
+ gnap._pos = Common::Point(3, 6);
+ gameSys.insertSequence(0x1B6, 120, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x1BC, 99, plat._sequenceId | (plat._sequenceDatNum << 16), 99, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x1BC, 99, 0);
+ gnap._id = 20 * gnap._pos.y;
+ gnap._sequenceId = 0x1B6;
+ gnap._sequenceDatNum = 0;
+ gnap._idleFacing = kDirIdleLeft;
+ gnap._actionStatus = kAS03FreePlatypusDone;
+ _nextPlatSequenceId = -1;
+ } else if (_nextPlatSequenceId == 0x1C2 && !_platypusScared) {
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.insertSequence(0x1C2, 99, plat._sequenceId | (plat._sequenceDatNum << 16), 99, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceId = 0x1C2;
+ plat._sequenceDatNum = 0;
+ gameSys.setAnimation(0x1C2, 99, 1);
+ _nextPlatSequenceId = -1;
+ } else if (_nextPlatSequenceId == -1 && _platypusScared && !_platypusHypnotized) {
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0x1BE, 99, 1);
+ gameSys.insertSequence(0x1BE, 99, plat._sequenceId | (plat._sequenceDatNum << 16), 99, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceId = 0x1BE;
+ plat._sequenceDatNum = 0;
+ _nextPlatSequenceId = -1;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2 && _nextFrogSequenceId != -1) {
+ gameSys.setAnimation(_nextFrogSequenceId, 253, 2);
+ gameSys.insertSequence(_nextFrogSequenceId, 253, _currFrogSequenceId, 253, kSeqSyncWait, 0, 0, 0);
+ _currFrogSequenceId = _nextFrogSequenceId;
+ _nextFrogSequenceId = -1;
+ }
+
+ if (gameSys.getAnimationStatus(5) == 2) {
+ gameSys.setAnimation(0, 0, 5);
+ _vm->invAdd(kItemGrass);
+ _vm->setGrabCursorSprite(kItemGrass);
+ _vm->setFlag(kGFGrassTaken);
+ updateHotspots();
+ }
+}
+
+/*****************************************************************************/
+
+Scene04::Scene04(GnapEngine *vm) : Scene(vm) {
+ _dogIdCtr = 0;
+ _triedWindow = false;
+ _nextDogSequenceId = -1;
+ _currDogSequenceId = -1;
+}
+
+int Scene04::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ return 0x214;
+}
+
+void Scene04::updateHotspots() {
+ _vm->setHotspot(kHS04Platypus, 0, 0, 0, 0, SF_DISABLED | SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS04Twig, 690, 394, 769, 452, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 9, 6);
+ _vm->setHotspot(kHS04Dog, 550, 442, 680, 552, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 8);
+ _vm->setHotspot(kHS04Axe, 574, 342, 680, 412, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 7);
+ _vm->setHotspot(kHS04Door, 300, 244, 386, 410, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 7);
+ _vm->setHotspot(kHS04ExitTruck, 226, 580, 688, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS04Window, 121, 295, 237, 342, SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 7);
+ _vm->setHotspot(kHS04ExitBarn, 585, 154, 800, 276, SF_EXIT_U_CURSOR, 10, 8);
+ _vm->setHotspot(kHS04WalkArea1, 0, 0, 562, 461);
+ _vm->setHotspot(kHS04WalkArea2, 562, 0, 800, 500);
+ _vm->setDeviceHotspot(kHS04Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS04Platypus]._flags = SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ if (_vm->isFlag(kGFTwigTaken))
+ _vm->_hotspots[kHS04Twig]._flags = SF_WALKABLE | SF_DISABLED;
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant) || _vm->_cursorValue == 1)
+ _vm->_hotspots[kHS04Axe]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 11;
+}
+
+void Scene04::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1091C, true);
+ _vm->startSoundTimerC(4);
+
+ gameSys.insertSequence(0x210, 139 - _dogIdCtr, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currDogSequenceId = 0x210;
+ _nextDogSequenceId = -1;
+
+ gameSys.setAnimation(0x210, 139 - _dogIdCtr, 3);
+ _dogIdCtr = (_dogIdCtr + 1) % 2;
+ _vm->_timers[6] = _vm->getRandom(20) + 60;
+ _vm->_timers[5] = _vm->getRandom(150) + 300;
+ _vm->_timers[7] = _vm->getRandom(150) + 200;
+ _vm->_timers[8] = _vm->getRandom(150) + 400;
+
+ if (!_vm->isFlag(kGFPlatypusTalkingToAssistant) && _vm->_cursorValue == 4)
+ gameSys.insertSequence(0x212, 100, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (!_vm->isFlag(kGFTwigTaken))
+ gameSys.insertSequence(0x1FE, 100, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ _vm->_timers[3] = 300;
+ _vm->setGrabCursorSprite(kItemKeys);
+ gnap._pos = Common::Point(4, 7);
+ gnap._id = 140;
+ plat._pos = Common::Point(6, 7);
+ plat._id = 141;
+ gameSys.insertSequence(0x107B5, 140, 0, 0, kSeqNone, 0, 300 - gnap._gridX, 336 - gnap._gridY);
+ gameSys.insertSequence(0x20C, 141, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x208, 121, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x209, 121, 0x208, 121, kSeqSyncWait, 0, 0, 0);
+ _vm->endSceneInit();
+ _vm->invRemove(kItemDisguise);
+ _vm->invAdd(kItemKeys);
+ _vm->setFlag(kGFKeysTaken);
+ _vm->clearFlag(kGFPlatypusDisguised);
+ plat._sequenceId = 0x20C;
+ plat._sequenceDatNum = 0;
+ plat._idleFacing = kDirBottomRight;
+ gnap._sequenceId = 0x7B5;
+ gnap._sequenceDatNum = 1;
+ gameSys.waitForUpdate();
+ } else {
+ gameSys.insertSequence(0x209, 121, 0, 0, kSeqNone, 0, 0, 0);
+ if (_vm->_prevSceneNum == 2) {
+ gnap.initPos(5, 11, kDirUpRight);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(6, 11, kDirUpLeft);
+ _vm->endSceneInit();
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(Common::Point(5, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(6, 9), -1, 0x107BA, 1);
+ } else if (_vm->_prevSceneNum == 38) {
+ gnap.initPos(5, 7, kDirBottomRight);
+ plat.initPos(4, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ } else {
+ gnap.initPos(12, 9, kDirBottomRight);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(12, 8, kDirIdleLeft);
+ _vm->endSceneInit();
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(Common::Point(9, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(9, 9), -1, 0x107BA, 1);
+ }
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 4, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS04Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS04Platypus:
+ if (gnap._actionStatus < 0 && _vm->isFlag(kGFPlatypus)) {
+ if (_vm->_grabCursorSpriteIndex == kItemDisguise) {
+ gnap.useDisguiseOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFKeysTaken))
+ gnap.playMoan1(plat._pos);
+ else
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ if (_vm->_cursorValue == 4)
+ gnap.kissPlatypus(0);
+ else
+ gnap.playMoan1(plat._pos);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS04Twig:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 9, 6);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(_vm->_hotspotsWalkPos[1]);
+ break;
+ case GRAB_CURSOR:
+ gnap.playPullOutDevice(_vm->_hotspotsWalkPos[1]);
+ gnap.playUseDevice(_vm->_hotspotsWalkPos[1]);
+ gameSys.insertSequence(0x1FD, 100, 510, 100, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x1FD, 100, 2);
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS04Axe:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[3], 9, 5);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2(_vm->_hotspotsWalkPos[3]);
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS04GrabAxe;
+ _vm->setFlag(kGFPlatypusTalkingToAssistant);
+ updateHotspots();
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS04Dog:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[2], 9, 7);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (gnap.walkTo(gnap._pos, 0, -1, 1)) {
+ gnap.playMoan2(_vm->_hotspotsWalkPos[2]);
+ _nextDogSequenceId = 0x20F;
+ }
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirBottomRight;
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1))
+ gnap._actionStatus = kAS04GrabDog;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirBottomRight;
+ if (gnap.walkTo(gnap._pos, 0, -1, 1)) {
+ gnap.playBrainPulsating(_vm->_hotspotsWalkPos[2]);
+ _nextDogSequenceId = 0x20E;
+ }
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS04Door:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 4, 3);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playScratchingHead(Common::Point(4, 3));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->_cursorValue == 1) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, 0x107BC, 1);
+ gnap._actionStatus = kAS04OpenDoor;
+ _vm->_timers[5] = 300;
+ gnap._idleFacing = kDirUpLeft;
+ } else {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, 0x107BC, 1);
+ gnap._actionStatus = kAS04LeaveScene;
+ _vm->_newSceneNum = 38;
+ }
+ break;
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS04ExitTruck:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[5], 0, 0x107AE, 1);
+ gnap._actionStatus = kAS04LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[5], -1, 0x107C7, 1);
+ if (_vm->_cursorValue == 1)
+ _vm->_newSceneNum = 2;
+ else
+ _vm->_newSceneNum = 33;
+ }
+ break;
+
+ case kHS04Window:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 2, 3);
+ } else if (_vm->isFlag(kGFKeysTaken)) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[7], 0, gnap.getSequenceId(kGSIdle, Common::Point(10, 2)) | 0x10000, 1)) {
+ if (_triedWindow) {
+ gnap._actionStatus = kAS04GetKeyAnother;
+ } else {
+ gnap._actionStatus = kAS04GetKeyFirst;
+ _triedWindow = true;
+ }
+ }
+ break;
+ case GRAB_CURSOR:
+ gnap.playScratchingHead(_vm->_hotspotsWalkPos[7]);
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS04ExitBarn:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[8], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS04LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[8] + Common::Point(0, 1), -1, 0x107C1, 1);
+ if (_vm->_cursorValue == 1)
+ _vm->_newSceneNum = 5;
+ else
+ _vm->_newSceneNum = 35;
+ }
+ break;
+
+ case kHS04WalkArea1:
+ case kHS04WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1091C))
+ _vm->playSound(0x1091C, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0 && _vm->isFlag(kGFPlatypus))
+ plat.updateIdleSequence2();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence2();
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(150) + 300;
+ if (gnap._actionStatus < 0)
+ gameSys.insertSequence(0x20D, 79, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ if (!_vm->_timers[7]) {
+ _vm->_timers[7] = _vm->getRandom(150) + 200;
+ gameSys.insertSequence(0x1FC, 59, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ if (!_vm->_timers[6]) {
+ _vm->_timers[6] = _vm->getRandom(20) + 60;
+ if (_nextDogSequenceId == -1)
+ _nextDogSequenceId = 0x210;
+ }
+ if (!_vm->_timers[8]) {
+ _vm->_timers[8] = _vm->getRandom(150) + 400;
+ gameSys.insertSequence(0x213, 20, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ _vm->playSoundC();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene04::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS04LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS04OpenDoor:
+ gameSys.insertSequence(0x205, gnap._id, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x207, 121, 521, 121, kSeqSyncWait, 0, 0, 0);
+ gnap._pos = Common::Point(6, 7);
+ gameSys.insertSequence(0x107B5, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, _vm->getSequenceTotalDuration(0x205) - 1, 450 - gnap._gridX, 336 - gnap._gridY);
+ gameSys.setAnimation(0x107B5, gnap._id, 0);
+ gnap._sequenceId = 0x7B5;
+ gnap._sequenceDatNum = 1;
+ gnap._actionStatus = kAS04OpenDoorDone;
+ break;
+ case kAS04OpenDoorDone:
+ gameSys.insertSequence(0x209, 121, 0x207, 121, kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = -1;
+ break;
+ case kAS04GetKeyFirst:
+ gameSys.insertSequence(0x204, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x204, gnap._id, 0);
+ gnap._sequenceId = 0x204;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS04GetKeyFirst2;
+ break;
+ case kAS04GetKeyFirst2:
+ gameSys.insertSequence(0x206, 255, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x1FF, 256, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x20B, 256, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(0x20B, 256, 0);
+ gnap._sequenceId = 0x206;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS04GetKeyFirstDone;
+ break;
+ case kAS04GetKeyFirstDone:
+ gameSys.requestRemoveSequence(0x1FF, 256);
+ gameSys.requestRemoveSequence(0x20B, 256);
+ gameSys.insertSequence(0x107B5, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), 255,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._idleFacing = kDirBottomRight;
+ gnap._sequenceId = 0x7B5;
+ gnap._sequenceDatNum = 1;
+ gnap._actionStatus = -1;
+ break;
+ case kAS04GetKeyAnother:
+ gameSys.insertSequence(0x202, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x202, gnap._id, 0);
+ gnap._sequenceId = 0x202;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS04GetKeyAnother2;
+ break;
+ case kAS04GetKeyAnother2:
+ gameSys.insertSequence(0x203, 255, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x1FF, 256, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x20A, 256, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(0x20A, 256, 0);
+ gnap._sequenceId = 0x203;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS04GetKeyAnotherDone;
+ break;
+ case kAS04GetKeyAnotherDone:
+ gameSys.removeSequence(0x1FF, 256, true);
+ gameSys.removeSequence(0x20A, 256, true);
+ gameSys.insertSequence(0x107B5, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), 255,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = 0x7B5;
+ gnap._sequenceDatNum = 1;
+ gnap._idleFacing = kDirBottomRight;
+ gnap._actionStatus = -1;
+ break;
+ case kAS04GrabDog:
+ _nextDogSequenceId = 0x201;
+ break;
+ case kAS04GrabAxe:
+ gameSys.insertSequence(0x211, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.requestRemoveSequence(0x212, 100);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x211;
+ gnap._actionStatus = -1;
+ break;
+ default:
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ gameSys.setAnimation(0, 0, 2);
+ _vm->invAdd(kItemTwig);
+ _vm->setGrabCursorSprite(kItemTwig);
+ _vm->setFlag(kGFTwigTaken);
+ updateHotspots();
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ if (_nextDogSequenceId == 0x201) {
+ gameSys.insertSequence(_nextDogSequenceId, 139 - _dogIdCtr,
+ _currDogSequenceId, 139 - (_dogIdCtr + 1) % 2,
+ kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x200, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextDogSequenceId, 139 - _dogIdCtr, 3);
+ _dogIdCtr = (_dogIdCtr + 1) % 2;
+ _currDogSequenceId = 0x201;
+ gnap._sequenceId = 0x200;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = -1;
+ _vm->_timers[6] = _vm->getRandom(20) + 60;
+ _nextDogSequenceId = -1;
+ } else if (_nextDogSequenceId != -1) {
+ gameSys.insertSequence(_nextDogSequenceId, 139 - _dogIdCtr,
+ _currDogSequenceId, 139 - (_dogIdCtr + 1) % 2,
+ kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextDogSequenceId, 139 - _dogIdCtr, 3);
+ _dogIdCtr = (_dogIdCtr + 1) % 2;
+ _currDogSequenceId = _nextDogSequenceId;
+ _nextDogSequenceId = -1;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene05::Scene05(GnapEngine *vm) : Scene(vm) {
+ _nextChickenSequenceId = -1;
+ _currChickenSequenceId = -1;
+}
+
+int Scene05::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 3);
+ return _vm->isFlag(kGFBarnPadlockOpen) ? 0x151 : 0x150;
+}
+
+void Scene05::updateHotspots() {
+ _vm->setHotspot(kHS05Platypus, 0, 0, 0, 0, SF_DISABLED | SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS05Haystack, 236, 366, 372, 442, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 7);
+ _vm->setHotspot(kHS05Padlock, 386, 230, 626, 481, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 7);
+ _vm->setHotspot(kHS05Ladder, 108, 222, 207, 444, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 7);
+ _vm->setHotspot(kHS05ExitHouse, 0, 395, 20, 600, SF_EXIT_L_CURSOR | SF_WALKABLE, 0, 8);
+ _vm->setHotspot(kHS05Chicken, 612, 462, 722, 564, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 8);
+ _vm->setHotspot(kHS05WalkArea1, 104, 0, 421, 480);
+ _vm->setHotspot(kHS05WalkArea2, 422, 0, 800, 487);
+ _vm->setHotspot(kHS05WalkArea3, 0, 0, 104, 499);
+ _vm->setDeviceHotspot(kHS05Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS05Platypus]._flags = SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ if (_vm->isFlag(kGFBarnPadlockOpen))
+ _vm->_hotspots[kHS05Padlock]._flags = SF_EXIT_U_CURSOR;
+ _vm->_hotspotsCount = 10;
+}
+
+void Scene05::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1091C, true);
+ _vm->startSoundTimerC(7);
+
+ _currChickenSequenceId = 0x142;
+ gameSys.setAnimation(0x142, 100, 3);
+ gameSys.insertSequence(0x142, 100, 0, 0, kSeqNone, 0, 0, 0);
+
+ _nextChickenSequenceId = -1;
+
+ _vm->_timers[5] = _vm->getRandom(10) + 30;
+ _vm->_timers[6] = _vm->getRandom(150) + 300;
+
+ if (_vm->isFlag(kGFBarnPadlockOpen))
+ gameSys.insertSequence(0x14A, 141, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->_prevSceneNum != 6 && _vm->_prevSceneNum != 36) {
+ gnap.initPos(-1, 8, kDirBottomRight);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(-1, 9, kDirIdleLeft);
+ _vm->endSceneInit();
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(Common::Point(2, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(2, 9), -1, 0x107B9, 1);
+ } else {
+ gnap.initPos(6, 8, kDirBottomRight);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(7, 9, kDirIdleLeft);
+ _vm->endSceneInit();
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 12, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS05Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS05Platypus:
+ if (gnap._actionStatus < 0 && _vm->isFlag(kGFPlatypus)) {
+ if (_vm->_grabCursorSpriteIndex == kItemDisguise) {
+ gnap.useDisguiseOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFKeysTaken))
+ gnap.playMoan1(plat._pos);
+ else
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS05Haystack:
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[1] + Common::Point(-2, 0), 4, 5);
+ } else if (_vm->isFlag(kGFNeedleTaken)) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(_vm->_hotspotsWalkPos[1] + Common::Point(0, -1));
+ break;
+ case GRAB_CURSOR:
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ case PLAT_CURSOR:
+ if (_vm->isFlag(kGFPlatypus)) {
+ gnap.useDeviceOnPlatypus();
+ if (plat.walkTo(_vm->_hotspotsWalkPos[1], 1, 0x107C2, 1)) {
+ plat._actionStatus = kAS05PlatSearchHaystack;
+ plat._idleFacing = kDirIdleRight;
+ }
+ if (gnap._pos.x == 4 && (gnap._pos.y == 8 || gnap._pos.y == 7))
+ gnap.walkStep();
+ gnap.playIdle(plat._pos);
+ }
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS05Chicken:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemTwig) {
+ gnap._idleFacing = kDirUpRight;
+ Common::Point checkPt = _vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot] + Common::Point(0, 1);
+ gnap.walkTo(checkPt, 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS05UseTwigWithChicken;
+ } else if (_vm->_grabCursorSpriteIndex >= 0)
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot] + Common::Point(0, 1), 9, 7);
+ else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2(Common::Point(9, 7));
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirBottomRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[5], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS05GrabChicken;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirBottomRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[5], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS05TalkChicken;
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS05Ladder:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 2, 5);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2(Common::Point(2, 4));
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirBottomLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS05GrabLadder;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS05Padlock:
+ if (_vm->isFlag(kGFBarnPadlockOpen)) {
+ _vm->_isLeavingScene = true;
+ Common::Point destPt = _vm->_hotspotsWalkPos[2] + Common::Point(- 1, 1);
+ gnap.walkTo(destPt, 0, -1, 1);
+ gnap._actionStatus = kAS05EnterBarn;
+ if (_vm->_cursorValue == 1)
+ _vm->_newSceneNum = 6;
+ else
+ _vm->_newSceneNum = 36;
+ } else if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemNeedle) {
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[2], 0,
+ gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[2]) | 0x10000, 1))
+ gnap._actionStatus = kAS05PickPadlock;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[2], 7, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(7, 4));
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS05TryPickPadlock;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS05ExitHouse:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, 0x107AF, 1);
+ gnap._actionStatus = kAS05LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[4] + Common::Point(0, 1), -1, 0x107C7, 1);
+ if (_vm->_cursorValue == 1)
+ _vm->_newSceneNum = 4;
+ else
+ _vm->_newSceneNum = 37;
+ }
+ break;
+
+ case kHS05WalkArea1:
+ case kHS05WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ case kHS05WalkArea3:
+ // Nothing
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1091C))
+ _vm->playSound(0x1091C, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (_vm->isFlag(kGFPlatypus))
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(20) + 30;
+ if (gnap._actionStatus != kAS05TalkChicken && _nextChickenSequenceId == -1) {
+ if (_vm->getRandom(4) != 0)
+ _nextChickenSequenceId = 0x142;
+ else
+ _nextChickenSequenceId = 0x143;
+ }
+ }
+ if (!_vm->_timers[6]) {
+ _vm->_timers[6] = _vm->getRandom(150) + 300;
+ if (gnap._actionStatus < 0)
+ gameSys.insertSequence(0x149, 39, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ _vm->playSoundC();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[5] = _vm->getRandom(20) + 30;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene05::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS05LeaveScene:
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ break;
+ case kAS05TryPickPadlock:
+ gameSys.insertSequence(0x148, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x148;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = -1;
+ break;
+ case kAS05PickPadlock:
+ gameSys.setAnimation(0x147, gnap._id, 0);
+ gameSys.insertSequence(0x147, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x147;
+ gnap._sequenceDatNum = 0;
+ _vm->setFlag(kGFBarnPadlockOpen);
+ _vm->setFlag(kGFSceneFlag1);
+ _vm->setGrabCursorSprite(-1);
+ _vm->_newSceneNum = 6;
+ _vm->_timers[2] = 100;
+ _vm->invRemove(kItemNeedle);
+ gnap._actionStatus = kAS05LeaveScene;
+ break;
+ case kAS05TalkChicken:
+ _nextChickenSequenceId = 0x144;
+ gnap._actionStatus = -1;
+ break;
+ case kAS05GrabChicken:
+ _nextChickenSequenceId = 0x14B;
+ break;
+ case kAS05GrabLadder:
+ while (gameSys.isSequenceActive(0x149, 39) && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ gameSys.insertSequence(0x14E, gnap._id + 1, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x14D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x14D;
+ gnap._sequenceDatNum = 0;
+ _vm->_timers[2] = 200;
+ _vm->_timers[6] = 300;
+ gnap._actionStatus = -1;
+ break;
+ case kAS05EnterBarn:
+ gameSys.insertSequence(0x107B1, 1,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gameSys.setAnimation(0x107B1, 1, 0);
+ gnap._actionStatus = kAS05LeaveScene;
+ break;
+ case kAS05UseTwigWithChicken:
+ gnap.playShowItem(5, 0, 0);
+ _nextChickenSequenceId = 0x14F;
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ PlayerPlat& plat = *_vm->_plat;
+ if (plat._sequenceId == 0x146) {
+ plat._pos = Common::Point(4, 8);
+ gameSys.insertSequence(0x107C1, 160, 0x146, 256, kSeqSyncWait, 0, 300 - plat._gridX, 384 - plat._gridY);
+ plat._sequenceId = 0x7C1;
+ plat._sequenceDatNum = 1;
+ plat._id = 20 * plat._pos.y;
+ _vm->invAdd(kItemNeedle);
+ _vm->setFlag(kGFNeedleTaken);
+ _vm->setGrabCursorSprite(kItemNeedle);
+ _vm->showCursor();
+ _vm->_timers[1] = 30;
+ plat._actionStatus = -1;
+ }
+ if (plat._actionStatus == kAS05PlatSearchHaystack) {
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.insertSequence(0x145, plat._id, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x146, 256, 0x145, plat._id, kSeqSyncWait, 0, 0, 0);
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+ plat._sequenceId = 0x146;
+ plat._sequenceDatNum = 0;
+ gameSys.setAnimation(0x146, 256, 1);
+ _vm->_timers[1] = 300;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ if (_nextChickenSequenceId == 0x14B) {
+ gameSys.setAnimation(_nextChickenSequenceId, 100, 3);
+ gameSys.insertSequence(_nextChickenSequenceId, 100, _currChickenSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x14C, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x14C;
+ _currChickenSequenceId = _nextChickenSequenceId;
+ _nextChickenSequenceId = -1;
+ gnap._actionStatus = -1;
+ } else if (_nextChickenSequenceId != -1) {
+ gameSys.setAnimation(_nextChickenSequenceId, 100, 3);
+ gameSys.insertSequence(_nextChickenSequenceId, 100, _currChickenSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ _currChickenSequenceId = _nextChickenSequenceId;
+ _nextChickenSequenceId = -1;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene06::Scene06(GnapEngine *vm) : Scene(vm) {
+ _horseTurnedBack = false;
+ _nextPlatSequenceId = -1;
+ _nextHorseSequenceId = -1;
+ _currHorseSequenceId = -1;
+}
+
+int Scene06::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ if (_vm->isFlag(kGFSceneFlag1)) {
+ _vm->playSound(0x11B, false);
+ _vm->clearFlag(kGFSceneFlag1);
+ }
+ return 0x101;
+}
+
+void Scene06::updateHotspots() {
+ _vm->setHotspot(kHS06Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS06Gas, 300, 120, 440, 232, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 7);
+ _vm->setHotspot(kHS06Ladder, 497, 222, 614, 492, SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 8);
+ _vm->setHotspot(kHS06Horse, 90, 226, 259, 376, SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 7);
+ _vm->setHotspot(kHS06ExitOutsideBarn, 226, 580, 688, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 10);
+ _vm->setHotspot(kHS06WalkArea1, 0, 0, 200, 515);
+ _vm->setHotspot(kHS06WalkArea2, 200, 0, 285, 499);
+ _vm->setHotspot(kHS06WalkArea3, 688, 0, 800, 499);
+ _vm->setHotspot(kHS06WalkArea4, 475, 469, 800, 505);
+ _vm->setHotspot(kHS06WalkArea5, 0, 0, 800, 504);
+ _vm->setDeviceHotspot(kHS06Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFGasTaken))
+ _vm->_hotspots[kHS06Ladder]._flags = SF_DISABLED;
+ if (_vm->_cursorValue == 4) {
+ _vm->_hotspots[kHS06Ladder]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS06Gas]._flags = SF_DISABLED;
+ }
+ _vm->_hotspotsCount = 11;
+}
+
+void Scene06::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ bool triedDeviceOnGas = false;
+
+ _vm->startSoundTimerC(7);
+
+ _horseTurnedBack = false;
+ gameSys.insertSequence(0xF1, 120, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currHorseSequenceId = 0xF1;
+ _nextHorseSequenceId = -1;
+
+ gameSys.setAnimation(0xF1, 120, 2);
+ _vm->_timers[4] = _vm->getRandom(40) + 25;
+
+ if (_vm->isFlag(kGFUnk04))
+ gameSys.insertSequence(0xF7, 20, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0xF8, 20, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (!_vm->isFlag(kGFGasTaken) && _vm->_cursorValue != 4)
+ gameSys.insertSequence(0xFE, 20, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ gnap.initPos(5, 12, kDirBottomRight);
+ plat.initPos(6, 12, kDirIdleLeft);
+ _vm->endSceneInit();
+
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107B9, 1);
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 5, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS06Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS06Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemDisguise) {
+ gnap.useDisguiseOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFKeysTaken))
+ gnap.playMoan1(plat._pos);
+ else
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS06Gas:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 5, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(5, 0));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFUnk04)) {
+ gnap.playImpossible();
+ } else if (triedDeviceOnGas) {
+ _vm->_hotspots[kHS06WalkArea5]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[1], 0, 0x107BC, 1);
+ _vm->_hotspots[kHS06WalkArea5]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = kAS06TryToGetGas;
+ } else {
+ triedDeviceOnGas = true;
+ gnap.playPullOutDeviceNonWorking(_vm->_hotspotsWalkPos[1]);
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ if (_vm->isFlag(kGFUnk04))
+ gnap.playImpossible();
+ else
+ gnap.playScratchingHead(Common::Point(5, 0));
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS06Ladder:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 8, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(8, 4));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFGasTaken))
+ gnap.playImpossible();
+ else {
+ gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, 0x107BB, 1);
+ gnap._actionStatus = kAS06TryToClimbLadder;
+ _vm->setFlag(kGFGasTaken);
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS06Horse:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemTwig && _horseTurnedBack) {
+ _vm->_hotspots[kHS06WalkArea5]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, 0x107BC, 1);
+ _vm->_hotspots[kHS06WalkArea5]._flags &= ~SF_WALKABLE;
+ gnap._idleFacing = kDirUpLeft;
+ plat.walkTo(Common::Point(6, 8), 1, 0x107C2, 1);
+ plat._idleFacing = kDirIdleLeft;
+ gnap._actionStatus = kAS06UseTwigOnHorse;
+ _vm->setGrabCursorSprite(-1);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 3, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(3, 2));
+ break;
+ case TALK_CURSOR:
+ if (_horseTurnedBack) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(3, 2)) | 0x10000, 1);
+ } else {
+ gnap._idleFacing = kDirBottomLeft;
+ _vm->_hotspots[kHS06WalkArea5]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ _vm->_hotspots[kHS06WalkArea5]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = kAS06TalkToHorse;
+ }
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS06ExitOutsideBarn:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, 0x107AE, 1);
+ gnap._actionStatus = kAS06LeaveScene;
+ if (_vm->_cursorValue == 1)
+ _vm->_newSceneNum = 5;
+ else
+ _vm->_newSceneNum = 35;
+ }
+ break;
+
+ case kHS06WalkArea1:
+ case kHS06WalkArea2:
+ case kHS06WalkArea3:
+ case kHS06WalkArea4:
+ case kHS06WalkArea5:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0)
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(40) + 25;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextHorseSequenceId == -1) {
+ if (_horseTurnedBack) {
+ _nextHorseSequenceId = 0xF5;
+ } else {
+ switch (_vm->getRandom(5)) {
+ case 0:
+ case 1:
+ case 2:
+ _nextHorseSequenceId = 0xF1;
+ break;
+ case 3:
+ _nextHorseSequenceId = 0xF3;
+ break;
+ case 4:
+ _nextHorseSequenceId = 0xF4;
+ break;
+ }
+ }
+ }
+ }
+ _vm->playSoundC();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene06::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS06LeaveScene:
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ break;
+ case kAS06TryToGetGas:
+ gameSys.insertSequence(0xFC, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0xFC;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = -1;
+ break;
+ case kAS06TryToClimbLadder:
+ gameSys.insertSequence(0xFF, 20, 0xFE, 20, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0xFD, gnap._id, 0);
+ gameSys.insertSequence(0xFD, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0xFD;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS06TryToClimbLadderDone;
+ break;
+ case kAS06TryToClimbLadderDone:
+ gnap._pos = Common::Point(6, 7);
+ gnap._actionStatus = -1;
+ break;
+ case kAS06TalkToHorse:
+ _nextHorseSequenceId = 0xF6;
+ break;
+ case kAS06UseTwigOnHorse:
+ _nextPlatSequenceId = 0xFB;
+ break;
+ default:
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ if (plat._sequenceId == 0xFA) {
+ gameSys.setAnimation(0, 0, 1);
+ _vm->invAdd(kItemGas);
+ _vm->setFlag(kGFGasTaken);
+ _vm->_hotspots[kHS06Ladder]._flags = SF_DISABLED;
+ _vm->setGrabCursorSprite(kItemGas);
+ plat._actionStatus = -1;
+ plat._pos = Common::Point(6, 8);
+ gameSys.insertSequence(0x107C1, plat._id, 0, 0, kSeqNone, 0, 450 - plat._gridX, 384 - plat._gridY);
+ plat._sequenceId = 0x7C1;
+ plat._sequenceDatNum = 1;
+ _vm->setFlag(kGFUnk04);
+ gnap._actionStatus = -1;
+ _vm->showCursor();
+ }
+ if (_nextPlatSequenceId == 0xFB) {
+ gameSys.setAnimation(0, 0, 1);
+ _nextHorseSequenceId = 0xF2;
+ plat._actionStatus = 6;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2 && _nextHorseSequenceId != -1) {
+ switch (_nextHorseSequenceId) {
+ case 0xF2:
+ _vm->setGrabCursorSprite(-1);
+ _vm->hideCursor();
+ gameSys.setAnimation(0xFA, 256, 1);
+ gameSys.insertSequence(0xF2, 120, _currHorseSequenceId, 120, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x100, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0xF7, 20, 0xF8, 20, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0xFB, plat._id, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0xFA, 256, 0xFB, plat._id, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceId = 0xFA;
+ plat._sequenceDatNum = 0;
+ gameSys.insertSequence(0x107B7, gnap._id, 0x100, gnap._id,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = 0x7B7;
+ gnap._sequenceDatNum = 1;
+ _currHorseSequenceId = _nextHorseSequenceId;
+ _nextHorseSequenceId = -1;
+ _nextPlatSequenceId = -1;
+ _vm->invRemove(kItemTwig);
+ break;
+ case 0xF6:
+ gameSys.setAnimation(_nextHorseSequenceId, 120, 2);
+ gameSys.insertSequence(0xF6, 120, _currHorseSequenceId, 120, kSeqSyncWait, 0, 0, 0);
+ _horseTurnedBack = true;
+ _currHorseSequenceId = _nextHorseSequenceId;
+ _nextHorseSequenceId = -1;
+ gnap._actionStatus = -1;
+ break;
+ default:
+ gameSys.setAnimation(_nextHorseSequenceId, 120, 2);
+ gameSys.insertSequence(_nextHorseSequenceId, 120, _currHorseSequenceId, 120, kSeqSyncWait, 0, 0, 0);
+ _currHorseSequenceId = _nextHorseSequenceId;
+ _nextHorseSequenceId = -1;
+ break;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene07::Scene07(GnapEngine *vm) : Scene(vm) {
+}
+
+int Scene07::init() {
+ return 0x92;
+}
+
+void Scene07::updateHotspots() {
+ _vm->setHotspot(kHS07Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS07ExitHouse, 700, 125, 799, 290, SF_EXIT_NE_CURSOR);
+ _vm->setHotspot(kHS07Dice, 200, 290, 270, 360, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS07WalkArea1, 0, 0, 325, 445);
+ _vm->setHotspot(kHS07WalkArea2, 325, 0, 799, 445, _vm->_isLeavingScene ? SF_WALKABLE : SF_NONE);
+ _vm->setHotspot(kHS07WalkArea3, 160, 0, 325, 495);
+ _vm->setDeviceHotspot(kHS07Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS07Dice]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 7;
+}
+
+void Scene07::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+ gameSys.insertSequence(0x8C, 1, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x90, 1, 0, 0, kSeqLoop, 0, 0, 0);
+
+ _vm->invRemove(kItemGas);
+ _vm->invRemove(kItemNeedle);
+
+ if (!_vm->isFlag(kGFPlatypus))
+ gameSys.insertSequence(0x8D, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->_prevSceneNum == 8) {
+ gnap.initPos(7, 7, kDirBottomLeft);
+ plat.initPos(9, 7, kDirIdleRight);
+ _vm->endSceneInit();
+ } else {
+ gnap._pos = Common::Point(6, 7);
+ gnap._id = 140;
+ gnap._sequenceId = 0x8F;
+ gnap._sequenceDatNum = 0;
+ gnap._idleFacing = kDirBottomRight;
+ gameSys.insertSequence(0x8F, 140, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0);
+ gnap._actionStatus = kAS07Wait;
+ plat._pos = Common::Point(3, 8);
+ plat._id = 160;
+ plat._sequenceId = 0x91;
+ plat._sequenceDatNum = 0;
+ plat._idleFacing = kDirIdleLeft;
+ gameSys.insertSequence(0x91, 160, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+ }
+
+ _vm->_timers[3] = 600;
+ _vm->_timers[4] = _vm->getRandom(40) + 50;
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x10919))
+ _vm->playSound(0x10919, true);
+
+ if (_vm->testWalk(0, 1, 8, 7, 6, 7))
+ updateHotspots();
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS07Platypus:
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ break;
+ }
+ break;
+
+ case kHS07ExitHouse:
+ _vm->_isLeavingScene = true;
+ if (gnap._pos.x > 8)
+ gnap.walkTo(Common::Point(gnap._pos.x, 7), 0, 0x107AD, 1);
+ else
+ gnap.walkTo(Common::Point(8, 7), 0, 0x107AD, 1);
+ gnap._actionStatus = kAS07LeaveScene;
+ break;
+
+ case kHS07Dice:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(4, 8), 3, 3);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ break;
+ case GRAB_CURSOR:
+ _vm->setFlag(kGFPlatypus);
+ _vm->invAdd(kItemDice);
+ updateHotspots();
+ gnap.playPullOutDevice(Common::Point(3, 3));
+ gameSys.setAnimation(0x8E, 1, 2);
+ gameSys.insertSequence(0x8E, 1, 141, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(gnap.getSequenceId(kGSUseDevice, Common::Point(0, 0)) | 0x10000, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = gnap.getSequenceId(kGSUseDevice, Common::Point(0, 0));
+ gnap._sequenceDatNum = 1;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS07Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(40) + 50;
+ }
+ break;
+
+ case kHS07WalkArea1:
+ case kHS07WalkArea2:
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ case kHS07WalkArea3:
+ // Nothing
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ gnap.updateIdleSequence();
+ if (plat._actionStatus < 0 && gnap._actionStatus < 0) {
+ if (_vm->_timers[0]) {
+ if (!_vm->_timers[1]) {
+ _vm->_timers[1] = _vm->getRandom(20) + 30;
+ int gnapRandomValue = _vm->getRandom(20);
+ if (plat._idleFacing != kDirIdleLeft) {
+ if (gnapRandomValue == 0 && plat._sequenceId == 0x7CA)
+ plat.playSequence(0x107CC);
+ else if (gnapRandomValue == 1 && plat._sequenceId == 0x7CA)
+ plat.playSequence(0x10845);
+ else if (plat._pos.y == 9)
+ plat.playSequence(0x107CA);
+ } else if (gnapRandomValue == 0 && plat._sequenceId == 0x7C9)
+ plat.playSequence(0x107CB);
+ else if (gnapRandomValue == 1 && plat._sequenceId == 0x7C9)
+ plat.playSequence(0x10844);
+ else if (plat._pos.y == 9)
+ plat.playSequence(0x107C9);
+ gameSys.setAnimation(plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, 1);
+ }
+ } else {
+ _vm->_timers[0] = _vm->getRandom(75) + 75;
+ plat.makeRoom();
+ }
+ } else {
+ _vm->_timers[0] = 100;
+ _vm->_timers[1] = 35;
+ }
+ playRandomSound(4);
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(40) + 50;
+ }
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene07::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS07LeaveScene:
+ _vm->_newSceneNum = 8;
+ _vm->_sceneDone = true;
+ break;
+ }
+ gnap._actionStatus = -1;
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ gameSys.setAnimation(0, 0, 2);
+ _vm->setGrabCursorSprite(kItemDice);
+ }
+}
+
+/*****************************************************************************/
+
+Scene08::Scene08(GnapEngine *vm) : Scene(vm) {
+ _nextDogSequenceId = -1;
+ _currDogSequenceId = -1;
+ _nextManSequenceId = -1;
+ _currManSequenceId = -1;
+}
+
+int Scene08::init() {
+ return 0x150;
+}
+
+void Scene08::updateHotspots() {
+ _vm->setHotspot(kH08SPlatypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS08ExitBackdoor, 0, 280, 10, 400, SF_EXIT_L_CURSOR | SF_WALKABLE);
+ _vm->setHotspot(kHS08ExitCrash, 200, 590, 400, 599, SF_EXIT_D_CURSOR | SF_WALKABLE);
+ _vm->setHotspot(kHS08Man, 510, 150, 610, 380, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS08Door, 350, 170, 500, 410, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS08Meat, 405, 450, 480, 485, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS08Bone, 200, 405, 270, 465, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS08Toy, 540, 430, 615, 465, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS08WalkArea1, 290, 340, -1, -1);
+ _vm->setHotspot(kHS08WalkArea2, 0, 0, 799, 420);
+ _vm->setDeviceHotspot(kHS08Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFBarnPadlockOpen))
+ _vm->_hotspots[kHS08Meat]._flags = SF_WALKABLE | SF_DISABLED;
+ if (_vm->isFlag(kGFTruckFilledWithGas))
+ _vm->_hotspots[kHS08Bone]._flags = SF_WALKABLE | SF_DISABLED;
+ if (_vm->isFlag(kGFTruckKeysUsed))
+ _vm->_hotspots[kHS08Toy]._flags = SF_WALKABLE | SF_DISABLED;
+ _vm->_hotspotsCount = 11;
+}
+
+void Scene08::updateAnimationsCb() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ gameSys.setAnimation(_nextDogSequenceId, 100, 3);
+ gameSys.insertSequence(_nextDogSequenceId, 100, _currDogSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ _currDogSequenceId = _nextDogSequenceId;
+ if ( _nextDogSequenceId != 0x135 )
+ _nextDogSequenceId = 0x134;
+ }
+}
+
+void Scene08::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+
+ gameSys.insertSequence(0x14F, 1, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x14E, 256, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currDogSequenceId = 0x135;
+ _nextDogSequenceId = 0x135;
+
+ gameSys.setAnimation(0x135, 100, 3);
+ gameSys.insertSequence(_currDogSequenceId, 100, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currManSequenceId = 0x140;
+ _nextManSequenceId = -1;
+
+ gameSys.setAnimation(0x140, 100, 2);
+ gameSys.insertSequence(_currManSequenceId, 100, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->_timers[4] = _vm->getRandom(50) + 75;
+
+ if (!_vm->isFlag(kGFBarnPadlockOpen))
+ gameSys.insertSequence(0x144, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (!_vm->isFlag(kGFTruckFilledWithGas))
+ gameSys.insertSequence(0x145, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (!_vm->isFlag(kGFTruckKeysUsed))
+ gameSys.insertSequence(0x146, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ gnap.initPos(-1, 8, kDirBottomRight);
+ plat.initPos(-1, 7, kDirIdleLeft);
+
+ _vm->endSceneInit();
+
+ gnap.walkTo(Common::Point(1, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(1, 7), -1, 0x107C2, 1);
+
+ _vm->_timers[5] = _vm->getRandom(40) + 50;
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x10919))
+ _vm->playSound(0x10919, true);
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS08Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(50) + 75;
+ _vm->_timers[5] = _vm->getRandom(40) + 50;
+ }
+ break;
+
+ case kH08SPlatypus:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFSceneFlag1))
+ gnap.playMoan1(plat._pos);
+ else
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.actionIdle(0x14D);
+ gnap.kissPlatypus(8);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ break;
+ }
+ }
+ break;
+
+ case kHS08ExitBackdoor:
+ _vm->_isLeavingScene = true;
+ gnap.actionIdle(0x14D);
+ gnap.walkTo(Common::Point(0, 6), 0, 0x107AF, 1);
+ gnap._actionStatus = kAS08LeaveScene;
+ plat.walkTo(Common::Point(0, 7), 1, 0x107CF, 1);
+ _vm->_newSceneNum = 9;
+ break;
+
+ case kHS08ExitCrash:
+ _vm->_isLeavingScene = true;
+ gnap.actionIdle(0x14D);
+ gnap.walkTo(Common::Point(3, 9), 0, 0x107AE, 1);
+ gnap._actionStatus = kAS08LeaveScene;
+ plat.walkTo(Common::Point(4, 9), 1, 0x107C1, 1);
+ _vm->_newSceneNum = 7;
+ break;
+
+ case kHS08Man:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(6, 6), 7, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.actionIdle(0x14D);
+ gnap.walkTo(Common::Point(6, 6), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS08LookMan;
+ gnap._idleFacing = kDirUpRight;
+ break;
+ case GRAB_CURSOR:
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.actionIdle(0x14D);
+ gnap.walkTo(Common::Point(8, 6), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS08TalkMan;
+ break;
+ case PLAT_CURSOR:
+ gnap.actionIdle(0x14D);
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(Common::Point(6, 6), 1, 0x107C2, 1);
+ plat._actionStatus = kAS08PlatWithMan;
+ plat._idleFacing = kDirIdleLeft;
+ gnap.playIdle(Common::Point(6, 6));
+ break;
+ }
+ }
+ break;
+
+ case kHS08Door:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(4, 7), 5, 0);
+ gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0);
+ gnap._actionStatus = kAS08GrabDog;
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(6, 0));
+ gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0);
+ gnap._actionStatus = kAS08LookDog;
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(Common::Point(4, 7), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS08GrabDog;
+ gnap._idleFacing = kDirUpRight;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.actionIdle(0x14D);
+ gnap.walkTo(Common::Point(4, 7), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS08TalkDog;
+ break;
+ case PLAT_CURSOR:
+ _vm->setFlag(kGFSceneFlag1);
+ gnap.actionIdle(0x14D);
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(Common::Point(3, 7), 1, 0x107C2, 1);
+ plat._actionStatus = kAS08PlatWithDog;
+ plat._idleFacing = kDirIdleLeft;
+ gnap.playIdle(Common::Point(3, 7));
+ break;
+ }
+ }
+ break;
+
+ case kHS08Meat:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(6, 8), 5, 6);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(6, 7));
+ break;
+ case GRAB_CURSOR:
+ if (_currDogSequenceId == 0x135) {
+ gnap.playScratchingHead(Common::Point(6, 7));
+ } else {
+ gnap.actionIdle(0x14D);
+ gnap.playPullOutDevice(Common::Point(6, 7));
+ gnap.playUseDevice();
+ _nextDogSequenceId = 0x149;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS08Bone:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(2, 7), 3, 6);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(3, 6));
+ break;
+ case GRAB_CURSOR:
+ if (_currDogSequenceId == 0x135) {
+ gnap.playScratchingHead(Common::Point(3, 6));
+ } else {
+ gnap.actionIdle(0x14D);
+ gnap.playPullOutDevice(Common::Point(3, 6));
+ gnap.playUseDevice();
+ _nextDogSequenceId = 0x14A;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS08Toy:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(8, 7), 7, 6);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(7, 6));
+ break;
+ case GRAB_CURSOR:
+ if (_currDogSequenceId == 0x135) {
+ gnap.playScratchingHead(Common::Point(7, 6));
+ } else {
+ gnap.actionIdle(0x14D);
+ gnap.playPullOutDevice(Common::Point(7, 6));
+ gnap.playUseDevice();
+ _nextDogSequenceId = 0x14B;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS08WalkArea1:
+ case kHS08WalkArea2:
+ gnap.actionIdle(0x14D);
+ gnap.walkTo(Common::Point(-1, 6), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.actionIdle(0x14D);
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(50) + 125;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextManSequenceId == -1 &&
+ (_currDogSequenceId == 0x134 || _currDogSequenceId == 0x135)) {
+ int _gnapRandomValue = _vm->getRandom(4);
+ switch (_gnapRandomValue) {
+ case 0:
+ _nextManSequenceId = 0x138;
+ break;
+ case 1:
+ _nextManSequenceId = 0x136;
+ break;
+ case 2:
+ _nextManSequenceId = 0x13B;
+ break;
+ case 3:
+ _nextManSequenceId = 0x13A;
+ break;
+ }
+ }
+ }
+ playRandomSound(5);
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(50) + 75;
+ _vm->_timers[5] = _vm->getRandom(40) + 50;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene08::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS08LeaveScene:
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ break;
+ case kAS08TalkMan:
+ _nextManSequenceId = 0x13F;
+ gnap._actionStatus = -1;
+ break;
+ case kAS08LookMan:
+ _nextManSequenceId = 0x140;
+ gnap._actionStatus = -1;
+ break;
+ case kAS08LookDog:
+ _nextManSequenceId = 0x137;
+ gnap._actionStatus = -1;
+ break;
+ case kAS08GrabDog:
+ if (_currDogSequenceId == 0x135)
+ _nextDogSequenceId = 0x133;
+ else
+ _nextDogSequenceId = 0x13C;
+ gnap._actionStatus = -1;
+ break;
+ case kAS08TalkDog:
+ if (_currDogSequenceId == 0x135)
+ _nextDogSequenceId = 0x133;
+ else
+ _nextDogSequenceId = 0x13C;
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ switch (plat._actionStatus) {
+ case kAS08PlatWithDog:
+ _nextDogSequenceId = 0x147;
+ break;
+ case kAS08PlatWithMan:
+ _nextManSequenceId = 0x140;
+ plat._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2 && _nextManSequenceId != -1) {
+ gameSys.setAnimation(_nextManSequenceId, 100, 2);
+ gameSys.insertSequence(_nextManSequenceId, 100, _currManSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ _currManSequenceId = _nextManSequenceId;
+ _nextManSequenceId = -1;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ if (_currDogSequenceId == 0x147)
+ plat._actionStatus = -1;
+ if (_currDogSequenceId == 0x149 || _currDogSequenceId == 0x14A || _currDogSequenceId == 0x14B) {
+ if (_vm->getRandom(2) != 0)
+ _nextManSequenceId = 0x13D;
+ else
+ _nextManSequenceId = 0x13E;
+ } else if (_currDogSequenceId == 0x133)
+ _nextManSequenceId = 0x139;
+ if (_nextDogSequenceId == 0x149 || _nextDogSequenceId == 0x14A || _nextDogSequenceId == 0x14B) {
+ gameSys.setAnimation(_nextDogSequenceId, 100, 3);
+ gameSys.insertSequence(_nextDogSequenceId, 100, _currDogSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ switch (_nextDogSequenceId) {
+ case 0x149:
+ _vm->setFlag(kGFBarnPadlockOpen);
+ _vm->_hotspots[kHS08Meat]._flags = SF_DISABLED | SF_WALKABLE;
+ gameSys.removeSequence(0x144, 1, true);
+ break;
+ case 0x14A:
+ _vm->setFlag(kGFTruckFilledWithGas);
+ _vm->_hotspots[kHS08Bone]._flags = SF_DISABLED | SF_WALKABLE;
+ gameSys.removeSequence(0x145, 1, true);
+ break;
+ case 0x14B:
+ _vm->setFlag(kGFTruckKeysUsed);
+ _vm->_hotspots[kHS08Toy]._flags = SF_DISABLED | SF_WALKABLE;
+ gameSys.removeSequence(0x146, 1, true);
+ break;
+ }
+ _currDogSequenceId = _nextDogSequenceId;
+ _nextDogSequenceId = 0x134;
+ } else if (_nextDogSequenceId == 0x147) {
+ gameSys.setAnimation(_nextDogSequenceId, 100, 3);
+ gameSys.insertSequence(_nextDogSequenceId, 100, _currDogSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x148, 160, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0);
+ _currDogSequenceId = _nextDogSequenceId;
+ _nextDogSequenceId = 0x134;
+ plat._pos = Common::Point(1, 8);
+ plat._id = 160;
+ plat._sequenceId = 0x148;
+ plat._idleFacing = kDirIdleRight;
+ plat._sequenceDatNum = 0;
+ if (gnap._pos == Common::Point(1, 8))
+ gnap.walkStep();
+ } else if (_nextDogSequenceId != -1) {
+ gameSys.setAnimation(_nextDogSequenceId, 100, 3);
+ gameSys.insertSequence(_nextDogSequenceId, 100, _currDogSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ _currDogSequenceId = _nextDogSequenceId;
+ if (_nextDogSequenceId != 0x135)
+ _nextDogSequenceId = 0x134;
+ if (_currDogSequenceId == 0x133) {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ gameSys.insertSequence(0x14D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x14D;
+ gnap._idleFacing = kDirUpRight;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = -1;
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene09::Scene09(GnapEngine *vm) : Scene(vm) {
+}
+
+int Scene09::init() {
+ return 0x4E;
+}
+
+void Scene09::updateHotspots() {
+ _vm->setHotspot(kHS09Platypus, 0, 200, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS09ExitKitchen, 280, 200, 380, 400, SF_EXIT_U_CURSOR);
+ _vm->setHotspot(kHS09ExitHouse, 790, 200, 799, 450, SF_EXIT_R_CURSOR | SF_WALKABLE);
+ _vm->setHotspot(kHS09Trash, 440, 310, 680, 420, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS09WalkArea1, 0, 0, 799, 400);
+ _vm->setHotspot(kHS09WalkArea2, 0, 0, 630, 450);
+ _vm->setHotspot(kHS09WalkArea2, 0, 0, 175, 495);
+ _vm->setDeviceHotspot(kHS09Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 8;
+}
+
+void Scene09::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+
+ gameSys.insertSequence(0x4D, 1, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x4B, 2, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->_prevSceneNum == 8) {
+ gnap.initPos(11, 8, kDirBottomLeft);
+ plat.initPos(12, 7, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(9, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 7), -1, 0x107D2, 1);
+ } else {
+ gnap.initPos(4, 7, kDirBottomRight);
+ plat.initPos(5, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ }
+
+ _vm->_timers[4] = _vm->getRandom(150) + 50;
+ _vm->_timers[5] = _vm->getRandom(40) + 50;
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x10919))
+ _vm->playSound(0x10919, true);
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS09Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(150) + 50;
+ _vm->_timers[5] = _vm->getRandom(40) + 50;
+ }
+ break;
+
+ case kHS09Platypus:
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ break;
+ }
+ break;
+
+ case kHS09ExitKitchen:
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 10;
+ gnap.walkTo(Common::Point(4, 7), 0, 0x107BF, 1);
+ gnap._actionStatus = kAS09LeaveScene;
+ plat.walkTo(Common::Point(4, 8), -1, 0x107D2, 1);
+ plat._idleFacing = kDirIdleRight;
+ break;
+
+ case kHS09ExitHouse:
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 8;
+ gnap.walkTo(Common::Point(10, -1), 0, 0x107AB, 1);
+ gnap._actionStatus = kAS09LeaveScene;
+ plat.walkTo(Common::Point(10, -1), -1, 0x107CD, 1);
+ plat._idleFacing = kDirIdleRight;
+ break;
+
+ case kHS09Trash:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(9, 6), 8, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(8, 3));
+ break;
+ case GRAB_CURSOR:
+ gnap._actionStatus = kAS09SearchTrash;
+ gnap.walkTo(Common::Point(9, 6), 0, 0x107BC, 1);
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS09WalkArea1:
+ case kHS09WalkArea2:
+ case kHS09WalkArea3:
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene && gnap._actionStatus != 1 && gnap._actionStatus != 2) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(150) + 100;
+ if (_vm->_timers[4] & 1)
+ gameSys.insertSequence(0x49, 1, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x4A, 1, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ playRandomSound(5);
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(150) + 50;
+ _vm->_timers[5] = _vm->getRandom(40) + 50;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene09::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS09LeaveScene:
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ break;
+ case kAS09SearchTrash:
+ gameSys.setAnimation(0x4C, 120, 0);
+ gameSys.insertSequence(0x4C, 120, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(0x4B, 2, true);
+ gnap._sequenceId = 0x4C;
+ gnap._id = 120;
+ gnap._idleFacing = kDirUpLeft;
+ gnap._sequenceDatNum = 0;
+ gnap._pos = Common::Point(9, 6);
+ gnap._actionStatus = kAS09SearchTrashDone;
+ break;
+ case kAS09SearchTrashDone:
+ gameSys.insertSequence(0x4B, 2, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_timers[2] = 360;
+ _vm->_timers[4] = _vm->getRandom(150) + 100;
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/group0.h b/engines/gnap/scenes/group0.h
new file mode 100644
index 0000000000..e06380926d
--- /dev/null
+++ b/engines/gnap/scenes/group0.h
@@ -0,0 +1,401 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 GNAP_GROUP0_H
+#define GNAP_GROUP0_H
+
+#include "gnap/debugger.h"
+
+namespace Gnap {
+
+enum {
+ kHS01Platypus = 0,
+ kHS01ExitTruck = 1,
+ kHS01Mud = 2,
+ kHS01Pigs = 3,
+ kHS01Spaceship = 4,
+ kHS01Device = 5,
+ kHS01WalkArea1 = 6,
+ kHS01WalkArea2 = 7,
+ kHS01WalkArea3 = 8,
+ kHS01WalkArea4 = 9,
+ kHS01WalkArea5 = 10,
+ kHS01WalkArea6 = 11,
+ kHS01WalkArea7 = 12,
+ kHS01WalkArea8 = 13
+};
+
+enum {
+ kHS02Platypus = 0,
+ kHS02Chicken = 1,
+ kHS02Truck1 = 2,
+ kHS02Truck2 = 3,
+ kHS02TruckGrill = 4,
+ kHS02Device = 5,
+ kHS02ExitHouse = 6,
+ kHS02ExitBarn = 7,
+ kHS02ExitCreek = 8,
+ kHS02ExitPigpen = 9,
+ kHS02WalkArea1 = 10,
+ kHS02WalkArea2 = 11,
+ kHS02WalkArea3 = 12,
+ kHS02WalkArea4 = 13
+};
+
+enum {
+ kHS03Platypus = 0,
+ kHS03Grass = 1,
+ kHS03ExitTruck = 2,
+ kHS03Creek = 3,
+ kHS03TrappedPlatypus = 4,
+ kHS03Device = 5,
+ kHS03WalkAreas1 = 6,
+ kHS03WalkAreas2 = 7,
+ kHS03PlatypusWalkArea = 8,
+ kHS03WalkAreas3 = 9
+};
+
+enum {
+ kHS04Platypus = 0,
+ kHS04Twig = 1,
+ kHS04Dog = 2,
+ kHS04Axe = 3,
+ kHS04Door = 4,
+ kHS04ExitTruck = 5,
+ kHS04Device = 6,
+ kHS04Window = 7,
+ kHS04ExitBarn = 8,
+ kHS04WalkArea1 = 9,
+ kHS04WalkArea2 = 10
+};
+
+enum {
+ kHS05Platypus = 0,
+ kHS05Haystack = 1,
+ kHS05Padlock = 2,
+ kHS05Ladder = 3,
+ kHS05ExitHouse = 4,
+ kHS05Chicken = 5,
+ kHS05Device = 6,
+ kHS05WalkArea1 = 7,
+ kHS05WalkArea2 = 8,
+ kHS05WalkArea3 = 9
+};
+
+enum {
+ kHS06Platypus = 0,
+ kHS06Gas = 1,
+ kHS06Ladder = 2,
+ kHS06Horse = 3,
+ kHS06ExitOutsideBarn = 4,
+ kHS06Device = 5,
+ kHS06WalkArea1 = 6,
+ kHS06WalkArea2 = 7,
+ kHS06WalkArea3 = 8,
+ kHS06WalkArea4 = 9,
+ kHS06WalkArea5 = 10
+};
+
+enum {
+ kHS07Platypus = 0,
+ kHS07ExitHouse = 1,
+ kHS07Dice = 2,
+ kHS07Device = 3,
+ kHS07WalkArea1 = 4,
+ kHS07WalkArea2 = 5,
+ kHS07WalkArea3 = 6
+};
+
+enum {
+ kH08SPlatypus = 0,
+ kHS08ExitBackdoor = 1,
+ kHS08ExitCrash = 2,
+ kHS08Man = 3,
+ kHS08Door = 4,
+ kHS08Meat = 5,
+ kHS08Bone = 6,
+ kHS08Toy = 7,
+ kHS08WalkArea1 = 8,
+ kHS08Device = 9,
+ kHS08WalkArea2 = 10
+};
+
+enum {
+ kHS09Platypus = 0,
+ kHS09ExitKitchen = 1,
+ kHS09ExitHouse = 2,
+ kHS09Trash = 3,
+ kHS09Device = 4,
+ kHS09WalkArea1 = 5,
+ kHS09WalkArea2 = 6,
+ kHS09WalkArea3 = 7
+};
+
+enum {
+ kAS01LookSpaceship = 1,
+ kAS01LookSpaceshipDone = 2,
+ kAS01LeaveScene = 3,
+ kAS01TakeMud = 5,
+ kAS01LookPigs = 6,
+ kAS01UsePigs = 7
+};
+
+enum {
+ kAS02UseTruckNoKeys = 0,
+ kAS02UseGasWithTruck = 1,
+ kAS02UseTruckGas = 2,
+ kAS02UseTruckNoGas = 3,
+ kAS02GrabTruckGrill = 5,
+ kAS02LeaveScene = 6,
+ kAS02TalkChicken = 7,
+ kAS02GrabChicken = 8,
+ kAS02GrabChickenDone = 9,
+ kAS02UseTruckNoKeysDone = 11,
+ kAS02UseGasWithTruckDone = 12,
+ kAS02UseTwigWithChicken = 16
+};
+
+enum {
+ kAS03LeaveScene = 0,
+ kAS03FreePlatypus = 1,
+ kAS03HypnotizePlat = 2,
+ kAS03HypnotizeScaredPlat= 3,
+ kAS03FreePlatypusDone = 4,
+ kAS03GrabPlatypus = 5,
+ kAS03GrabCreek = 6,
+ kAS03GrabCreekDone = 7,
+ kAS03GrabScaredPlatypus = 8
+};
+
+enum {
+ kAS04OpenDoor = 1,
+ kAS04GetKeyFirst = 2,
+ kAS04GetKeyAnother = 3,
+ kAS04LeaveScene = 4,
+ kAS04GetKeyFirstDone = 6,
+ kAS04GetKeyFirst2 = 7,
+ kAS04GetKeyAnother2 = 8,
+ kAS04GetKeyAnotherDone = 9,
+ kAS04OpenDoorDone = 10,
+ kAS04GrabDog = 12,
+ kAS04GrabAxe = 13
+};
+
+enum {
+ kAS05PlatSearchHaystack = 0,
+ kAS05TryPickPadlock = 1,
+ kAS05PickPadlock = 2,
+ kAS05TalkChicken = 3,
+ kAS05GrabChicken = 4,
+ kAS05GrabLadder = 5,
+ kAS05EnterBarn = 6,
+ kAS05UseTwigWithChicken = 11,
+ kAS05LeaveScene = 12
+};
+
+enum {
+ kAS06TryToGetGas = 0,
+ kAS06TryToClimbLadder = 1,
+ kAS06TryToClimbLadderDone = 2,
+ kAS06TalkToHorse = 3,
+ kAS06UseTwigOnHorse = 4,
+ kAS06LeaveScene = 5
+};
+
+enum {
+ kAS07Wait = 0,
+ kAS07LeaveScene = 1
+};
+
+enum {
+ kAS08LeaveScene = 0,
+ kAS08TalkMan = 1,
+ kAS08LookMan = 2,
+ kAS08LookDog = 3,
+ kAS08GrabDog = 4,
+ kAS08TalkDog = 5,
+ kAS08PlatWithMan = 6,
+ kAS08PlatWithDog = 7
+};
+
+enum {
+ kAS09LeaveScene = 0,
+ kAS09SearchTrash = 1,
+ kAS09SearchTrashDone = 2
+};
+
+/*****************************************************************************/
+
+class GnapEngine;
+class CutScene;
+
+class Scene01: public Scene {
+public:
+ Scene01(GnapEngine *vm);
+ virtual ~Scene01();
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {}
+
+private:
+ int _pigsIdCtr;
+ int _smokeIdCtr;
+ Graphics::Surface *_spaceshipSurface;
+};
+
+class Scene02: public Scene {
+public:
+ Scene02(GnapEngine *vm);
+ virtual ~Scene02() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {}
+
+private:
+ int _truckGrillCtr;
+ int _nextChickenSequenceId;
+ int _currChickenSequenceId;
+ int _gnapTruckSequenceId;
+};
+
+class Scene03: public Scene {
+public:
+ Scene03(GnapEngine *vm);
+ virtual ~Scene03() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {}
+
+private:
+ bool _platypusHypnotized;
+ bool _platypusScared;
+ int _nextPlatSequenceId;
+ int _nextFrogSequenceId;
+ int _currFrogSequenceId;
+};
+
+class Scene04: public Scene {
+public:
+ Scene04(GnapEngine *vm);
+ virtual ~Scene04() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {}
+
+private:
+ bool _triedWindow;
+ int _dogIdCtr;
+ int _nextDogSequenceId;
+ int _currDogSequenceId;
+};
+
+class Scene05: public Scene {
+public:
+ Scene05(GnapEngine *vm);
+ virtual ~Scene05() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {}
+
+private:
+ int _nextChickenSequenceId;
+ int _currChickenSequenceId;
+};
+
+class Scene06: public Scene {
+public:
+ Scene06(GnapEngine *vm);
+ virtual ~Scene06() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {}
+
+private:
+ bool _horseTurnedBack;
+ int _nextPlatSequenceId;
+ int _nextHorseSequenceId;
+ int _currHorseSequenceId;
+};
+
+class Scene07: public Scene {
+public:
+ Scene07(GnapEngine *vm);
+ virtual ~Scene07() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {}
+};
+
+class Scene08: public Scene {
+public:
+ Scene08(GnapEngine *vm);
+ virtual ~Scene08() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb();
+
+private:
+ int _nextDogSequenceId;
+ int _currDogSequenceId;
+ int _nextManSequenceId;
+ int _currManSequenceId;
+};
+
+class Scene09: public Scene {
+public:
+ Scene09(GnapEngine *vm);
+ virtual ~Scene09() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {}
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_GROUP0_H
diff --git a/engines/gnap/scenes/group1.cpp b/engines/gnap/scenes/group1.cpp
new file mode 100644
index 0000000000..bd152c7f39
--- /dev/null
+++ b/engines/gnap/scenes/group1.cpp
@@ -0,0 +1,4500 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/group1.h"
+
+namespace Gnap {
+
+Scene10::Scene10(GnapEngine *vm) : Scene(vm) {
+ _nextCookSequenceId = -1;
+ _currCookSequenceId = -1;
+}
+
+int Scene10::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ return 0x10F;
+}
+
+void Scene10::updateHotspots() {
+ _vm->setHotspot(kHS10Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS10ExitBar, 0, 75, 85, 455, SF_EXIT_NW_CURSOR);
+ _vm->setHotspot(kHS10ExitBackdoor, 75, 590, 500, 599, SF_EXIT_D_CURSOR | SF_WALKABLE);
+ _vm->setHotspot(kHS10Cook, 370, 205, 495, 460, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS10Tongs, 250, 290, 350, 337, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS10Box, 510, 275, 565, 330, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS10Oven, 690, 280, 799, 420, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS10WalkArea1, 59, 0, 495, 460);
+ _vm->setHotspot(kHS10WalkArea2, 495, 0, 650, 420);
+ _vm->setHotspot(kHS10WalkArea3, 651, 0, 725, 400);
+ _vm->setHotspot(kHS10WalkArea4, 725, 0, 799, 441);
+ _vm->setDeviceHotspot(kHS10Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 12;
+}
+
+void Scene10::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _currCookSequenceId = 0x103;
+
+ gameSys.setAnimation(0x103, 100, 2);
+ gameSys.insertSequence(0x103, 100, 0, 0, kSeqNone, 0, 0, 0);
+
+ _nextCookSequenceId = 0x106;
+ if (!_vm->isFlag(kGFMudTaken))
+ gameSys.insertSequence(0x107, 100, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->_prevSceneNum == 9) {
+ gnap.initPos(11, 8, kDirBottomLeft);
+ plat.initPos(12, 7, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(9, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 7), -1, 0x107D2, 1);
+ } else {
+ gnap.initPos(-1, 7, kDirBottomRight);
+ plat.initPos(-2, 8, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(1, 7), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1);
+ }
+
+ _vm->_timers[4] = _vm->getRandom(80) + 150;
+ _vm->_timers[5] = _vm->getRandom(100) + 100;
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1091E))
+ _vm->playSound(0x1091E, true);
+
+ if (!_vm->isSoundPlaying(0x1091A))
+ _vm->playSound(0x1091A, true);
+
+ _vm->updateMouseCursor();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS10Platypus:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFMudTaken))
+ gnap.playMoan1(plat._pos);
+ else
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(10);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ break;
+ }
+ }
+ break;
+
+ case kHS10ExitBar:
+ _vm->_isLeavingScene = true;
+ gnap.actionIdle(0x10C);
+ gnap.walkTo(Common::Point(0, 7), 0, 0x107AF, 1);
+ gnap._actionStatus = kAS10LeaveScene;
+ plat.walkTo(Common::Point(0, 7), -1, 0x107CF, 1);
+ _vm->_newSceneNum = 11;
+ break;
+
+ case kHS10ExitBackdoor:
+ _vm->_isLeavingScene = true;
+ gnap.actionIdle(0x10C);
+ gnap.walkTo(Common::Point(2, 9), 0, 0x107AE, 1);
+ gnap._actionStatus = kAS10LeaveScene;
+ plat.walkTo(Common::Point(3, 9), -1, 0x107C7, 1);
+ _vm->_newSceneNum = 9;
+ break;
+
+ case kHS10Cook:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(4, 8), 6, 0);
+ gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0);
+ gnap._actionStatus = kAS10AnnoyCook;
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(6, 0));
+ break;
+ case GRAB_CURSOR:
+ gnap.playImpossible();
+ gnap._idleFacing = kDirBottomRight;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.actionIdle(0x10C);
+ gnap.walkTo(Common::Point(4, 8), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS10AnnoyCook;
+ break;
+ case PLAT_CURSOR:
+ gnap.actionIdle(0x10C);
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(Common::Point(4, 6), -1, -1, 1);
+ gnap.walkTo(Common::Point(4, 8), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS10AnnoyCook;
+ break;
+ }
+ }
+ break;
+
+ case kHS10Tongs:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(3, 7), 4, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFMudTaken))
+ gnap.playMoan2(Common::Point(-1, -1));
+ else
+ gnap.playScratchingHead(Common::Point(4, 3));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFMudTaken))
+ gnap.playMoan2(Common::Point(-1, -1));
+ else {
+ gnap.actionIdle(0x10C);
+ gnap.walkTo(Common::Point(4, 8), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS10AnnoyCook;
+ }
+ break;
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ case PLAT_CURSOR:
+ if (_vm->isFlag(kGFMudTaken))
+ gnap.playMoan2(Common::Point(-1, -1));
+ else {
+ gnap.actionIdle(0x10C);
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(Common::Point(3, 7), -1, -1, 1);
+ gnap.walkTo(Common::Point(4, 8), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS10AnnoyCook;
+ }
+ break;
+ }
+ }
+ break;
+
+ case kHS10Box:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(7, 6), 6, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(7, 3));
+ break;
+ case GRAB_CURSOR:
+ gnap.actionIdle(0x10C);
+ gnap.walkTo(Common::Point(4, 8), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS10AnnoyCook;
+ break;
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ case PLAT_CURSOR:
+ if (_vm->isFlag(kGFMudTaken))
+ gnap.playMoan2(Common::Point(-1, -1));
+ else {
+ _vm->invAdd(kItemTongs);
+ _vm->setFlag(kGFMudTaken);
+ gnap.actionIdle(0x10C);
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(Common::Point(7, 6), 1, 0x107D2, 1);
+ plat._actionStatus = kAS10PlatWithBox;
+ plat._idleFacing = kDirIdleRight;
+ _vm->_largeSprite = gameSys.createSurface(0xC3);
+ gnap.playIdle(Common::Point(7, 6));
+ }
+ break;
+ }
+ }
+ break;
+
+ case kHS10Oven:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(9, 6), 10, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playSequence(gnap.getSequenceId(kGSDeflect, Common::Point(10, 5)) | 0x10000);
+ break;
+ case GRAB_CURSOR:
+ gnap.actionIdle(0x10C);
+ gnap.walkTo(Common::Point(9, 6), 0, 0x107BB, 1);
+ gameSys.insertSequence(0x10E, 120, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x10E;
+ gnap._id = 120;
+ gnap._idleFacing = kDirUpRight;
+ gnap._sequenceDatNum = 0;
+ gnap._pos = Common::Point(9, 6);
+ _vm->_timers[2] = 360;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS10WalkArea1:
+ case kHS10WalkArea2:
+ case kHS10WalkArea3:
+ case kHS10WalkArea4:
+ gnap.actionIdle(0x10C);
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ case kHS10Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.actionIdle(0x10C);
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(80) + 150;
+ _vm->playSound(0x12B, false);
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(100) + 100;
+ int _gnapRandomValue = _vm->getRandom(4);
+ if (_gnapRandomValue) {
+ int sequenceId;
+ if (_gnapRandomValue == 1) {
+ sequenceId = 0x8A5;
+ } else if (_gnapRandomValue == 2) {
+ sequenceId = 0x8A6;
+ } else {
+ sequenceId = 0x8A7;
+ }
+ gameSys.insertSequence(sequenceId | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene10::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS10LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS10AnnoyCook:
+ _nextCookSequenceId = 0x105;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ switch (plat._actionStatus) {
+ case kAS10PlatWithBox:
+ _nextCookSequenceId = 0x109;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2 && _nextCookSequenceId != -1) {
+
+ switch (_nextCookSequenceId) {
+ case 0x109:
+ plat._pos = Common::Point(4, 8);
+ gameSys.insertSequence(0x109, 100, _currCookSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x107C9, 160,
+ plat._sequenceId | (plat._sequenceDatNum << 16), plat._id,
+ kSeqSyncWait, _vm->getSequenceTotalDuration(0x109) + _vm->getSequenceTotalDuration(0x10A) + _vm->getSequenceTotalDuration(0x10843),
+ 75 * plat._pos.x - plat._gridX, 48 * plat._pos.y - plat._gridY);
+ gameSys.removeSequence(0x107, 100, true);
+ _currCookSequenceId = 0x109;
+ _nextCookSequenceId = 0x843;
+ plat._sequenceId = 0x7C9;
+ plat._id = 160;
+ plat._idleFacing = kDirIdleLeft;
+ plat._sequenceDatNum = 1;
+ break;
+ case 0x843:
+ _vm->hideCursor();
+ gameSys.insertSpriteDrawItem(_vm->_largeSprite, 0, 0, 300);
+ gameSys.insertSequence(0x10843, 301, _currCookSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ _currCookSequenceId = 0x843;
+ _nextCookSequenceId = 0x10A;
+ break;
+ case 0x10A:
+ gameSys.insertSequence(_nextCookSequenceId, 100, 0x10843, 301, kSeqSyncWait, 0, 0, 0);
+ _currCookSequenceId = _nextCookSequenceId;
+ _nextCookSequenceId = 0x104;
+ _vm->showCursor();
+ gameSys.removeSpriteDrawItem(_vm->_largeSprite, 300);
+ _vm->delayTicksCursor(5);
+ _vm->deleteSurface(&_vm->_largeSprite);
+ _vm->setGrabCursorSprite(kItemTongs);
+ if (plat._actionStatus == kAS10PlatWithBox)
+ plat._actionStatus = -1;
+ if (gnap._pos == Common::Point(4, 8))
+ gnap.walkStep();
+ break;
+ default:
+ gameSys.insertSequence(_nextCookSequenceId, 100, _currCookSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ _currCookSequenceId = _nextCookSequenceId;
+ break;
+ }
+
+ switch (_currCookSequenceId) {
+ case 0x106:
+ if (gnap._actionStatus >= 0 || plat._actionStatus >= 0)
+ _nextCookSequenceId = 0x106;
+ else {
+ int rnd = _vm->getRandom(7);
+ switch (rnd) {
+ case 0:
+ _nextCookSequenceId = 0x104;
+ break;
+ case 1:
+ _nextCookSequenceId = 0x103;
+ break;
+ case 2:
+ _nextCookSequenceId = 0x106;
+ gameSys.insertSequence(0x10D, 1, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ default:
+ _nextCookSequenceId = 0x106;
+ }
+ }
+ break;
+ case 0x103:
+ if (gnap._actionStatus >= 0 || plat._actionStatus >= 0)
+ _nextCookSequenceId = 0x106;
+ else if (_vm->getRandom(7) == 0)
+ _nextCookSequenceId = 0x104;
+ else
+ _nextCookSequenceId = 0x106;
+ break;
+ case 0x104:
+ if (gnap._actionStatus >= 0 || plat._actionStatus >= 0)
+ _nextCookSequenceId = 0x106;
+ else if (_vm->getRandom(7) == 0)
+ _nextCookSequenceId = 0x103;
+ else
+ _nextCookSequenceId = 0x106;
+ break;
+ case 0x105:
+ if (gnap._actionStatus >= 0 || plat._actionStatus >= 0)
+ _nextCookSequenceId = 0x106;
+ else {
+ int rnd = _vm->getRandom(7);
+ switch (rnd) {
+ case 0:
+ _nextCookSequenceId = 0x104;
+ break;
+ case 1:
+ _nextCookSequenceId = 0x103;
+ break;
+ default:
+ _nextCookSequenceId = 0x106;
+ }
+ }
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = 300;
+ gameSys.insertSequence(0x10C, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x10C;
+ gnap._idleFacing = kDirUpRight;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = -1;
+ plat._actionStatus = -1;
+ break;
+ }
+ if (_currCookSequenceId == 0x843)
+ gameSys.setAnimation(_currCookSequenceId | 0x10000, 301, 2);
+ else
+ gameSys.setAnimation(_currCookSequenceId, 100, 2);
+ }
+}
+
+void Scene10::updateAnimationsCb() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ gameSys.setAnimation(_nextCookSequenceId, 100, 2);
+ gameSys.insertSequence(_nextCookSequenceId, 100, _currCookSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ _currCookSequenceId = _nextCookSequenceId;
+ _nextCookSequenceId = 0x106;
+ }
+}
+
+/*****************************************************************************/
+
+Scene11::Scene11(GnapEngine *vm) : Scene(vm) {
+ _billardBallCtr = 0;
+ _nextHookGuySequenceId = -1;
+ _currHookGuySequenceId = -1;
+ _nextGoggleGuySequenceId = -1;
+ _currGoggleGuySequenceId = -1;
+}
+
+int Scene11::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 3);
+ gameSys.setAnimation(0, 0, 2);
+ if (_vm->_prevSceneNum == 10 || _vm->_prevSceneNum == 13) {
+ _vm->playSound(0x108EC, false);
+ _vm->playSound(0x10928, false);
+ }
+ return 0x209;
+}
+
+void Scene11::updateHotspots() {
+ _vm->setHotspot(kHS11Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS11ExitKitchen, 420, 140, 520, 345, SF_EXIT_U_CURSOR);
+ _vm->setHotspot(kHS11ExitToilet, 666, 130, 740, 364, SF_EXIT_R_CURSOR);
+ _vm->setHotspot(kHS11ExitLeft, 0, 350, 10, 599, SF_EXIT_L_CURSOR | SF_WALKABLE);
+ _vm->setHotspot(kHS11GoggleGuy, 90, 185, 185, 340, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS11HookGuy, 210, 240, 340, 430, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS11Billard, 640, 475, 700, 530, SF_WALKABLE | SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS11WalkArea1, 0, 0, 365, 453);
+ _vm->setHotspot(kHS11WalkArea2, 0, 0, 629, 353);
+ _vm->setHotspot(kHS11WalkArea3, 629, 0, 799, 364);
+ _vm->setHotspot(kHS11WalkArea4, 735, 0, 799, 397);
+ _vm->setHotspot(kHS11WalkArea5, 510, 540, 799, 599);
+ _vm->setDeviceHotspot(kHS11Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 13;
+}
+
+void Scene11::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ bool flag = true;
+
+ _vm->_timers[7] = 50;
+ _vm->_hotspots[kHS11Billard]._flags |= SF_DISABLED;
+
+ _currGoggleGuySequenceId = 0x1F9;
+ _currHookGuySequenceId = 0x201;
+
+ switch (_vm->_prevSceneNum) {
+ case 13:
+ gnap.initPos(8, 5, kDirBottomLeft);
+ plat.initPos(9, 6, kDirIdleRight);
+ break;
+ case 47:
+ gnap.initPos(8, 5, kDirBottomLeft);
+ plat.initPos(9, 5, kDirIdleRight);
+ _currGoggleGuySequenceId = 0x1FA;
+ _currHookGuySequenceId = 0x1FF;
+ _vm->_timers[7] = 180;
+ break;
+ case 12:
+ gnap.initPos(-1, 9, kDirBottomRight);
+ plat.initPos(-2, 8, kDirIdleLeft);
+ break;
+ default:
+ gnap.initPos(6, 6, kDirBottomLeft);
+ plat.initPos(6, 5, kDirIdleRight);
+ break;
+ }
+
+ _vm->queueInsertDeviceIcon();
+
+ gameSys.insertSequence(_currHookGuySequenceId, 120, 0, 0, kSeqNone, 0, 0, 0);
+
+ _nextHookGuySequenceId = -1;
+
+ gameSys.setAnimation(_currHookGuySequenceId, 120, 3);
+ gameSys.insertSequence(_currGoggleGuySequenceId, 121, 0, 0, kSeqNone, 0, 0, 0);
+
+ _nextGoggleGuySequenceId = -1;
+
+ gameSys.setAnimation(_currGoggleGuySequenceId, 121, 2);
+
+ _vm->_timers[5] = _vm->getRandom(100) + 75;
+ _vm->_timers[4] = _vm->getRandom(40) + 20;
+ _vm->_timers[6] = _vm->getRandom(100) + 100;
+ _vm->endSceneInit();
+
+ if (_vm->_prevSceneNum == 12) {
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1);
+ }
+
+ gameSys.insertSequence(0x208, 256, 0, 0, kSeqNone, 40, 0, 0);
+
+ while (!_vm->_sceneDone) {
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS11Platypus:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ break;
+ }
+ }
+ break;
+
+ case kHS11ExitKitchen:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(6, 5), 0, 0x107BF, 1);
+ gnap._actionStatus = kAS11LeaveScene;
+ plat.walkTo(Common::Point(6, 6), -1, -1, 1);
+ _vm->_newSceneNum = 10;
+ break;
+
+ case kHS11ExitToilet:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(8, 5), 0, 0x107BF, 1);
+ gnap._actionStatus = kAS11LeaveScene;
+ plat.walkTo(Common::Point(8, 6), -1, -1, 1);
+ _vm->_newSceneNum = 13;
+ break;
+
+ case kHS11ExitLeft:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(-1, 8), 0, 0x107AF, 1);
+ gnap._actionStatus = kAS11LeaveScene;
+ plat.walkTo(Common::Point(-1, 9), -1, 0x107CF, 1);
+ _vm->_newSceneNum = 12;
+ break;
+
+ case kHS11GoggleGuy:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemMagazine) {
+ gnap.walkTo(Common::Point(3, 7), 0, 0x107BC, 1);
+ gnap._actionStatus = kAS11ShowMagazineToGoggleGuy;
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 2, 0);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(3, 7), 2, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(1, 6));
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(Common::Point(3, 7), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS11TalkGoggleGuy;
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS11HookGuy:
+ if (gnap._actionStatus < 0) {
+ gnap._idleFacing = kDirUpRight;
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.walkTo(Common::Point(5, 6), 0, 0x107BC, 9);
+ gnap._actionStatus = kAS11ShowItemToHookGuy;
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 4, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playSequence(gnap.getSequenceId(kGSDeflect, Common::Point(3, 6)) | 0x10000);
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(Common::Point(5, 6), 0, 0x107BC, 1);
+ gnap._actionStatus = kAS11GrabHookGuy;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirBottomLeft;
+ gnap.walkTo(Common::Point(5, 6), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS11TalkHookGuy;
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS11Billard:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(Common::Point(9, 8));
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(9, 8));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(Common::Point(9, 8), 0, 0x107BA, 1);
+ gnap._actionStatus = kAS11GrabBillardBall;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible(Common::Point(9, 8));
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS11WalkArea1:
+ case kHS11WalkArea2:
+ case kHS11WalkArea3:
+ case kHS11WalkArea4:
+ case kHS11WalkArea5:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ case kHS11Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ if (flag && !_vm->_timers[7]) {
+ flag = false;
+ gameSys.setAnimation(0x207, 257, 4);
+ gameSys.insertSequence(0x207, 257, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ plat.updateIdleSequence2();
+ gnap.updateIdleSequence2();
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(100) + 75;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextGoggleGuySequenceId == -1) {
+ if (_vm->getRandom(2))
+ _nextGoggleGuySequenceId = 0x1F6;
+ else
+ _nextGoggleGuySequenceId = 0x1F9;
+ }
+ }
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(40) + 20;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextHookGuySequenceId == -1) {
+ if (_currHookGuySequenceId == 0x201) {
+ switch (_vm->getRandom(7)) {
+ case 0:
+ _nextHookGuySequenceId = 0x200;
+ break;
+ case 1:
+ _nextHookGuySequenceId = 0x205;
+ break;
+ case 2:
+ _nextHookGuySequenceId = 0x202;
+ break;
+ default:
+ _nextHookGuySequenceId = 0x201;
+ break;
+ }
+ } else {
+ _nextHookGuySequenceId = 0x201;
+ }
+ }
+ }
+ if (!_vm->_timers[6]) {
+ _vm->_timers[6] = _vm->getRandom(100) + 100;
+ int _gnapRandomValue = _vm->getRandom(3);
+ switch (_gnapRandomValue) {
+ case 0:
+ gameSys.insertSequence(0x8A5 | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 1:
+ gameSys.insertSequence(0x8A7 | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 2:
+ gameSys.insertSequence(0x8A6 | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[5] = _vm->getRandom(50) + 75;
+ _vm->_timers[4] = _vm->getRandom(40) + 20;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene11::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ if (gnap._actionStatus != kAS11GrabBillardBall)
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS11LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS11ShowMagazineToGoggleGuy:
+ _nextGoggleGuySequenceId = 0x1F7;
+ break;
+ case kAS11TalkGoggleGuy:
+ _nextGoggleGuySequenceId = 0x1FB;
+ break;
+ case kAS11GrabHookGuy:
+ _nextHookGuySequenceId = 0x204;
+ break;
+ case kAS11ShowItemToHookGuy:
+ _nextHookGuySequenceId = 0x203;
+ break;
+ case kAS11TalkHookGuy:
+ _nextHookGuySequenceId = 0x206;
+ break;
+ case kAS11GrabBillardBall:
+ if (gameSys.getAnimationStatus(2) == 2 && gameSys.getAnimationStatus(3) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ gameSys.insertSequence(0x1F4, 255, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x1F4;
+ gnap._id = 255;
+ gnap._sequenceDatNum = 0;
+ gameSys.removeSequence(0x207, 257, true);
+ gameSys.removeSequence(0x208, 256, true);
+ _nextGoggleGuySequenceId = 0x1F8;
+ _vm->_timers[5] = _vm->getRandom(100) + 75;
+ gameSys.insertSequence(_nextGoggleGuySequenceId, 121, _currGoggleGuySequenceId, 121, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextGoggleGuySequenceId, 121, 2);
+ _currGoggleGuySequenceId = _nextGoggleGuySequenceId;
+ _nextGoggleGuySequenceId = -1;
+ switch (_billardBallCtr) {
+ case 0:
+ _nextHookGuySequenceId = 0x1FC;
+ break;
+ case 1:
+ _nextHookGuySequenceId = 0x1FD;
+ break;
+ default:
+ _nextHookGuySequenceId = 0x1FE;
+ break;
+ }
+ ++_billardBallCtr;
+ gameSys.insertSequence(_nextHookGuySequenceId, 120, _currHookGuySequenceId, 120, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextHookGuySequenceId, 120, 3);
+ _currHookGuySequenceId = _nextHookGuySequenceId;
+ _nextHookGuySequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(40) + 20;
+ gameSys.insertSequence(0x208, 256, 0, 0, kSeqNone, _vm->getSequenceTotalDuration(0x1F4) - 5, 0, 0);
+ _vm->_hotspots[kHS11Billard]._flags |= SF_DISABLED;
+ gameSys.setAnimation(0x207, 257, 4);
+ gameSys.insertSequence(0x207, 257, 0, 0, kSeqNone, _vm->getSequenceTotalDuration(0x1FE), 0, 0);
+ gnap._actionStatus = -1;
+ }
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2 && _nextGoggleGuySequenceId != -1) {
+ _vm->_timers[5] = _vm->getRandom(100) + 75;
+ gameSys.insertSequence(_nextGoggleGuySequenceId, 121, _currGoggleGuySequenceId, 121, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextGoggleGuySequenceId, 121, 2);
+ _currGoggleGuySequenceId = _nextGoggleGuySequenceId;
+ _nextGoggleGuySequenceId = -1;
+ if (gnap._actionStatus >= 1 && gnap._actionStatus <= 4)
+ gnap._actionStatus = -1;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ if (_nextHookGuySequenceId == 0x204) {
+ gameSys.setAnimation(_nextHookGuySequenceId, 120, 3);
+ gameSys.insertSequence(0x204, 120, _currHookGuySequenceId, 120, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x1F5, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ _currHookGuySequenceId = 0x204;
+ _nextHookGuySequenceId = -1;
+ gnap._sequenceId = 0x1F5;
+ gnap._sequenceDatNum = 0;
+ _vm->_timers[4] = _vm->getRandom(40) + 20;
+ _vm->_timers[2] = _vm->getRandom(20) + 70;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ if (gnap._actionStatus == kAS11GrabHookGuy)
+ gnap._actionStatus = -1;
+ } else if (_nextHookGuySequenceId != -1) {
+ gameSys.insertSequence(_nextHookGuySequenceId, 120, _currHookGuySequenceId, 120, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextHookGuySequenceId, 120, 3);
+ _currHookGuySequenceId = _nextHookGuySequenceId;
+ _nextHookGuySequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(40) + 20;
+ if (gnap._actionStatus >= 6 && gnap._actionStatus <= 9)
+ gnap._actionStatus = -1;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2) {
+ gameSys.setAnimation(0, 0, 4);
+ _vm->_hotspots[kHS11Billard]._flags &= ~SF_DISABLED;
+ }
+}
+
+/*****************************************************************************/
+
+Scene12::Scene12(GnapEngine *vm) : Scene(vm) {
+ _nextBeardGuySequenceId = -1;
+ _currBeardGuySequenceId = -1;
+ _nextToothGuySequenceId = -1;
+ _currToothGuySequenceId = -1;
+ _nextBarkeeperSequenceId = -1;
+ _currBarkeeperSequenceId = -1;
+}
+
+int Scene12::init() {
+ return 0x209;
+}
+
+void Scene12::updateHotspots() {
+ _vm->setHotspot(kHS12Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS12ExitRight, 790, 360, 799, 599, SF_EXIT_R_CURSOR);
+ _vm->setHotspot(kHS12ToothGuy, 80, 180, 160, 380, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS12Barkeeper, 490, 175, 580, 238, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS12BeardGuy, 620, 215, 720, 350, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS12Jukebox, 300, 170, 410, 355, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS12WalkArea1, 0, 0, 260, 460);
+ _vm->setHotspot(kHS12WalkArea2, 0, 0, 380, 410);
+ _vm->setHotspot(kHS12WalkArea3, 0, 0, 799, 395);
+ _vm->setHotspot(kHS12WalkArea4, 585, 0, 799, 455);
+ _vm->setDeviceHotspot(kHS12Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 11;
+}
+
+void Scene12::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ int v18 = 1;
+
+ _vm->queueInsertDeviceIcon();
+
+ gameSys.insertSequence(0x207, 256, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x200, 50, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currToothGuySequenceId = 0x200;
+ _nextToothGuySequenceId = -1;
+
+ gameSys.setAnimation(0x200, 50, 2);
+ gameSys.insertSequence(0x202, 50, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currBeardGuySequenceId = 0x202;
+ _nextBeardGuySequenceId = -1;
+
+ gameSys.setAnimation(0x202, 50, 4);
+ gameSys.insertSequence(0x203, 50, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currBarkeeperSequenceId = 0x203;
+ _nextBarkeeperSequenceId = -1;
+
+ gameSys.setAnimation(0x203, 50, 3);
+
+ _vm->_timers[4] = 30;
+ _vm->_timers[6] = _vm->getRandom(30) + 20;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ _vm->_timers[7] = _vm->getRandom(100) + 100;
+
+ if (_vm->_prevSceneNum == 15) {
+ gnap.initPos(5, 6, kDirBottomRight);
+ plat.initPos(3, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ } else {
+ gnap.initPos(11, 8, kDirBottomLeft);
+ plat.initPos(12, 8, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 8), -1, 0x107D2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS12Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS12Platypus:
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ break;
+ }
+ break;
+
+ case kHS12ExitRight:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(10, -1), 0, 0x107AB, 1);
+ gnap._actionStatus = kAS12LeaveScene;
+ plat.walkTo(Common::Point(10, -1), -1, -1, 1);
+ _vm->_newSceneNum = 11;
+ break;
+
+ case kHS12ToothGuy:
+ if (_vm->_grabCursorSpriteIndex == kItemQuarter) {
+ _vm->_largeSprite = gameSys.createSurface(0x141);
+ gnap.walkTo(Common::Point(3, 7), 0, 0x107BC, 9);
+ gnap._idleFacing = kDirUpLeft;
+ gnap._actionStatus = kAS12QuarterToToothGuy;
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 2, 0);
+ _vm->setGrabCursorSprite(-1);
+ } else if (_vm->_grabCursorSpriteIndex == kItemQuarterWithHole) {
+ gnap.walkTo(Common::Point(3, 7), 0, 0x107BC, 9);
+ gnap._idleFacing = kDirUpLeft;
+ gnap._actionStatus = kAS12QuarterWithHoleToToothGuy;
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 2, 0);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.walkTo(Common::Point(3, 7), 0, 0x107BC, 9);
+ gnap._idleFacing = kDirUpLeft;
+ gnap._actionStatus = kAS12ShowItemToToothGuy;
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 2, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(1, 2));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(Common::Point(3, 7), 0, 0x107BC, 1);
+ gnap._actionStatus = kAS12GrabToothGuy;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(Common::Point(3, 7), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS12TalkToothGuy;
+ break;
+ case PLAT_CURSOR:
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(Common::Point(3, 7), 1, 0x107D2, 1);
+ plat._actionStatus = kAS12PlatWithToothGuy;
+ plat._idleFacing = kDirIdleRight;
+ gnap.playIdle(Common::Point(2, 7));
+ break;
+ }
+ }
+ break;
+
+ case kHS12Barkeeper:
+ if (_vm->_grabCursorSpriteIndex == kItemQuarter || _vm->_grabCursorSpriteIndex == kItemQuarterWithHole) {
+ gnap.walkTo(Common::Point(6, 6), 0, 0x107BB, 9);
+ gnap._idleFacing = kDirUpRight;
+ gnap._actionStatus = kAS12QuarterWithBarkeeper;
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 7, 0);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.walkTo(Common::Point(6, 6), 0, 0x107BB, 9);
+ gnap._idleFacing = kDirUpRight;
+ gnap._actionStatus = kAS12ShowItemToBarkeeper;
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 7, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.walkTo(Common::Point(6, 6), 0, 0x107BB, 1);
+ gnap._idleFacing = kDirUpRight;
+ gnap._actionStatus = kAS12LookBarkeeper;
+ break;
+ case GRAB_CURSOR:
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(Common::Point(6, 6), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS12TalkBarkeeper;
+ break;
+ case PLAT_CURSOR:
+ gnap.playPullOutDevice(plat._pos);
+ gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0);
+ gnap._actionStatus = kAS12PlatWithBarkeeper;
+ break;
+ }
+ }
+ break;
+
+ case kHS12BeardGuy:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.walkTo(Common::Point(7, 6), 0, 0x107BB, 9);
+ gnap._idleFacing = kDirUpRight;
+ gnap._actionStatus = kAS12ShowItemToBeardGuy;
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 8, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.walkTo(Common::Point(7, 6), 0, 0x107BB, 1);
+ gnap._idleFacing = kDirUpRight;
+ gnap._actionStatus = kAS12LookBeardGuy;
+ break;
+ case GRAB_CURSOR:
+ // NOTE Bug in the original. It has 9 as flags which seems wrong here.
+ gnap.walkTo(Common::Point(7, 6), 0, 0x107BB, 1);
+ gnap._idleFacing = kDirUpRight;
+ gnap._actionStatus = kAS12GrabBeardGuy;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(Common::Point(7, 6), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS12TalkBeardGuy;
+ break;
+ case PLAT_CURSOR:
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(Common::Point(7, 6), 1, 0x107C2, 1);
+ plat._actionStatus = kAS12PlatWithBeardGuy;
+ plat._idleFacing = kDirIdleLeft;
+ gnap.playIdle(Common::Point(7, 6));
+ break;
+ }
+ }
+ break;
+
+ case kHS12Jukebox:
+ _vm->_newSceneNum = 15;
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(5, 6), 0, 0x107BC, 1);
+ gnap._actionStatus = kAS12LeaveScene;
+ break;
+
+ case kHS12WalkArea1:
+ case kHS12WalkArea2:
+ case kHS12WalkArea3:
+ case kHS12WalkArea4:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = 15;
+ if (_nextToothGuySequenceId == -1) {
+ if (v18 == 0 && _currBeardGuySequenceId == 0x202 && _currBarkeeperSequenceId == 0x203 && gnap._actionStatus < 0 && plat._actionStatus < 0) {
+ if (_vm->getRandom(2) != 0)
+ _nextToothGuySequenceId = 0x1EC;
+ else
+ _nextToothGuySequenceId = 0x204;
+ } else if (_currToothGuySequenceId != 0x200)
+ _nextToothGuySequenceId = 0x200;
+ v18 = (v18 + 1) % 15;
+ }
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ if (_nextBarkeeperSequenceId == -1 && gnap._actionStatus < 0 && plat._actionStatus < 0) {
+ if (v18 == 0 && _currToothGuySequenceId == 0x200 && _currBeardGuySequenceId == 0x202 && gnap._actionStatus < 0 && plat._actionStatus < 0) {
+ if (_vm->getRandom(2) != 0)
+ _nextBarkeeperSequenceId = 0x208;
+ else
+ _nextBarkeeperSequenceId = 0x1FB;
+ } else
+ _nextBarkeeperSequenceId = 0x203;
+ v18 = (v18 + 1) % 15;
+ }
+ }
+ if (!_vm->_timers[6]) {
+ _vm->_timers[6] = _vm->getRandom(30) + 15;
+ if (_nextBeardGuySequenceId == -1 && gnap._actionStatus < 0 && plat._actionStatus < 0) {
+ if (v18 == 0 && _currToothGuySequenceId == 0x200 && _currBarkeeperSequenceId == 0x203 && gnap._actionStatus < 0 && plat._actionStatus < 0)
+ _nextBeardGuySequenceId = 0x1F2;
+ else
+ _nextBeardGuySequenceId = 0x202;
+ v18 = (v18 + 1) % 15;
+ }
+ }
+ if (!_vm->_timers[7]) {
+ _vm->_timers[7] = _vm->getRandom(100) + 100;
+ int _gnapRandomValue = _vm->getRandom(3);
+ switch (_gnapRandomValue) {
+ case 0:
+ gameSys.insertSequence(0x8A5 | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 1:
+ gameSys.insertSequence(0x8A7 | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 2:
+ gameSys.insertSequence(0x8A6 | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = 30;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ _vm->_timers[6] = _vm->getRandom(30) + 20;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene12::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS12LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS12TalkToothGuy:
+ if (_vm->isKeyStatus1(Common::KEYCODE_j)) {
+ // Easter egg
+ _vm->clearKeyStatus1(Common::KEYCODE_j);
+ _nextToothGuySequenceId = 0x206;
+ } else {
+ _nextToothGuySequenceId = 0x1EE;
+ }
+ break;
+ case 3:
+ break;
+ case kAS12GrabToothGuy:
+ if (_vm->isKeyStatus1(Common::KEYCODE_j)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_j);
+ _nextToothGuySequenceId = 0x206;
+ } else {
+ _nextToothGuySequenceId = 0x1EF;
+ }
+ break;
+ case kAS12ShowItemToToothGuy:
+ if (_vm->isKeyStatus1(Common::KEYCODE_j)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_j);
+ _nextToothGuySequenceId = 0x206;
+ } else {
+ _nextToothGuySequenceId = 0x1ED;
+ }
+ break;
+ case kAS12QuarterWithHoleToToothGuy:
+ if (_vm->isKeyStatus1(Common::KEYCODE_j)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_j);
+ _nextToothGuySequenceId = 0x206;
+ } else {
+ _nextToothGuySequenceId = 0x1EA;
+ }
+ break;
+ case kAS12QuarterToToothGuy:
+ if (_vm->isKeyStatus1(Common::KEYCODE_j)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_j);
+ _nextToothGuySequenceId = 0x206;
+ } else {
+ _nextToothGuySequenceId = 0x1E9;
+ }
+ break;
+ case kAS12QuarterToToothGuyDone:
+ gnap._actionStatus = -1;
+ _vm->showCursor();
+ gameSys.removeSpriteDrawItem(_vm->_largeSprite, 300);
+ _vm->deleteSurface(&_vm->_largeSprite);
+ _vm->setGrabCursorSprite(kItemQuarterWithHole);
+ break;
+ case kAS12TalkBeardGuy:
+ _nextBeardGuySequenceId = 0x1F4;
+ break;
+ case kAS12LookBeardGuy:
+ _nextBeardGuySequenceId = 0x1F3;
+ break;
+ case kAS12GrabBeardGuy:
+ _nextBeardGuySequenceId = 0x1F1;
+ break;
+ case kAS12ShowItemToBeardGuy:
+ _nextBeardGuySequenceId = 0x1F0;
+ break;
+ case kAS12TalkBarkeeper:
+ if (_vm->getRandom(2) != 0)
+ _nextBarkeeperSequenceId = 0x1FD;
+ else
+ _nextBarkeeperSequenceId = 0x1FF;
+ break;
+ case kAS12LookBarkeeper:
+ _nextBarkeeperSequenceId = 0x1F8;
+ break;
+ case 14:
+ _nextBarkeeperSequenceId = 0x1F6;
+ break;
+ case kAS12ShowItemToBarkeeper:
+ _nextBarkeeperSequenceId = 0x1F5;
+ break;
+ case kAS12QuarterWithBarkeeper:
+ _nextBarkeeperSequenceId = 0x1FA;
+ break;
+ case kAS12PlatWithBarkeeper:
+ _nextBarkeeperSequenceId = 0x1F9;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ switch (plat._actionStatus) {
+ case kAS12PlatWithToothGuy:
+ _nextToothGuySequenceId = 0x1EB;
+ break;
+ case kAS12PlatWithBeardGuy:
+ _nextBeardGuySequenceId = 0x1F3;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ if (_currToothGuySequenceId == 0x1E9) {
+ gameSys.setAnimation(0, 0, 2);
+ _vm->hideCursor();
+ gameSys.setAnimation(0x10843, 301, 0);
+ gnap._actionStatus = kAS12QuarterToToothGuyDone;
+ gameSys.insertSpriteDrawItem(_vm->_largeSprite, 0, 0, 300);
+ gameSys.insertSequence(0x10843, 301, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x107B7, gnap._id, 0x10843, 301,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = 0x7B7;
+ gnap._sequenceDatNum = 1;
+ _vm->setFlag(kGFTwigTaken);
+ _vm->invAdd(kItemQuarterWithHole);
+ _vm->invRemove(kItemQuarter);
+ }
+ if (_nextToothGuySequenceId == 0x1EF) {
+ gameSys.setAnimation(_nextToothGuySequenceId, 50, 2);
+ gameSys.insertSequence(_nextToothGuySequenceId, 50, _currToothGuySequenceId, 50, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x205, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ _currToothGuySequenceId = _nextToothGuySequenceId;
+ _nextToothGuySequenceId = -1;
+ gnap._sequenceId = 0x205;
+ gnap._sequenceDatNum = 0;
+ _vm->_timers[4] = 40;
+ _vm->_timers[2] = _vm->getRandom(20) + 70;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ if (gnap._actionStatus == kAS12GrabToothGuy)
+ gnap._actionStatus = -1;
+ } else if (_nextToothGuySequenceId != -1) {
+ gameSys.insertSequence(_nextToothGuySequenceId, 50, _currToothGuySequenceId, 50, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextToothGuySequenceId, 50, 2);
+ _currToothGuySequenceId = _nextToothGuySequenceId;
+ _nextToothGuySequenceId = -1;
+ _vm->_timers[4] = 50;
+ if (gnap._actionStatus >= kAS12TalkToothGuy && gnap._actionStatus <= kAS12QuarterToToothGuy && _currToothGuySequenceId != 0x1E9 &&
+ _currToothGuySequenceId != 0x1EC && _currToothGuySequenceId != 0x200)
+ gnap._actionStatus = -1;
+ if (plat._actionStatus == kAS12PlatWithToothGuy)
+ plat._actionStatus = -1;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ if (gnap._actionStatus == kAS12PlatWithBarkeeper && _currBarkeeperSequenceId == 0x1F9) {
+ gnap._actionStatus = -1;
+ gnap.playIdle(Common::Point(7, 6));
+ _vm->_timers[5] = 0;
+ }
+ if (_nextBarkeeperSequenceId != -1) {
+ gameSys.insertSequence(_nextBarkeeperSequenceId, 50, _currBarkeeperSequenceId, 50, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextBarkeeperSequenceId, 50, 3);
+ _currBarkeeperSequenceId = _nextBarkeeperSequenceId;
+ _nextBarkeeperSequenceId = -1;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ if (gnap._actionStatus >= kAS12TalkBarkeeper && gnap._actionStatus <= kAS12QuarterWithBarkeeper && _currBarkeeperSequenceId != 0x203 &&
+ _currBarkeeperSequenceId != 0x1FB && _currBarkeeperSequenceId != 0x208)
+ gnap._actionStatus = -1;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2 && _nextBeardGuySequenceId != -1) {
+ gameSys.insertSequence(_nextBeardGuySequenceId, 50, _currBeardGuySequenceId, 50, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextBeardGuySequenceId, 50, 4);
+ _currBeardGuySequenceId = _nextBeardGuySequenceId;
+ _nextBeardGuySequenceId = -1;
+ _vm->_timers[6] = _vm->getRandom(30) + 20;
+ if (gnap._actionStatus >= kAS12TalkBeardGuy && gnap._actionStatus <= kAS12ShowItemToBeardGuy && _currBeardGuySequenceId != 0x202 && _currBeardGuySequenceId != 0x1F2)
+ gnap._actionStatus = -1;
+ if (plat._actionStatus == kAS12PlatWithBeardGuy)
+ plat._actionStatus = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene13::Scene13(GnapEngine *vm) : Scene(vm) {
+ _backToiletCtr = -1;
+}
+
+int Scene13::init() {
+ _vm->playSound(0x108EC, false);
+ return 0xAC;
+}
+
+void Scene13::updateHotspots() {
+ _vm->setHotspot(kHS13Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS13ExitBar, 113, 160, 170, 455, SF_EXIT_L_CURSOR);
+ _vm->setHotspot(kHS13BackToilet, 385, 195, 478, 367, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS13FrontToilet, 497, 182, 545, 432, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS13Urinal, 680, 265, 760, 445, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS13Scribble, 560, 270, 660, 370, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS13Sink, 310, 520, 560, 599, SF_WALKABLE | SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS13WalkArea1, 268, 270, 325, 385);
+ _vm->setHotspot(kHS13WalkArea2, 0, 0, 52, 599);
+ _vm->setHotspot(kHS13WalkArea3, 0, 0, 113, 550);
+ _vm->setHotspot(kHS13WalkArea4, 0, 0, 226, 438);
+ _vm->setHotspot(kHS13WalkArea5, 0, 0, 268, 400);
+ _vm->setHotspot(kHS13WalkArea6, 0, 0, 799, 367);
+ _vm->setHotspot(kHS13WalkArea7, 478, 0, 799, 401);
+ _vm->setHotspot(kHS13WalkArea8, 545, 0, 799, 473);
+ _vm->setHotspot(kHS13WalkArea9, 0, 549, 799, 599);
+ _vm->setDeviceHotspot(kHS13Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 17;
+}
+
+void Scene13::showScribble() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ _vm->hideCursor();
+ _vm->_largeSprite = gameSys.createSurface(0x6F);
+ gameSys.insertSpriteDrawItem(_vm->_largeSprite, 0, 0, 300);
+ while (!_vm->_mouseClickState._left && !_vm->isKeyStatus1(Common::KEYCODE_ESCAPE) &&
+ !_vm->isKeyStatus1(Common::KEYCODE_SPACE) && !_vm->isKeyStatus1(Common::KEYCODE_RETURN) && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->_mouseClickState._left = false;
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _vm->clearKeyStatus1(Common::KEYCODE_RETURN);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ gameSys.removeSpriteDrawItem(_vm->_largeSprite, 300);
+ _vm->deleteSurface(&_vm->_largeSprite);
+ _vm->showCursor();
+}
+
+void Scene13::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ int currSoundId = 0;
+
+ _vm->queueInsertDeviceIcon();
+ gameSys.insertSequence(0xAA, 256, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->_prevSceneNum == 14) {
+ gnap.initPos(6, 6, kDirBottomLeft);
+ plat.initPos(9, 8, kDirIdleLeft);
+ } else {
+ gnap.initPos(3, 7, kDirBottomRight);
+ plat.initPos(2, 7, kDirIdleLeft);
+ }
+
+ _vm->endSceneInit();
+
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ _vm->_timers[5] = _vm->getRandom(50) + 50;
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1091A))
+ _vm->playSound(0x1091A, true);
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS13Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ _vm->_timers[5] = _vm->getRandom(50) + 50;
+ }
+ break;
+
+ case kHS13Platypus:
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ break;
+ }
+ break;
+
+ case kHS13ExitBar:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(2, 7), 0, 0x107C0, 1);
+ gnap._actionStatus = kAS13LeaveScene;
+ plat.walkTo(Common::Point(2, 8), -1, -1, 1);
+ if (_vm->isFlag(kGFUnk14) || _vm->isFlag(kGFSpringTaken)) {
+ _vm->_newSceneNum = 11;
+ } else {
+ _vm->setFlag(kGFSpringTaken);
+ _vm->_newSceneNum = 47;
+ }
+ break;
+
+ case kHS13BackToilet:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(5, 5), 6, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ case GRAB_CURSOR:
+ case TALK_CURSOR:
+ if (gnap._pos == Common::Point(5, 5)) {
+ _backToiletCtr = MIN(5, _backToiletCtr + 1);
+ gameSys.setAnimation(_backToiletCtr + 0xA3, gnap._id, 0);
+ gameSys.insertSequence(_backToiletCtr + 0xA3, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqScale | kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = kAS13Wait;
+ gnap._sequenceId = _backToiletCtr + 0xA3;
+ gnap._idleFacing = kDirUpRight;
+ gnap._sequenceDatNum = 0;
+ } else {
+ gnap.walkTo(Common::Point(5, 5), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS13BackToilet;
+ gnap._idleFacing = kDirUpRight;
+ }
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS13FrontToilet:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(6, 7), 7, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ case GRAB_CURSOR:
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.walkTo(Common::Point(6, 7), 0, 0xA9, 5);
+ gnap._actionStatus = kAS13FrontToilet;
+ gnap._idleFacing = kDirBottomRight;
+ break;
+ }
+ }
+ break;
+
+ case kHS13Scribble:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(7, 7), 8, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.walkTo(Common::Point(7, 7), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS13LookScribble;
+ gnap._idleFacing = kDirUpRight;
+ break;
+ case GRAB_CURSOR:
+ gnap.playScratchingHead();
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(Common::Point(7, 7), -1, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)), 1);
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS13Urinal:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(8, 7), 9, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playSequence(gnap.getSequenceId(kGSDeflect, Common::Point(9, 6)));
+ gnap.walkTo(gnap._pos, 0, -1, 1);
+ gnap._actionStatus = kAS13Wait;
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(Common::Point(8, 7), 0, -1, 1);
+ gnap._actionStatus = kAS13GrabUrinal;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS13Sink:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playSequence(gnap.getSequenceId(kGSDeflect, Common::Point(5, 9)));
+ gnap.walkTo(gnap._pos, 0, -1, 1);
+ gnap._actionStatus = kAS13Wait;
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(Common::Point(4, 8), 0, 0x107B9, 1);
+ gnap._actionStatus = kAS13GrabSink;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS13WalkArea2:
+ case kHS13WalkArea3:
+ case kHS13WalkArea4:
+ case kHS13WalkArea5:
+ case kHS13WalkArea6:
+ case kHS13WalkArea7:
+ case kHS13WalkArea8:
+ case kHS13WalkArea9:
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ case kHS13WalkArea1:
+ // Nothing
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ if (plat._pos.y == 5 || plat._pos.y == 6)
+ plat.walkTo(Common::Point(-1, 7), -1, -1, 1);
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ switch (_vm->getRandom(5)) {
+ case 0:
+ _vm->playSound(0xD2, false);
+ break;
+ case 1:
+ _vm->playSound(0xD3, false);
+ break;
+ case 2:
+ _vm->playSound(0xD4, false);
+ break;
+ case 3:
+ _vm->playSound(0xD5, false);
+ break;
+ case 4:
+ _vm->playSound(0xD6, false);
+ break;
+ }
+ }
+ if (!_vm->_timers[5]) {
+ int newSoundId;
+ _vm->_timers[5] = _vm->getRandom(50) + 50;
+ switch (_vm->getRandom(7)) {
+ case 0:
+ newSoundId = 0xD7;
+ _vm->_timers[5] = 2 * _vm->getRandom(50) + 100;
+ break;
+ case 1:
+ case 2:
+ newSoundId = 0xCF;
+ break;
+ case 3:
+ case 4:
+ newSoundId = 0xD0;
+ break;
+ default:
+ newSoundId = 0xD1;
+ break;
+ }
+ if (newSoundId != currSoundId) {
+ _vm->playSound(newSoundId, false);
+ currSoundId = newSoundId;
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ _vm->_timers[5] = _vm->getRandom(50) + 50;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene13::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS13LeaveScene:
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ break;
+ case kAS13BackToilet:
+ _backToiletCtr = MIN(5, _backToiletCtr + 1);
+ gameSys.insertSequence(_backToiletCtr + 0xA3, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 9, 0, 0, 0);
+ gnap._sequenceId = _backToiletCtr + 0xA3;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = -1;
+ break;
+ case kAS13FrontToilet:
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 14;
+ break;
+ case kAS13LookScribble:
+ gnap._actionStatus = -1;
+ showScribble();
+ break;
+ case kAS13GrabSink:
+ gameSys.setAnimation(0xAB, 160, 0);
+ gameSys.insertSequence(0xAB, 160, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(0xAA, 256, true);
+ gnap._sequenceId = 0xAB;
+ gnap._id = 160;
+ gnap._idleFacing = kDirBottomRight;
+ gnap._sequenceDatNum = 0;
+ gnap._pos = Common::Point(4, 8);
+ _vm->_timers[2] = 360;
+ gnap._actionStatus = kAS13GrabSinkDone;
+ break;
+ case kAS13GrabSinkDone:
+ gameSys.insertSequence(0xAA, 256, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._actionStatus = -1;
+ break;
+ case kAS13Wait:
+ gnap._actionStatus = -1;
+ break;
+ case kAS13GrabUrinal:
+ gameSys.setAnimation(0xA2, 120, 0);
+ gameSys.insertSequence(0xA2, 120, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0xA2;
+ gnap._id = 120;
+ gnap._idleFacing = kDirBottomLeft;
+ gnap._sequenceDatNum = 0;
+ gnap._pos = Common::Point(4, 6);
+ _vm->_timers[2] = 360;
+ gnap._actionStatus = kAS13Wait;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ _vm->_plat->_actionStatus = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene14::Scene14(GnapEngine *vm) : Scene(vm) {
+}
+
+int Scene14::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ return 0x27;
+}
+
+void Scene14::updateHotspots() {
+ _vm->setHotspot(kHS14Platypus, 0, 0, 0, 0);
+ _vm->setHotspot(kHS14Exit, 0, 590, 799, 599, SF_EXIT_D_CURSOR);
+ _vm->setHotspot(kHS14Coin, 330, 390, 375, 440, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS14Toilet, 225, 250, 510, 500, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setDeviceHotspot(kHS14Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFNeedleTaken))
+ _vm->_hotspots[kHS14Coin]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 5;
+}
+
+void Scene14::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ _vm->_largeSprite = nullptr;
+ _vm->queueInsertDeviceIcon();
+
+ if (!_vm->isFlag(kGFNeedleTaken))
+ gameSys.insertSequence(0x23, 10, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->endSceneInit();
+
+ if (!_vm->isFlag(kGFNeedleTaken) && _vm->invHas(kItemTongs))
+ _vm->_largeSprite = gameSys.createSurface(1);
+
+ if (!_vm->isFlag(kGFNeedleTaken)) {
+ gameSys.insertSequence(0x24, 10, 0x23, 10, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x24;
+ _vm->_timers[2] = _vm->getRandom(40) + 50;
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS14Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS14Exit:
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 13;
+ break;
+
+ case kHS14Coin:
+ if (_vm->_grabCursorSpriteIndex == kItemTongs) {
+ _vm->invAdd(kItemQuarter);
+ _vm->setFlag(kGFNeedleTaken);
+ _vm->setGrabCursorSprite(-1);
+ _vm->hideCursor();
+ gameSys.setAnimation(0x26, 10, 0);
+ gameSys.insertSequence(0x26, 10, gnap._sequenceId, 10, kSeqSyncWait, 0, 0, 0);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ _vm->playSound(0x108E9, false);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ _vm->playSound(0x108E9, false);
+ break;
+ case GRAB_CURSOR:
+ gameSys.insertSequence(0x25, 10, gnap._sequenceId, 10, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x23, 10, 0x25, 10, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x23;
+ break;
+ case TALK_CURSOR:
+ _vm->playSound((_vm->getRandom(5) + 0x8D5) | 0x10000, false);
+ break;
+ case PLAT_CURSOR:
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ break;
+ }
+ }
+ break;
+
+ case kHS14Toilet:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ case GRAB_CURSOR:
+ _vm->playSound(0x108B1, false);
+ break;
+ case TALK_CURSOR:
+ _vm->playSound((_vm->getRandom(5) + 0x8D5) | 0x10000, false);
+ break;
+ case PLAT_CURSOR:
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ break;
+ }
+ }
+ break;
+
+ default:
+ _vm->_mouseClickState._left = false;
+ break;
+ }
+
+ updateAnimations();
+ _vm->checkGameKeys();
+
+ if (!_vm->isFlag(kGFNeedleTaken) && !_vm->_timers[2]) {
+ gameSys.insertSequence(0x24, 10, gnap._sequenceId, 10, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x24;
+ _vm->_timers[2] = _vm->getRandom(40) + 50;
+ }
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+
+ if (_vm->_largeSprite)
+ _vm->deleteSurface(&_vm->_largeSprite);
+}
+
+void Scene14::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.insertSpriteDrawItem(_vm->_largeSprite, 0, 0, 300);
+ gameSys.setAnimation(0x10843, 301, 1);
+ gameSys.insertSequence(0x10843, 301, 0x26, 10, kSeqSyncWait, 0, 0, 0);
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 13;
+ _vm->_grabCursorSpriteIndex = kItemQuarter;
+ }
+}
+
+/*****************************************************************************/
+
+Scene15::Scene15(GnapEngine *vm) : Scene(vm) {
+ _nextRecordSequenceId = -1;
+ _currRecordSequenceId = -1;
+ _nextSlotSequenceId = -1;
+ _currSlotSequenceId = -1;
+ _nextUpperButtonSequenceId = -1;
+ _currUpperButtonSequenceId = -1;
+ _nextLowerButtonSequenceId = -1;
+ _currLowerButtonSequenceId = -1;
+}
+
+int Scene15::init() {
+ return 0xDD;
+}
+
+void Scene15::updateHotspots() {
+ _vm->setHotspot(kHS15Platypus, 0, 0, 0, 0, SF_DISABLED);
+ _vm->setHotspot(kHS15Exit, 50, 590, 750, 599, SF_EXIT_D_CURSOR);
+ _vm->setHotspot(kHS15Button1, 210, 425, 260, 475, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15Button2, 280, 425, 325, 475, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15Button3, 340, 425, 385, 475, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15Button4, 400, 425, 445, 475, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15Button5, 460, 425, 510, 475, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15Button6, 520, 425, 560, 475, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15ButtonA, 205, 480, 250, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15ButtonB, 270, 480, 320, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15ButtonC, 335, 480, 380, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15ButtonD, 395, 480, 445, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15ButtonE, 460, 480, 505, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15ButtonF, 515, 480, 560, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15CoinSlot, 585, 475, 620, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15PlayButton, 622, 431, 650, 482, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setDeviceHotspot(kHS15Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 17;
+}
+
+void Scene15::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ _currSlotSequenceId = -1;
+ _currUpperButtonSequenceId = -1;
+ _currLowerButtonSequenceId = -1;
+ _nextSlotSequenceId = -1;
+ _nextUpperButtonSequenceId = -1;
+ _nextLowerButtonSequenceId = -1;
+ _currRecordSequenceId = 0xD5;
+ _nextRecordSequenceId = -1;
+
+ gameSys.setAnimation(0xD5, 1, 0);
+ gameSys.insertSequence(_currRecordSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ _vm->endSceneInit();
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_hotspots[kHS15Platypus].clearRect();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS15Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS15Exit:
+ _vm->_newSceneNum = 12;
+ _vm->_isLeavingScene = true;
+ break;
+
+ case kHS15CoinSlot:
+ if (_vm->_grabCursorSpriteIndex == kItemQuarter || _vm->_grabCursorSpriteIndex == kItemQuarterWithHole) {
+ _nextSlotSequenceId = 0xDC; // Insert coin
+ } else if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole) {
+ _nextSlotSequenceId = 0xDB;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ case GRAB_CURSOR:
+ _vm->playSound(0x108E9, false);
+ break;
+ case TALK_CURSOR:
+ _vm->playSound((_vm->getRandom(5) + 0x8D5) | 0x10000, false);
+ break;
+ case PLAT_CURSOR:
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ break;
+ }
+ }
+ break;
+
+ case kHS15PlayButton:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFGnapControlsToyUFO) || _vm->isFlag(kGFUnk13))
+ _vm->playSound(0x108E9, false);
+ else
+ _nextSlotSequenceId = 0xDA;
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFGnapControlsToyUFO) || _vm->isFlag(kGFUnk13))
+ _nextSlotSequenceId = 0xD9;
+ else
+ _nextSlotSequenceId = 0xDA;
+ break;
+ case TALK_CURSOR:
+ _vm->playSound((_vm->getRandom(5) + 0x8D5) | 0x10000, false);
+ break;
+ case PLAT_CURSOR:
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ break;
+ }
+ }
+ break;
+
+ case kHS15Button1:
+ case kHS15Button2:
+ case kHS15Button3:
+ case kHS15Button4:
+ case kHS15Button5:
+ case kHS15Button6:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ _vm->playSound(0x108E9, false);
+ break;
+ case GRAB_CURSOR:
+ _nextUpperButtonSequenceId = _vm->_sceneClickedHotspot + 0xC5;
+ break;
+ case TALK_CURSOR:
+ _vm->playSound((_vm->getRandom(5) + 0x8D5) | 0x10000, false);
+ break;
+ case PLAT_CURSOR:
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ break;
+ }
+ }
+ break;
+
+ case kHS15ButtonA:
+ case kHS15ButtonB:
+ case kHS15ButtonC:
+ case kHS15ButtonD:
+ case kHS15ButtonE:
+ case kHS15ButtonF:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ _vm->playSound(0x108E9, false);
+ break;
+ case GRAB_CURSOR:
+ _nextLowerButtonSequenceId = _vm->_sceneClickedHotspot + 0xC5;
+ break;
+ case TALK_CURSOR:
+ _vm->playSound((_vm->getRandom(5) + 0x8D5) | 0x10000, false);
+ break;
+ case PLAT_CURSOR:
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ break;
+ }
+ }
+ break;
+
+ default:
+ _vm->_mouseClickState._left = false;
+ break;
+
+ }
+
+ updateAnimations();
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene15::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ if (_vm->_isLeavingScene) {
+ _vm->_sceneDone = true;
+ } else if (_nextSlotSequenceId != -1) {
+ gameSys.setAnimation(_nextSlotSequenceId, 1, 0);
+ gameSys.insertSequence(_nextSlotSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+ _currSlotSequenceId = _nextSlotSequenceId;
+ _nextSlotSequenceId = -1;
+ switch (_currSlotSequenceId) {
+ case 0xDC:
+ if (_vm->_grabCursorSpriteIndex == kItemQuarter) {
+ _vm->invRemove(kItemQuarter);
+ } else {
+ _vm->invRemove(kItemQuarterWithHole);
+ _vm->setFlag(kGFUnk13);
+ }
+ _vm->setGrabCursorSprite(-1);
+ break;
+ case 0xDB:
+ _vm->setFlag(kGFUnk14);
+ _vm->setGrabCursorSprite(-1);
+ _nextSlotSequenceId = 0xD8;
+ break;
+ case 0xD9:
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->clearFlag(kGFGnapControlsToyUFO);
+ _vm->invAdd(kItemQuarter);
+ _vm->_newGrabCursorSpriteIndex = kItemQuarter;
+ } else if (_vm->isFlag(kGFUnk13)) {
+ _vm->clearFlag(kGFUnk13);
+ _vm->invAdd(kItemQuarterWithHole);
+ _vm->_newGrabCursorSpriteIndex = kItemQuarterWithHole;
+ }
+ _vm->_newSceneNum = 12;
+ _vm->_isLeavingScene = true;
+ break;
+ case 0xD8:
+ case 0xDA:
+ if (_currUpperButtonSequenceId != -1) {
+ gameSys.removeSequence(_currUpperButtonSequenceId, 1, true);
+ _currUpperButtonSequenceId = -1;
+ }
+ if (_currLowerButtonSequenceId != -1) {
+ gameSys.removeSequence(_currLowerButtonSequenceId, 1, true);
+ _currLowerButtonSequenceId = -1;
+ }
+ break;
+ }
+ } else if (_nextRecordSequenceId != -1) {
+ gameSys.setAnimation(_nextRecordSequenceId, 1, 0);
+ gameSys.insertSequence(_nextRecordSequenceId, 1, _currRecordSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ _currRecordSequenceId = _nextRecordSequenceId;
+ _nextRecordSequenceId = -1;
+ if (_currRecordSequenceId == 0xD3) {
+ _vm->invRemove(kItemDiceQuarterHole);
+ _vm->_newSceneNum = 16;
+ _vm->_isLeavingScene = true;
+ }
+ gameSys.removeSequence(_currUpperButtonSequenceId, 1, true);
+ _currUpperButtonSequenceId = -1;
+ gameSys.removeSequence(_currLowerButtonSequenceId, 1, true);
+ _currLowerButtonSequenceId = -1;
+ } else if (_nextUpperButtonSequenceId != -1) {
+ gameSys.setAnimation(_nextUpperButtonSequenceId, 1, 0);
+ if (_currUpperButtonSequenceId == -1)
+ gameSys.insertSequence(_nextUpperButtonSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(_nextUpperButtonSequenceId, 1, _currUpperButtonSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ _currUpperButtonSequenceId = _nextUpperButtonSequenceId;
+ _nextUpperButtonSequenceId = -1;
+ if (_currLowerButtonSequenceId != -1 && _vm->isFlag(kGFUnk14)) {
+ if (_currUpperButtonSequenceId == 0xCC && _currLowerButtonSequenceId == 0xCE)
+ _nextRecordSequenceId = 0xD3;
+ else
+ _nextRecordSequenceId = 0xD4;
+ }
+ } else if (_nextLowerButtonSequenceId != -1) {
+ gameSys.setAnimation(_nextLowerButtonSequenceId, 1, 0);
+ if (_currLowerButtonSequenceId == -1)
+ gameSys.insertSequence(_nextLowerButtonSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(_nextLowerButtonSequenceId, 1, _currLowerButtonSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ _currLowerButtonSequenceId = _nextLowerButtonSequenceId;
+ _nextLowerButtonSequenceId = -1;
+ if (_currUpperButtonSequenceId != -1 && _vm->isFlag(kGFUnk14)) {
+ if (_currUpperButtonSequenceId == 0xCC && _currLowerButtonSequenceId == 0xCE)
+ _nextRecordSequenceId = 0xD3;
+ else
+ _nextRecordSequenceId = 0xD4;
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene17::Scene17(GnapEngine *vm) : Scene(vm) {
+ _platTryGetWrenchCtr = 0;
+ _wrenchCtr = 2;
+ _nextCarWindowSequenceId = -1;
+ _nextWrenchSequenceId = -1;
+ _canTryGetWrench = true;
+ _platPhoneCtr = 0;
+ _nextPhoneSequenceId = -1;
+ _currPhoneSequenceId = -1;
+ _currWrenchSequenceId = -1;
+ _currCarWindowSequenceId = -1;
+}
+
+int Scene17::init() {
+ return 0x263;
+}
+
+void Scene17::updateHotspots() {
+ _vm->setHotspot(kHS17Platypus, 1, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS17Phone1, 61, 280, 97, 322, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 7);
+ _vm->setHotspot(kHS17Phone2, 80, 204, 178, 468, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 7);
+ _vm->setHotspot(kHS17ExitGrubCity, 196, 207, 280, 304, SF_EXIT_U_CURSOR, 3, 5);
+ _vm->setHotspot(kHS17ExitToyStore, 567, 211, 716, 322, SF_EXIT_U_CURSOR, 5, 6);
+ _vm->setHotspot(kHS17Wrench, 586, 455, 681, 547, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 7);
+ _vm->setHotspot(kHS17WalkArea1, 0, 0, 800, 434);
+ _vm->setHotspot(kHS17WalkArea2, 541, 0, 800, 600);
+ _vm->setHotspot(kHS17WalkArea3, 0, 204, 173, 468);
+ _vm->setDeviceHotspot(kHS17Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFGrassTaken))
+ _vm->_hotspots[kHS17Wrench]._flags = SF_NONE;
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ _vm->_hotspots[kHS17Device]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS17Platypus]._flags = SF_DISABLED;
+ }
+ _vm->_hotspotsCount = 10;
+}
+
+void Scene17::update() {
+ _vm->gameUpdateTick();
+ _vm->updateMouseCursor();
+ _vm->updateGrabCursorSprite(0, 0);
+ if (_vm->_mouseClickState._left) {
+ _vm->_gnap->walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+}
+
+void Scene17::platHangUpPhone() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ int savedGnapActionStatus = gnap._actionStatus;
+
+ if (plat._actionStatus == kAS17PlatPhoningAssistant) {
+ gnap._actionStatus = kAS17PlatHangUpPhone;
+ _vm->updateMouseCursor();
+ _platPhoneCtr = 0;
+ plat._actionStatus = -1;
+ gameSys.setAnimation(0x257, 254, 4);
+ gameSys.insertSequence(0x257, 254, _currPhoneSequenceId, 254, kSeqSyncExists, 0, 0, 0);
+ while (gameSys.getAnimationStatus(4) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ gameSys.setAnimation(0x25B, plat._id, 1);
+ gameSys.insertSequence(0x25B, plat._id, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceId = 0x25B;
+ plat._sequenceDatNum = 0;
+ _currPhoneSequenceId = -1;
+ _nextPhoneSequenceId = -1;
+ _vm->clearFlag(kGFPlatypusTalkingToAssistant);
+ while (gameSys.getAnimationStatus(1) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ gnap._actionStatus = savedGnapActionStatus;
+ _vm->updateMouseCursor();
+ }
+ updateHotspots();
+}
+
+void Scene17::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x10940, true);
+ _vm->startSoundTimerA(8);
+ _vm->_sceneWaiting = false;
+ _vm->_timers[4] = _vm->getRandom(100) + 200;
+ _vm->_timers[3] = 200;
+ _vm->_timers[5] = _vm->getRandom(30) + 80;
+ _vm->_timers[6] = _vm->getRandom(30) + 200;
+ _vm->_timers[7] = _vm->getRandom(100) + 100;
+
+ if (_vm->isFlag(kGFTruckKeysUsed)) {
+ gameSys.insertSequence(0x25F, 20, 0, 0, kSeqNone, 0, 0, 0);
+ } else {
+ if (_vm->_s18GarbageCanPos >= 8) {
+ gameSys.insertSequence(0x260, 20, 0, 0, kSeqNone, 0, 97, 1);
+ } else if (_vm->_s18GarbageCanPos >= 6) {
+ gameSys.insertSequence(0x260, 20, 0, 0, kSeqNone, 0, 68, 2);
+ } else if (_vm->_s18GarbageCanPos >= 5) {
+ gameSys.insertSequence(0x260, 20, 0, 0, kSeqNone, 0, 23, -1);
+ } else if (_vm->_s18GarbageCanPos >= 4) {
+ gameSys.insertSequence(0x260, 20, 0, 0, kSeqNone, 0, -11, -5);
+ } else {
+ gameSys.insertSequence(0x260, 20, 0, 0, kSeqNone, 0, -54, -8);
+ }
+ }
+
+ if (_vm->isFlag(kGFGroceryStoreHatTaken))
+ gameSys.insertSequence(0x262, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->isFlag(kGFGrassTaken))
+ _currWrenchSequenceId = 0x22D;
+ else
+ _currWrenchSequenceId = 0x22F;
+
+ _currCarWindowSequenceId = 0x244;
+
+ if (_vm->isFlag(kGFUnk14))
+ gameSys.insertSequence(0x261, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ gameSys.setAnimation(_currWrenchSequenceId, 40, 2);
+ gameSys.insertSequence(_currWrenchSequenceId, 40, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFGrassTaken)) {
+ gameSys.setAnimation(0, 0, 3);
+ } else {
+ gameSys.setAnimation(_currCarWindowSequenceId, 40, 3);
+ gameSys.insertSequence(_currCarWindowSequenceId, 40, 0, 0, kSeqNone, 0, 0, 0);
+ }
+
+ _canTryGetWrench = true;
+
+ if (_vm->isFlag(kGFUnk18))
+ gameSys.insertSequence(0x24F, 100, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->_prevSceneNum == 53 || _vm->_prevSceneNum == 18 || _vm->_prevSceneNum == 20 || _vm->_prevSceneNum == 19) {
+ if (_vm->_prevSceneNum == 20) {
+ gnap.initPos(4, 6, kDirBottomRight);
+ plat.initPos(5, 6, kDirIdleLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(5, 9), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(4, 8), -1, 0x107B9, 1);
+ } else if (_vm->isFlag(kGFUnk27)) {
+ gnap.initPos(3, 9, kDirUpLeft);
+ plat._pos = _vm->_hotspotsWalkPos[2];
+ plat._id = 20 * _vm->_hotspotsWalkPos[2].y;
+ gameSys.insertSequence(0x25A, 20 * _vm->_hotspotsWalkPos[2].y, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x257, 254, 0, 0, kSeqNone, 0, 0, 0);
+ plat._sequenceId = 0x25A;
+ plat._sequenceDatNum = 0;
+ _vm->endSceneInit();
+ _vm->clearFlag(kGFSpringTaken);
+ _vm->clearFlag(kGFUnk16);
+ plat._actionStatus = kAS17PlatPhoningAssistant;
+ platHangUpPhone();
+ gameSys.setAnimation(0, 0, 4);
+ _vm->clearFlag(kGFPlatypusTalkingToAssistant);
+ _vm->clearFlag(kGFUnk27);
+ updateHotspots();
+ } else if (_vm->isFlag(kGFUnk25)) {
+ _vm->clearFlag(kGFSpringTaken);
+ _vm->clearFlag(kGFUnk16);
+ plat.initPos(7, 9, kDirIdleLeft);
+ gnap._pos = _vm->_hotspotsWalkPos[2];
+ gnap._id = 20 * _vm->_hotspotsWalkPos[2].y;
+ gameSys.insertSequence(601, 20 * _vm->_hotspotsWalkPos[2].y, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 601;
+ gnap._actionStatus = kAS17GnapHangUpPhone;
+ _vm->clearFlag(kGFUnk25);
+ gameSys.insertSequence(0x251, 254, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+ gameSys.setAnimation(0x257, 254, 0);
+ gameSys.insertSequence(0x257, 254, 0x251, 254, kSeqSyncWait, 0, 0, 0);
+ } else if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ _vm->clearFlag(kGFSpringTaken);
+ _vm->clearFlag(kGFUnk16);
+ _vm->_sceneWaiting = true;
+ gnap.initPos(3, 9, kDirUpLeft);
+ plat._pos = _vm->_hotspotsWalkPos[2];
+ plat._id = 20 * _vm->_hotspotsWalkPos[2].y;
+ _currPhoneSequenceId = 0x251;
+ gameSys.insertSequence(0x25A, 20 * _vm->_hotspotsWalkPos[2].y, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(_currPhoneSequenceId, 254, 0, 0, kSeqNone, 0, 0, 0);
+ plat._sequenceId = 0x25A;
+ plat._sequenceDatNum = 0;
+ _vm->endSceneInit();
+ gameSys.setAnimation(_currPhoneSequenceId, 254, 1);
+ plat._actionStatus = kAS17PlatPhoningAssistant;
+ updateHotspots();
+ } else if (_vm->_prevSceneNum == 18) {
+ gnap.initPos(6, 6, kDirBottomRight);
+ plat.initPos(5, 6, kDirIdleLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(5, 9), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(4, 8), -1, 0x107B9, 1);
+ } else {
+ if (_vm->isFlag(kGFSpringTaken)) {
+ gnap.initPos(_vm->_hotspotsWalkPos[2].x, _vm->_hotspotsWalkPos[2].y, kDirBottomRight);
+ plat.initPos(1, 9, kDirIdleLeft);
+ _vm->endSceneInit();
+ } else {
+ gnap.initPos(3, 7, kDirBottomRight);
+ plat.initPos(1, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ }
+ _vm->clearFlag(kGFSpringTaken);
+ _vm->clearFlag(kGFUnk16);
+ _vm->endSceneInit();
+ }
+ } else {
+ gnap._pos = Common::Point(3, 6);
+ gnap._id = 120;
+ gnap._sequenceId = 0x23D;
+ gnap._sequenceDatNum = 0;
+ gnap._idleFacing = kDirBottomRight;
+ gameSys.insertSequence(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0, 0, kSeqNone, 0, 0, 0);
+ plat._pos = Common::Point(-1, 8);
+ plat._id = 160;
+ gameSys.insertSequence(0x241, 160, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x107C1, plat._id, 0x241, plat._id,
+ kSeqScale | kSeqSyncWait, 0, 75 * plat._pos.x - plat._gridX, 48 * plat._pos.y - plat._gridY);
+ gameSys.insertSequence(0x22C, 2, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->delayTicksA(2, 9);
+ _vm->endSceneInit();
+ plat._sequenceId = 0x7C1;
+ plat._sequenceDatNum = 1;
+ plat._idleFacing = kDirBottomRight;
+ plat.walkTo(Common::Point(2, 9), -1, 0x107C2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS17Device:
+ if (gnap._actionStatus < 0 || gnap._actionStatus == 3) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS17Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ if (_vm->isFlag(kGFGrassTaken)) {
+ gnap.useJointOnPlatypus();
+ } else {
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(_vm->_hotspotsWalkPos[6], 1, 0x107C2, 1);
+ gnap.walkTo(_vm->_hotspotsWalkPos[6] + Common::Point(1, 0), 0, 0x107BA, 1);
+ plat._actionStatus = kAS17GetWrench1;
+ gnap._actionStatus = kAS17GetWrench1;
+ _vm->_timers[5] = _vm->getRandom(30) + 80;
+ _vm->setGrabCursorSprite(-1);
+ _vm->invRemove(kItemJoint);
+ }
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playScratchingHead(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ case GRAB_CURSOR:
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS17Wrench:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFGrassTaken)) {
+ gnap.playImpossible();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 8, 7);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ case GRAB_CURSOR:
+ gnap.playScratchingHead(Common::Point(8, 7));
+ break;
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ case PLAT_CURSOR:
+ if (_canTryGetWrench) {
+ platHangUpPhone();
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(_vm->_hotspotsWalkPos[6] + Common::Point(1, 0), 1, 0x107C2, 1);
+ plat._actionStatus = kAS17TryGetWrench;
+ gnap._actionStatus = kAS17TryGetWrench;
+ _vm->_timers[5] = _vm->getRandom(30) + 80;
+ } else
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS17Phone1:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS17PutCoinIntoPhone;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[2], 1, 3);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(1, 3));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFUnk18)) {
+ platHangUpPhone();
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[2]) | 0x10000, 1);
+ gnap._actionStatus = kAS17GetCoinFromPhone;
+ } else
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ case PLAT_CURSOR:
+ if (_vm->isFlag(kGFUnk18)) {
+ platHangUpPhone();
+ _vm->_isLeavingScene = true;
+ gnap.useDeviceOnPlatypus();
+ plat._idleFacing = kDirUpLeft;
+ plat.walkTo(_vm->_hotspotsWalkPos[2], 1, 0x107C2, 1);
+ _vm->setFlag(kGFUnk16);
+ plat._actionStatus = kAS17PlatUsePhone;
+ gnap._actionStatus = kAS17PlatUsePhone;
+ } else
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS17Phone2:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS17PutCoinIntoPhone;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[2], 1, 3);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(1, 3));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFUnk18)) {
+ platHangUpPhone();
+ _vm->_isLeavingScene = true;
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS17GnapUsePhone;
+ _vm->setFlag(kGFSpringTaken);
+ } else
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ case PLAT_CURSOR:
+ if (_vm->isFlag(kGFUnk18)) {
+ platHangUpPhone();
+ _vm->_isLeavingScene = true;
+ gnap.useDeviceOnPlatypus();
+ plat._idleFacing = kDirUpLeft;
+ plat.walkTo(_vm->_hotspotsWalkPos[2], 1, 0x107C2, 1);
+ _vm->setFlag(kGFUnk16);
+ plat._actionStatus = kAS17PlatUsePhone;
+ gnap._actionStatus = kAS17PlatUsePhone;
+ } else
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS17ExitToyStore:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 18;
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[5], 0, 0x107BB, 1);
+ gnap._actionStatus = kAS17LeaveScene;
+ if (plat._actionStatus != kAS17PlatPhoningAssistant)
+ plat.walkTo(_vm->_hotspotsWalkPos[5] + Common::Point(-1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS17ExitGrubCity:
+ if (gnap._actionStatus < 0) {
+ platHangUpPhone();
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 20;
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, 0x107BC, 1);
+ gnap._actionStatus = kAS17LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[3] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS17WalkArea1:
+ case kHS17WalkArea2:
+ case kHS17WalkArea3:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = 0;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x10940))
+ _vm->playSound(0x10940, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0)
+ plat.updateIdleSequence2();
+ gnap.updateIdleSequence2();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(100) + 200;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0)
+ gameSys.insertSequence(0x22B, 21, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ if (!_vm->_timers[7]) {
+ _vm->_timers[7] = _vm->getRandom(100) + 100;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0) {
+ switch (_vm->getRandom(3)) {
+ case 0:
+ gameSys.insertSequence(0x25C, 255, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 1:
+ gameSys.insertSequence(0x25D, 255, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 2:
+ gameSys.insertSequence(0x25E, 255, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ }
+ }
+ }
+ if (plat._actionStatus < 0 && !_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(30) + 80;
+ if (_vm->isFlag(kGFGrassTaken) && _nextWrenchSequenceId == -1) {
+ _nextWrenchSequenceId = 0x236;
+ } else if (_canTryGetWrench) {
+ switch (_vm->getRandom(6)) {
+ case 0:
+ _nextWrenchSequenceId = 0x231;
+ break;
+ case 1:
+ _nextWrenchSequenceId = 0x232;
+ break;
+ case 2:
+ case 3:
+ _nextWrenchSequenceId = 0x23C;
+ break;
+ case 4:
+ case 5:
+ _nextWrenchSequenceId = 0x22E;
+ break;
+ }
+ } else {
+ --_wrenchCtr;
+ if (_wrenchCtr) {
+ switch (_vm->getRandom(6)) {
+ case 0:
+ _nextWrenchSequenceId = 0x237;
+ break;
+ case 1:
+ _nextWrenchSequenceId = 0x238;
+ break;
+ case 2:
+ _nextWrenchSequenceId = 0x239;
+ break;
+ case 3:
+ _nextWrenchSequenceId = 0x23A;
+ break;
+ case 4:
+ _nextWrenchSequenceId = 0x23B;
+ break;
+ case 5:
+ _nextWrenchSequenceId = 0x235;
+ break;
+ }
+ } else {
+ _wrenchCtr = 2;
+ _nextWrenchSequenceId = 0x235;
+ }
+ }
+ }
+ if (!_vm->_timers[6]) {
+ _vm->_timers[6] = _vm->getRandom(30) + 200;
+ if (_nextCarWindowSequenceId == -1 && !_vm->isFlag(kGFGrassTaken))
+ _nextCarWindowSequenceId = 0x246;
+ }
+ _vm->playSoundA();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene17::updateAnimations() {
+ static const int kPlatPhoneSequenceIds[] = {
+ 0x251, 0x252, 0x253, 0x254, 0x255, 0x256, 0x257
+ };
+
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS17GetWrench1:
+ gnap._actionStatus = kAS17GetWrenchGnapReady;
+ break;
+ case kAS17GetCoinFromPhone:
+ gnap.playPullOutDevice(Common::Point(1, 3));
+ gnap.playUseDevice();
+ gameSys.setAnimation(0x250, 100, 0);
+ gameSys.insertSequence(0x250, 100, 591, 100, kSeqSyncWait, 0, 0, 0);
+ _vm->invAdd(kItemDiceQuarterHole);
+ _vm->clearFlag(kGFUnk18);
+ gnap._actionStatus = kAS17GetCoinFromPhoneDone;
+ break;
+ case kAS17GetCoinFromPhoneDone:
+ _vm->setGrabCursorSprite(kItemDiceQuarterHole);
+ gnap._actionStatus = -1;
+ break;
+ case kAS17PutCoinIntoPhone:
+ gameSys.setAnimation(0x24C, gnap._id, 0);
+ gameSys.insertSequence(0x24C, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x24C;
+ _vm->invRemove(kItemDiceQuarterHole);
+ _vm->setGrabCursorSprite(-1);
+ _vm->setFlag(kGFUnk18);
+ gnap._actionStatus = kAS17PutCoinIntoPhoneDone;
+ break;
+ case kAS17PutCoinIntoPhoneDone:
+ gameSys.insertSequence(0x24F, 100, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._actionStatus = -1;
+ break;
+ case kAS17GnapUsePhone:
+ gameSys.setAnimation(0x24D, gnap._id, 0);
+ gameSys.insertSequence(0x24D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = kAS17LeaveScene;
+ _vm->_newSceneNum = 53;
+ break;
+ case kAS17GnapHangUpPhone:
+ gameSys.insertSequence(0x258, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x258;
+ gnap._actionStatus = -1;
+ break;
+ case kAS17LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ switch (plat._actionStatus) {
+ case kAS17TryGetWrench:
+ plat._actionStatus = -1;
+ ++_platTryGetWrenchCtr;
+ if (_platTryGetWrenchCtr % 2 != 0)
+ _nextWrenchSequenceId = 0x233;
+ else
+ _nextWrenchSequenceId = 0x234;
+ _canTryGetWrench = false;
+ break;
+ case kAS17GetWrench1:
+ _nextWrenchSequenceId = 0x230;
+ break;
+ case kAS17GetWrench2:
+ _nextCarWindowSequenceId = 0x249;
+ break;
+ case kAS17GetWrenchDone:
+ plat._actionStatus = -1;
+ _vm->invAdd(kItemWrench);
+ _vm->setGrabCursorSprite(kItemWrench);
+ break;
+ case kAS17PlatUsePhone:
+ gameSys.setAnimation(0x24E, plat._id, 1);
+ gameSys.insertSequence(0x24E, plat._id, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceDatNum = 0;
+ plat._sequenceId = 0x24E;
+ plat._actionStatus = kAS17LeaveScene;
+ _vm->_newSceneNum = 53;
+ break;
+ case kAS17PlatPhoningAssistant:
+ ++_platPhoneCtr;
+ if (_platPhoneCtr >= 7) {
+ _platPhoneCtr = 0;
+ _nextPhoneSequenceId = -1;
+ _currPhoneSequenceId = -1;
+ gameSys.insertSequence(0x25B, plat._id, 0x25A, plat._id, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceDatNum = 0;
+ plat._sequenceId = 0x25B;
+ plat._actionStatus = -1;
+ _vm->clearFlag(kGFPlatypusTalkingToAssistant);
+ _vm->_sceneWaiting = false;
+ updateHotspots();
+ } else {
+ _nextPhoneSequenceId = kPlatPhoneSequenceIds[_platPhoneCtr];
+ gameSys.setAnimation(_nextPhoneSequenceId, 254, 1);
+ gameSys.insertSequence(_nextPhoneSequenceId, 254, _currPhoneSequenceId, 254, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x25A, plat._id, 0x25A, plat._id, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceDatNum = 0;
+ plat._sequenceId = 0x25A;
+ _currPhoneSequenceId = _nextPhoneSequenceId;
+ }
+ break;
+ case kAS17LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ switch (_nextWrenchSequenceId) {
+ case 0x233:
+ gnap._actionStatus = -1;
+ gameSys.insertSequence(0x243, plat._id,
+ plat._sequenceId | (plat._sequenceDatNum << 16), plat._id,
+ kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(_nextWrenchSequenceId, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currWrenchSequenceId = _nextWrenchSequenceId;
+ _nextWrenchSequenceId = -1;
+ plat._sequenceId = 0x243;
+ plat._sequenceDatNum = 0;
+ gameSys.setAnimation(0x243, plat._id, 1);
+ break;
+ case 0x234:
+ gnap._actionStatus = -1;
+ gameSys.insertSequence(0x242, plat._id,
+ plat._sequenceId | (plat._sequenceDatNum << 16), plat._id,
+ kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(_nextWrenchSequenceId, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currWrenchSequenceId = _nextWrenchSequenceId;
+ _nextWrenchSequenceId = -1;
+ plat._sequenceId = 0x242;
+ plat._sequenceDatNum = 0;
+ gameSys.setAnimation(0x242, plat._id, 1);
+ break;
+ case 0x231:
+ if (_vm->getRandom(2) != 0)
+ _nextCarWindowSequenceId = 0x245;
+ else
+ _nextCarWindowSequenceId = 0x248;
+ gameSys.setAnimation(0, 0, 2);
+ break;
+ case 0x232:
+ _nextCarWindowSequenceId = 0x247;
+ gameSys.setAnimation(0, 0, 2);
+ break;
+ case 0x22E:
+ case 0x235:
+ if (_nextWrenchSequenceId == 0x235)
+ _vm->_hotspots[kHS17Wrench]._flags &= ~SF_DISABLED;
+ else
+ _vm->_hotspots[kHS17Wrench]._flags |= SF_DISABLED;
+ _canTryGetWrench = !_canTryGetWrench;
+ gameSys.setAnimation(_nextWrenchSequenceId, 40, 2);
+ gameSys.insertSequence(_nextWrenchSequenceId, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currWrenchSequenceId = _nextWrenchSequenceId;
+ _nextWrenchSequenceId = -1;
+ break;
+ case 0x230:
+ if (gnap._actionStatus == kAS17GetWrenchGnapReady) {
+ gameSys.setAnimation(0, 0, 2);
+ if (_canTryGetWrench) {
+ gameSys.insertSequence(0x22E, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currWrenchSequenceId = 0x22E;
+ _canTryGetWrench = false;
+ }
+ gameSys.setAnimation(0x23F, plat._id, 1);
+ gameSys.insertSequence(0x10875, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x23F, plat._id,
+ plat._sequenceId | (plat._sequenceDatNum << 16), plat._id,
+ kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 1;
+ plat._sequenceDatNum = 0;
+ gnap._sequenceId = 0x875;
+ plat._sequenceId = 0x23F;
+ gnap.walkTo(Common::Point(3, 8), -1, 0x107B9, 1);
+ plat._actionStatus = kAS17GetWrench2;
+ }
+ break;
+ default:
+ if (_nextWrenchSequenceId != -1) {
+ gameSys.setAnimation(_nextWrenchSequenceId, 40, 2);
+ gameSys.insertSequence(_nextWrenchSequenceId, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currWrenchSequenceId = _nextWrenchSequenceId;
+ _nextWrenchSequenceId = -1;
+ }
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ switch (_nextCarWindowSequenceId) {
+ case 0x246:
+ gameSys.setAnimation(_nextCarWindowSequenceId, 40, 3);
+ gameSys.insertSequence(_nextCarWindowSequenceId, 40, _currCarWindowSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currCarWindowSequenceId = _nextCarWindowSequenceId;
+ _nextCarWindowSequenceId = -1;
+ break;
+ case 0x245:
+ case 0x247:
+ case 0x248:
+ gameSys.setAnimation(_nextWrenchSequenceId, 40, 2);
+ gameSys.insertSequence(_nextWrenchSequenceId, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(2) != 2)
+ update();
+ gameSys.setAnimation(_nextCarWindowSequenceId, 40, 3);
+ gameSys.insertSequence(_nextCarWindowSequenceId, 40, _currCarWindowSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currCarWindowSequenceId = _nextCarWindowSequenceId;
+ _nextCarWindowSequenceId = -1;
+ _currWrenchSequenceId = _nextWrenchSequenceId;
+ _nextWrenchSequenceId = -1;
+ break;
+ case 0x249:
+ gameSys.setAnimation(0x230, 40, 2);
+ gameSys.setAnimation(0x240, plat._id, 1);
+ gameSys.insertSequence(0x230, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(_nextCarWindowSequenceId, 40, _currCarWindowSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x240, plat._id, plat._sequenceId, plat._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x23E, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x23E;
+ gnap._sequenceDatNum = 0;
+ plat._sequenceId = 0x240;
+ plat._sequenceDatNum = 0;
+ gameSys.setAnimation(0x24A, 40, 3);
+ gameSys.insertSequence(0x24A, 40, _nextCarWindowSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(2) != 2) {
+ update();
+ if (gameSys.getAnimationStatus(3) == 2) {
+ gameSys.setAnimation(0x24A, 40, 3);
+ gameSys.insertSequence(0x24A, 40, 586, 40, kSeqSyncWait, 0, 0, 0);
+ }
+ }
+ gameSys.insertSequence(0x22D, 40, 560, 40, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x24B, 40, 3);
+ gameSys.insertSequence(0x24B, 40, 586, 40, kSeqSyncWait, 0, 0, 0);
+ _currCarWindowSequenceId = 0x24B;
+ _nextCarWindowSequenceId = -1;
+ _currWrenchSequenceId = 0x22D;
+ _nextWrenchSequenceId = -1;
+ _vm->setFlag(kGFGrassTaken);
+ gnap._actionStatus = -1;
+ plat._actionStatus = 2;
+ updateHotspots();
+ _vm->_timers[5] = _vm->getRandom(30) + 80;
+ break;
+ }
+ }
+
+}
+
+/*****************************************************************************/
+
+static const int kScene18SequenceIds[] = {
+ 0x219, 0x21A, 0x21B, 0x21C, 0x21D
+};
+
+Scene18::Scene18(GnapEngine *vm) : Scene(vm) {
+ _cowboyHatSurface = nullptr;
+
+ _platPhoneCtr = 0;
+ _platPhoneIter = 0;
+ _nextPhoneSequenceId = -1;
+ _currPhoneSequenceId = -1;
+}
+
+Scene18::~Scene18() {
+ delete _cowboyHatSurface;
+}
+
+int Scene18::init() {
+ _vm->_gameSys->setAnimation(0, 0, 3);
+ return 0x222;
+}
+
+void Scene18::updateHotspots() {
+ _vm->setHotspot(kHS18Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS18GarbageCan, _vm->_gridMinX + 75 * _vm->_s18GarbageCanPos - 35, _vm->_gridMinY + 230, _vm->_gridMinX + 75 * _vm->_s18GarbageCanPos + 35, _vm->_gridMinY + 318,
+ SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, _vm->_s18GarbageCanPos, 7);
+ _vm->setHotspot(kHS18ExitToyStore, 460, 238, 592, 442, SF_EXIT_U_CURSOR, 7, 7);
+ _vm->setHotspot(kHS18ExitPhoneBooth, 275, 585, 525, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 10);
+ _vm->setHotspot(kHS18ExitGrubCity, 0, 350, 15, 600, SF_EXIT_L_CURSOR, 0, 9);
+ _vm->setHotspot(kHS18HydrantTopValve, 100, 345, 182, 410, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 8);
+ _vm->setHotspot(kHS18HydrantRightValve, 168, 423, 224, 470, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 7);
+ _vm->setHotspot(kHS18CowboyHat, 184, 63, 289, 171, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 7);
+ _vm->setHotspot(kHS18WalkArea1, 0, 0, 800, 448);
+ _vm->setHotspot(kHS18WalkArea2, 0, 0, 214, 515);
+ _vm->setDeviceHotspot(kHS18Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFTruckFilledWithGas)) {
+ if (_vm->isFlag(kGFTruckKeysUsed)) {
+ _vm->_hotspots[kHS18HydrantTopValve]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS18HydrantRightValve]._rect.left = 148;
+ _vm->_hotspots[kHS18HydrantRightValve]._rect.top = 403;
+ _vm->_hotspots[kHS18GarbageCan]._flags = SF_DISABLED;
+ _vm->_hotspotsWalkPos[kHS18GarbageCan] = Common::Point(3, 7);
+ } else {
+ _vm->_hotspots[kHS18HydrantTopValve]._rect.top = 246;
+ }
+ } else if (_vm->isFlag(kGFBarnPadlockOpen)) {
+ _vm->_hotspots[kHS18HydrantRightValve]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS18HydrantTopValve]._rect.left = 105;
+ _vm->_hotspots[kHS18HydrantTopValve]._rect.right = 192;
+ } else if (_vm->isFlag(kGFTruckKeysUsed)) {
+ _vm->_hotspots[kHS18GarbageCan]._rect = Common::Rect(115, 365, 168, 470);
+ _vm->_hotspots[kHS18GarbageCan]._flags = SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ _vm->_hotspotsWalkPos[kHS18GarbageCan] = Common::Point(3, 7);
+ }
+ if (_vm->isFlag(kGFPlatypusDisguised))
+ _vm->_hotspots[kHS18GarbageCan]._flags = SF_DISABLED;
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ _vm->_hotspots[kHS18Device]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS18HydrantTopValve]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS18HydrantRightValve]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS18Platypus]._flags = SF_DISABLED;
+ }
+ if (_vm->isFlag(kGFUnk14)) {
+ _vm->_hotspots[kHS18HydrantTopValve]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS18CowboyHat]._flags = SF_DISABLED;
+ }
+ _vm->_hotspotsCount = 11;
+}
+
+void Scene18::gnapCarryGarbageCanTo(int gridX) {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ int gnapSeqId, gnapId, gnapDatNum, gnapGridX;
+ int destGridX, direction;
+
+ int curGridX = (_vm->_leftClickMouseX - _vm->_gridMinX + 37) / 75;
+
+ if (curGridX >= gnap._pos.x)
+ destGridX = curGridX - 1;
+ else
+ destGridX = curGridX + 1;
+
+ if (gridX < 0)
+ gridX = 4;
+
+ if (destGridX <= gridX)
+ destGridX = gridX;
+
+ int nextGridX = _vm->_gridMaxX - 1;
+ if (nextGridX >= destGridX)
+ nextGridX = destGridX;
+
+ if (nextGridX == gnap._pos.x) {
+ gnapSeqId = gnap._sequenceId;
+ gnapId = gnap._id;
+ gnapDatNum = gnap._sequenceDatNum;
+ gnapGridX = gnap._pos.x;
+ if (gnap._pos.x <= curGridX)
+ direction = 1;
+ else
+ direction = -1;
+ } else {
+ PlayerPlat& plat = *_vm->_plat;
+ if (gnap._pos.y == plat._pos.y) {
+ if (nextGridX >= gnap._pos.x) {
+ if (nextGridX >= plat._pos.x && gnap._pos.x <= plat._pos.x)
+ plat.makeRoom();
+ } else if (nextGridX <= plat._pos.x && gnap._pos.x >= plat._pos.x) {
+ plat.makeRoom();
+ }
+ }
+ gnapSeqId = gnap._sequenceId;
+ gnapId = gnap._id;
+ gnapDatNum = gnap._sequenceDatNum;
+ gnapGridX = gnap._pos.x;
+ int seqId;
+ if (nextGridX < gnap._pos.x) {
+ direction = -1;
+ seqId = 0x204;
+ } else {
+ direction = 1;
+ seqId = 0x203;
+ }
+
+ int seqId2 = 20 * gnap._pos.y + 1;
+ do {
+ if (_vm->isPointBlocked(gnapGridX + direction, gnap._pos.y))
+ break;
+ seqId2 += direction;
+ gameSys.insertSequence(seqId, seqId2,
+ gnapSeqId | (gnapDatNum << 16), gnapId,
+ kSeqSyncWait, 0, 75 * gnapGridX - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnapSeqId = seqId;
+ gnapId = seqId2;
+ gnapDatNum = 0;
+ gnapGridX += direction;
+ } while (nextGridX != gnapGridX);
+ }
+
+ if (direction == 1)
+ gnap._sequenceId = 0x20A;
+ else
+ gnap._sequenceId = 0x209;
+ gnap._sequenceDatNum = 0;
+
+ if (direction == 1)
+ gnap._idleFacing = kDirBottomRight;
+ else
+ gnap._idleFacing = kDirBottomLeft;
+
+ gnap._id = 20 * gnap._pos.y + 1;
+
+ gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0);
+ gameSys.insertSequence(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ gnapSeqId | (gnapDatNum << 16), gnapId,
+ kSeqScale | kSeqSyncWait, 0, 75 * gnapGridX - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+
+ gnap._pos.x = gnapGridX;
+}
+
+void Scene18::putDownGarbageCan(int animationIndex) {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (animationIndex >= 0) {
+ while (gameSys.getAnimationStatus(animationIndex) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ }
+ if (gnap._idleFacing != kDirIdleLeft && gnap._idleFacing != kDirBottomRight && gnap._idleFacing != kDirUpRight)
+ _vm->_s18GarbageCanPos = gnap._pos.x - 1;
+ else
+ _vm->_s18GarbageCanPos = gnap._pos.x + 1;
+ _vm->clearFlag(kGFPlatypusDisguised);
+ updateHotspots();
+ if (gnap._idleFacing != kDirIdleLeft && gnap._idleFacing != kDirBottomRight && gnap._idleFacing != kDirUpRight) {
+ gameSys.insertSequence(0x107BA, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = 0x7BA;
+ } else {
+ gameSys.insertSequence(0x107B9, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = 0x7B9;
+ }
+ gnap._sequenceDatNum = 1;
+ gameSys.insertSequence(0x1FB, 19, 0, 0, kSeqNone, 0, 15 * (5 * _vm->_s18GarbageCanPos - 40), 0);
+ gameSys.setAnimation(0x1FA, 19, 4);
+ gameSys.insertSequence(0x1FA, 19, 507, 19, kSeqSyncWait, 0, 15 * (5 * _vm->_s18GarbageCanPos - 40), 0);
+ while (gameSys.getAnimationStatus(4) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+}
+
+void Scene18::platEndPhoning(bool platFl) {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ _platPhoneIter = 0;
+ _platPhoneCtr = 0;
+ plat._actionStatus = -1;
+ if (_currPhoneSequenceId != -1) {
+ gameSys.setAnimation(0x21E, 254, 3);
+ gameSys.insertSequence(0x21E, 254, _currPhoneSequenceId, 254, kSeqSyncExists, 0, 0, 0);
+ while (gameSys.getAnimationStatus(3) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ }
+ gameSys.removeSequence(0x21F, 254, true);
+ gameSys.setAnimation(0, 0, 3);
+ _vm->clearFlag(kGFPlatypusTalkingToAssistant);
+ if (platFl) {
+ plat._actionStatus = kAS18PlatComesHere;
+ _vm->_timers[6] = 50;
+ _vm->_sceneWaiting = true;
+ }
+ _currPhoneSequenceId = -1;
+ _nextPhoneSequenceId = -1;
+ updateHotspots();
+ }
+}
+
+void Scene18::closeHydrantValve() {
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ gnap._actionStatus = kAS18LeaveScene;
+ _vm->updateMouseCursor();
+ if (_vm->isFlag(kGFTruckFilledWithGas)) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18HydrantRightValve], 0, 0x107BA, 1);
+ if (_vm->isFlag(kGFTruckKeysUsed)) {
+ gnap._actionStatus = kAS18CloseRightValveWithGarbageCan;
+ waitForGnapAction();
+ } else {
+ gnap._actionStatus = kAS18CloseRightValveNoGarbageCan;
+ waitForGnapAction();
+ }
+ } else if (_vm->isFlag(kGFBarnPadlockOpen)) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18HydrantTopValve], 0, 0x107BA, 1);
+ gnap._actionStatus = kAS18CloseTopValve;
+ waitForGnapAction();
+ }
+}
+
+void Scene18::waitForGnapAction() {
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ while (gnap._actionStatus >= 0 && !_vm->_gameDone) {
+ updateAnimations();
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene18::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _cowboyHatSurface = nullptr;
+
+ _vm->playSound(0x10940, true);
+ _vm->startSoundTimerA(4);
+ _vm->_timers[5] = _vm->getRandom(100) + 100;
+ _vm->queueInsertDeviceIcon();
+ _vm->clearFlag(kGFPlatypusDisguised);
+
+ if (!_vm->isFlag(kGFUnk14))
+ gameSys.insertSequence(0x1F8, 19, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFTruckKeysUsed)) {
+ if (_vm->isFlag(kGFTruckFilledWithGas)) {
+ gameSys.insertSequence(0x214, 39, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x20D, 39, 0, 0, kSeqLoop, 0, 0, 0);
+ _vm->playSound(0x22B, true);
+ } else {
+ gameSys.insertSequence(0x1F9, 19, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ } else {
+ gameSys.insertSequence(0x1FA, 19, 0, 0, kSeqNone, 0, 15 * (5 * _vm->_s18GarbageCanPos - 40), 0);
+ if (_vm->isFlag(kGFTruckFilledWithGas)) {
+ gameSys.insertSequence(0x212, 39, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x20D, 39, 0, 0, kSeqLoop, 0, 0, 0);
+ _vm->playSound(0x22B, true);
+ } else if (_vm->isFlag(kGFBarnPadlockOpen)) {
+ gameSys.insertSequence(0x20E, 39, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x217, 39, 0, 0, kSeqLoop, 0, 0, 0);
+ _vm->playSound(0x22B, true);
+ }
+ }
+
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ if (_vm->_prevSceneNum == 17)
+ gnap.initPos(4, 11, kDirBottomRight);
+ else
+ gnap.initPos(4, 7, kDirBottomRight);
+ _platPhoneCtr = _vm->getRandom(5);
+ if (_vm->isFlag(kGFUnk27)) {
+ gameSys.insertSequence(0x21E, 254, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+ _currPhoneSequenceId = -1;
+ platEndPhoning(true);
+ _vm->clearFlag(kGFUnk27);
+ } else {
+ _currPhoneSequenceId = kScene18SequenceIds[_platPhoneCtr];
+ _platPhoneIter = 0;
+ gameSys.insertSequence(0x21F, 254, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(_currPhoneSequenceId, 254, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+ }
+ if (_vm->isFlag(kGFUnk27)) {
+ platEndPhoning(true);
+ _vm->clearFlag(kGFUnk27);
+ } else {
+ gameSys.setAnimation(_currPhoneSequenceId, 254, 3);
+ }
+ gnap.walkTo(Common::Point(4, 8), -1, 0x107B9, 1);
+ } else {
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->clearFlag(kGFGnapControlsToyUFO);
+ _vm->setGrabCursorSprite(kItemCowboyHat);
+ _vm->_prevSceneNum = 19;
+ }
+ if (_vm->_prevSceneNum == 17) {
+ gnap.initPos(4, 11, kDirBottomRight);
+ plat.initPos(5, 11, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(4, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(5, 9), -1, 0x107C2, 1);
+ } else if (_vm->_prevSceneNum == 19) {
+ gnap.initPos(7, 7, kDirBottomRight);
+ plat.initPos(8, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(7, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(8, 8), -1, 0x107C2, 1);
+ } else {
+ gnap.initPos(-1, 10, kDirBottomRight);
+ plat.initPos(-1, 10, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(3, 7), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(3, 8), -1, 0x107C2, 1);
+ }
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 20, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS18Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS18Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ }
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, plat._pos.x, plat._pos.y);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS18CowboyHat:
+ if (gnap._actionStatus == kAS18StandingOnHydrant) {
+ gnap._actionStatus = kAS18GrabCowboyHat;
+ _vm->_sceneWaiting = false;
+ } else if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ }
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS18CowboyHat], 3, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(3, 2));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18CowboyHat], 0, gnap.getSequenceId(kGSPullOutDeviceNonWorking, Common::Point(3, 2)) | 0x10000, 1);
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS18GarbageCan:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFUnk14)) {
+ if (_vm->_grabCursorSpriteIndex >= 0)
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS18GarbageCan], 1, 5);
+ else
+ gnap.playImpossible();
+ } else {
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant))
+ platEndPhoning(true);
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ if (!_vm->isFlag(kGFTruckKeysUsed)) {
+ Common::Point destPos;
+ destPos.x = _vm->_hotspotsWalkPos[kHS18GarbageCan].x - (gnap._pos.x < _vm->_s18GarbageCanPos ? 1 : -1);
+ destPos.y = _vm->_hotspotsWalkPos[kHS18GarbageCan].y;
+ gnap.playShowCurrItem(destPos, _vm->_hotspotsWalkPos[kHS18GarbageCan].x, _vm->_hotspotsWalkPos[kHS18GarbageCan].y);
+ } else
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS18GarbageCan], 2, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (!_vm->isFlag(kGFTruckKeysUsed))
+ gnap.playScratchingHead(Common::Point(_vm->_hotspotsWalkPos[kHS18GarbageCan].x - (gnap._pos.x < _vm->_s18GarbageCanPos ? 1 : -1), _vm->_hotspotsWalkPos[kHS18GarbageCan].y));
+ else if (!_vm->isFlag(kGFTruckFilledWithGas))
+ gnap.playScratchingHead(Common::Point(2, 4));
+ break;
+ case GRAB_CURSOR:
+ if (!_vm->isFlag(kGFTruckKeysUsed)) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18GarbageCan] + Common::Point((gnap._pos.x < _vm->_s18GarbageCanPos ? 1 : -1), 0),
+ -1, -1, 1);
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, Common::Point(_vm->_s18GarbageCanPos, gnap._pos.y)) | 0x10000, 1);
+ gnap._actionStatus = kAS18GrabGarbageCanFromStreet;
+ } else if (!_vm->isFlag(kGFTruckFilledWithGas)) {
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[kHS18GarbageCan], 0, -1, 1))
+ gnap._actionStatus = kAS18GrabGarbageCanFromHydrant;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case kHS18HydrantTopValve:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ // While carrying garbage can
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 0, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ gnap.playScratchingHead();
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFTruckFilledWithGas)) {
+ gnapCarryGarbageCanTo(2);
+ gnap._actionStatus = kAS18PutGarbageCanOnRunningHydrant;
+ } else if (!_vm->isFlag(kGFBarnPadlockOpen)) {
+ gnapCarryGarbageCanTo(2);
+ gnap._actionStatus = kAS18PutGarbageCanOnHydrant;
+ } else {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ gnap.playImpossible();
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ gnap.playImpossible();
+ break;
+ }
+ }
+ } else {
+ if (_vm->_grabCursorSpriteIndex == kItemWrench) {
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 8)) | 0x10000, 1);
+ gnap._actionStatus = kAS18OpenTopValve;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS18HydrantTopValve], 1, 5);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(1, 5));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFBarnPadlockOpen)) {
+ _vm->_hotspots[kHS18WalkArea2]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18HydrantTopValve], 0, 0x107BA, 1);
+ _vm->_hotspots[kHS18WalkArea2]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = kAS18CloseTopValve;
+ } else
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case kHS18HydrantRightValve:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFUnk14)) {
+ if (_vm->_grabCursorSpriteIndex == -1) {
+ gnap.playImpossible();
+ } else {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS18HydrantRightValve], 1, 5);
+ }
+ } else {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ }
+ if (_vm->_grabCursorSpriteIndex == kItemWrench) {
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 8)) | 0x10000, 1);
+ if (_vm->isFlag(kGFTruckKeysUsed))
+ gnap._actionStatus = kAS18OpenRightValveWithGarbageCan;
+ else
+ gnap._actionStatus = kAS18OpenRightValveNoGarbageCan;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS18HydrantRightValve], 1, 5);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(1, 5));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFTruckFilledWithGas)) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18HydrantRightValve], 0, 0x107BA, 1);
+ if (_vm->isFlag(kGFTruckKeysUsed))
+ gnap._actionStatus = kAS18CloseRightValveWithGarbageCan;
+ else
+ gnap._actionStatus = kAS18CloseRightValveNoGarbageCan;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case kHS18ExitToyStore:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ }
+ if (_vm->isFlag(kGFPictureTaken)) {
+ gnap.playImpossible();
+ } else {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 19;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18ExitToyStore], 0, 0x107C0, 1);
+ gnap._actionStatus = kAS18LeaveScene;
+ if (!_vm->isFlag(kGFPlatypusTalkingToAssistant))
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS18ExitToyStore] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ }
+ break;
+
+ case kHS18ExitPhoneBooth:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ }
+ closeHydrantValve();
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 17;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18ExitPhoneBooth], 0, 0x107AE, 1);
+ gnap._actionStatus = kAS18LeaveScene;
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant))
+ _vm->setFlag(kGFUnk27);
+ else
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS18ExitPhoneBooth] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS18ExitGrubCity:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ }
+ closeHydrantValve();
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 20;
+ _vm->_hotspots[kHS18WalkArea2]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18ExitGrubCity], 0, 0x107B2, 1);
+ gnap._actionStatus = kAS18LeaveScene;
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant))
+ platEndPhoning(false);
+ else
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS18ExitGrubCity] + Common::Point(0, -1), -1, 0x107CF, 1);
+ _vm->_hotspots[kHS18WalkArea2]._flags &= ~SF_WALKABLE;
+ }
+ break;
+
+ case kHS18WalkArea1:
+ case kHS18WalkArea2:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ } else {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ }
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ default:
+ if (gnap._actionStatus != kAS18StandingOnHydrant && _vm->_mouseClickState._left) {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ } else {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ }
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x10940))
+ _vm->playSound(0x10940, true);
+
+ if ((_vm->isFlag(kGFTruckFilledWithGas) || _vm->isFlag(kGFBarnPadlockOpen)) && !_vm->isSoundPlaying(0x22B) &&
+ gnap._actionStatus != kAS18OpenRightValveNoGarbageCanDone && gnap._actionStatus != kAS18OpenRightValveNoGarbageCan &&
+ gnap._actionStatus != kAS18OpenTopValve && gnap._actionStatus != kAS18OpenTopValveDone &&
+ gnap._actionStatus != kAS18OpenRightValveWithGarbageCan && gnap._actionStatus != kAS18OpenRightValveWithGarbageCanDone)
+ _vm->playSound(0x22B, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (!_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ if (plat._actionStatus == kAS18PlatComesHere) {
+ if (!_vm->_timers[6]) {
+ plat._actionStatus = -1;
+ _vm->_sceneWaiting = false;
+ plat.initPos(-1, 10, kDirIdleLeft);
+ plat.walkTo(Common::Point(3, 9), -1, 0x107C2, 1);
+ _vm->clearFlag(kGFPlatypusTalkingToAssistant);
+ }
+ } else {
+ _vm->_hotspots[kHS18WalkArea1]._rect.bottom += 48;
+ _vm->_hotspots[kHS18WalkArea2]._rect.left += 75;
+ plat.updateIdleSequence();
+ _vm->_hotspots[kHS18WalkArea2]._rect.left -= 75;
+ _vm->_hotspots[kHS18WalkArea1]._rect.bottom -= 48;
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(100) + 100;
+ if (gnap._actionStatus < 0) {
+ if (_vm->getRandom(2) == 1)
+ gameSys.insertSequence(0x220, 255, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x221, 255, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ }
+ _vm->playSoundA();
+ }
+ if (!_vm->isFlag(kGFPlatypusDisguised))
+ gnap.updateIdleSequence();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO))
+ _vm->deleteSurface(&_cowboyHatSurface);
+}
+
+void Scene18::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS18GrabGarbageCanFromStreet:
+ if (gnap._idleFacing != kDirUpRight && gnap._idleFacing != kDirBottomRight) {
+ gameSys.insertSequence(0x1FC, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - 675, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x1FC;
+ } else {
+ gameSys.insertSequence(0x1FD, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - 525, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x1FD;
+ }
+ gameSys.removeSequence(0x1FA, 19, true);
+ _vm->setFlag(kGFPlatypusDisguised);
+ updateHotspots();
+ gnap._actionStatus = -1;
+ break;
+ case kAS18GrabGarbageCanFromHydrant:
+ gameSys.insertSequence(0x1FE, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(0x1F9, 19, true);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x1FE;
+ _vm->clearFlag(kGFTruckKeysUsed);
+ _vm->setFlag(kGFPlatypusDisguised);
+ updateHotspots();
+ gnap._actionStatus = -1;
+ break;
+ case kAS18CloseRightValveNoGarbageCan:
+ gameSys.insertSequence(0x205, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(0x20D, 39, true);
+ gameSys.removeSequence(0x212, 39, true);
+ gameSys.removeSequence(0x211, 39, true);
+ _vm->stopSound(0x22B);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x205;
+ _vm->clearFlag(kGFTruckFilledWithGas);
+ _vm->invAdd(kItemWrench);
+ _vm->setGrabCursorSprite(kItemWrench);
+ updateHotspots();
+ gnap._actionStatus = -1;
+ break;
+ case kAS18OpenTopValve:
+ _vm->setFlag(kGFBarnPadlockOpen);
+ updateHotspots();
+ gnap.playPullOutDevice(Common::Point(2, 7));
+ gnap.playUseDevice();
+ gameSys.insertSequence(0x20C, 19, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_hotspots[kHS18WalkArea2]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18HydrantTopValve], 0, 0x107BB, 1);
+ _vm->_hotspots[kHS18WalkArea2]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = kAS18OpenTopValveDone;
+ break;
+ case kAS18OpenTopValveDone:
+ _vm->setGrabCursorSprite(-1);
+ gameSys.insertSequence(0x208, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x216, 39, 0, 0, kSeqNone, 21, 0, 0);
+ gameSys.removeSequence(0x20C, 19, true);
+ gameSys.setAnimation(0x217, 39, 5);
+ gameSys.insertSequence(0x217, 39, 0x216, 39, kSeqLoop | kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(5) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->playSound(0x22B, true);
+ gameSys.insertSequence(0x20E, 39, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x208;
+ _vm->invRemove(kItemWrench);
+ _vm->setGrabCursorSprite(-1);
+ gnap._actionStatus = -1;
+ break;
+ case kAS18CloseTopValve:
+ gameSys.insertSequence(0x206, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(0x20E, 39, true);
+ gameSys.removeSequence(0x216, 39, true);
+ gameSys.removeSequence(0x217, 39, true);
+ _vm->stopSound(0x22B);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x206;
+ _vm->clearFlag(kGFBarnPadlockOpen);
+ _vm->invAdd(kItemWrench);
+ _vm->setGrabCursorSprite(kItemWrench);
+ updateHotspots();
+ gnap._actionStatus = -1;
+ break;
+ case kAS18GrabCowboyHat:
+ gameSys.setAnimation(0x200, gnap._id, 0);
+ gameSys.insertSequence(0x200, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x200;
+ gnap._actionStatus = kAS18GrabCowboyHatDone;
+ break;
+ case kAS18GrabCowboyHatDone:
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+ _cowboyHatSurface = _vm->addFullScreenSprite(0x1D2, 255);
+ gameSys.setAnimation(0x218, 256, 0);
+ gameSys.insertSequence(0x218, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->_newSceneNum = 18;
+ _vm->invAdd(kItemCowboyHat);
+ _vm->invAdd(kItemWrench);
+ _vm->setFlag(kGFGnapControlsToyUFO);
+ _vm->setFlag(kGFUnk14);
+ _vm->clearFlag(kGFTruckFilledWithGas);
+ _vm->setFlag(kGFTruckKeysUsed);
+ _vm->setFlag(kGFUnk14); // Useless, already set
+ updateHotspots();
+ gnap._actionStatus = kAS18LeaveScene;
+ break;
+ case kAS18LeaveScene:
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ break;
+ case kAS18PutGarbageCanOnRunningHydrant:
+ _vm->setFlag(kGFTruckKeysUsed);
+ _vm->clearFlag(kGFPlatypusDisguised);
+ gameSys.requestRemoveSequence(0x211, 39);
+ gameSys.requestRemoveSequence(0x212, 39);
+ gameSys.insertSequence(0x210, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ _vm->stopSound(0x22B);
+ gameSys.setAnimation(0x210, gnap._id, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x210;
+ gnap._actionStatus = kAS18PutGarbageCanOnRunningHydrant2;
+ break;
+ case kAS18PutGarbageCanOnRunningHydrant2:
+ _vm->playSound(0x22B, true);
+ gameSys.setAnimation(0x1FF, gnap._id, 0);
+ gameSys.insertSequence(0x1FF, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x1FF;
+ _vm->_sceneWaiting = true;
+ gnap._actionStatus = kAS18StandingOnHydrant;
+ break;
+ case kAS18StandingOnHydrant:
+ gameSys.setAnimation(0x1FF, gnap._id, 0);
+ gameSys.insertSequence(0x1FF, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ break;
+ case kAS18OpenRightValveNoGarbageCan:
+ case kAS18OpenRightValveWithGarbageCan:
+ _vm->setFlag(kGFTruckFilledWithGas);
+ updateHotspots();
+ gnap.playPullOutDevice(Common::Point(2, 7));
+ gnap.playUseDevice();
+ gameSys.insertSequence(0x20B, 19, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_hotspots[kHS18WalkArea2]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18HydrantRightValve], 0, 0x107BA, 1);
+ _vm->_hotspots[kHS18WalkArea2]._flags &= ~SF_WALKABLE;
+ if (gnap._actionStatus == kAS18OpenRightValveNoGarbageCan)
+ gnap._actionStatus = kAS18OpenRightValveNoGarbageCanDone;
+ else
+ gnap._actionStatus = kAS18OpenRightValveWithGarbageCanDone;
+ break;
+ case kAS18OpenRightValveWithGarbageCanDone:
+ _vm->setGrabCursorSprite(-1);
+ gameSys.insertSequence(0x207, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x213, 39, 0, 0, kSeqNone, 21, 0, 0);
+ gameSys.requestRemoveSequence(0x1F9, 19);
+ gameSys.removeSequence(0x20B, 19, true);
+ gameSys.setAnimation(0x213, 39, 5);
+ gameSys.insertSequence(0x214, 39, 0x213, 39, kSeqLoop | kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(5) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->playSound(0x22B, true);
+ gameSys.insertSequence(0x20D, 39, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x207;
+ _vm->invRemove(kItemWrench);
+ gnap._actionStatus = -1;
+ break;
+ case kAS18OpenRightValveNoGarbageCanDone:
+ _vm->setGrabCursorSprite(-1);
+ gameSys.insertSequence(0x207, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x211, 39, 0, 0, kSeqNone, 21, 0, 0);
+ gameSys.removeSequence(0x20B, 19, true);
+ gameSys.setAnimation(0x211, 39, 5);
+ gameSys.insertSequence(0x212, 39, 0x211, 39, kSeqLoop | kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(5) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->playSound(0x22B, true);
+ gameSys.insertSequence(0x20D, 39, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x207;
+ _vm->invRemove(kItemWrench);
+ gnap._actionStatus = -1;
+ break;
+ case kAS18CloseRightValveWithGarbageCan:
+ gameSys.insertSequence(0x205, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(0x20D, 39, true);
+ gameSys.insertSequence(0x215, 39, 0x214, 39, kSeqSyncWait, 0, 0, 0);
+ _vm->stopSound(0x22B);
+ gameSys.setAnimation(0x1F9, 19, 0);
+ gameSys.insertSequence(0x1F9, 19, 0x215, 39, kSeqSyncWait, 0, 0, 0);
+ _vm->clearFlag(kGFTruckFilledWithGas);
+ _vm->invAdd(kItemWrench);
+ _vm->setGrabCursorSprite(kItemWrench);
+ gameSys.insertSequence(0x107B5, gnap._id, 517, gnap._id, kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ updateHotspots();
+ gnap._sequenceDatNum = 1;
+ gnap._sequenceId = 0x7B5;
+ gnap._actionStatus = kAS18CloseRightValveWithGarbageCanDone;
+ break;
+ case kAS18CloseRightValveWithGarbageCanDone:
+ gnap._actionStatus = -1;
+ break;
+ case kAS18PutGarbageCanOnHydrant:
+ _vm->setFlag(kGFTruckKeysUsed);
+ _vm->clearFlag(kGFPlatypusDisguised);
+ gameSys.insertSequence(0x20F, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x20F, gnap._id, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x20F;
+ gnap._actionStatus = kAS18PutGarbageCanOnHydrantDone;
+ break;
+ case kAS18PutGarbageCanOnHydrantDone:
+ gameSys.insertSequence(0x1F9, 19, 0x20F, gnap._id, kSeqNone, 0, 0, 0);
+ updateHotspots();
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ gameSys.setAnimation(0, 0, 3);
+ ++_platPhoneIter;
+ if (_platPhoneIter <= 4) {
+ ++_platPhoneCtr;
+ _nextPhoneSequenceId = kScene18SequenceIds[_platPhoneCtr % 5];
+ gameSys.setAnimation(_nextPhoneSequenceId, 254, 3);
+ gameSys.insertSequence(_nextPhoneSequenceId, 254, _currPhoneSequenceId, 254, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x21F, 254, 0x21F, 254, kSeqSyncWait, 0, 0, 0);
+ _currPhoneSequenceId = _nextPhoneSequenceId;
+ } else {
+ platEndPhoning(true);
+ }
+ }
+}
+
+/*****************************************************************************/
+
+static const int kS19ShopAssistantSequenceIds[] = {
+ 0x6F, 0x70, 0x71, 0x72, 0x73
+};
+
+Scene19::Scene19(GnapEngine *vm) : Scene(vm) {
+ _toyGrabCtr = 0;
+ _shopAssistantCtr = 0;
+ _currShopAssistantSequenceId = -1;
+ _nextShopAssistantSequenceId = -1;
+
+ _pictureSurface = nullptr;
+}
+
+Scene19::~Scene19() {
+ delete _pictureSurface;
+}
+
+int Scene19::init() {
+ _vm->playSound(0x79, false);
+ return _vm->isFlag(kGFPlatypusTalkingToAssistant) ? 0x77 : 0x76;
+}
+
+void Scene19::updateHotspots() {
+ _vm->setHotspot(kHS19Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS19ExitOutsideToyStore, 36, 154, 142, 338, SF_EXIT_NW_CURSOR, 4, 6);
+ _vm->setHotspot(kHS19Picture, 471, 237, 525, 283, SF_DISABLED, 7, 2);
+ _vm->setHotspot(kHS19ShopAssistant, 411, 151, 575, 279, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 7);
+ _vm->setHotspot(kHS19Phone, 647, 166, 693, 234, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 9, 0);
+ _vm->setHotspot(kHS19Toy1, 181, 11, 319, 149, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 0);
+ _vm->setHotspot(kHS19Toy2, 284, 85, 611, 216, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 0);
+ _vm->setHotspot(kHS19Toy3, 666, 38, 755, 154, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 9, 0);
+ _vm->setHotspot(kHS19Toy4, 154, 206, 285, 327, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 3);
+ _vm->setHotspot(kHS19Toy5, 494, 301, 570, 448, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 5);
+ _vm->setHotspot(kHS19Toy6, 0, 320, 188, 600, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 6);
+ _vm->setHotspot(kHS19Toy7, 597, 434, 800, 600, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 9, 8);
+ _vm->setHotspot(kHS19WalkArea1, 0, 0, 170, 600);
+ _vm->setHotspot(kHS19WalkArea2, 622, 0, 800, 600);
+ _vm->setHotspot(kHS19WalkArea3, 0, 0, 800, 437);
+ _vm->setDeviceHotspot(kHS19Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ _vm->_hotspots[kHS19Toy1]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Toy2]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Toy3]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Toy4]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Toy5]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Toy6]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Toy7]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19ShopAssistant]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Phone]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Platypus]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Picture]._flags = SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ }
+ _vm->_hotspotsCount = 16;
+}
+
+void Scene19::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+ _toyGrabCtr = 0;
+ _pictureSurface = nullptr;
+
+ gameSys.insertSequence(0x74, 254, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x75, 254, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (!_vm->isFlag(kGFPictureTaken))
+ gameSys.insertSequence(0x69, 19, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ gnap.initPos(3, 6, kDirBottomRight);
+ _currShopAssistantSequenceId = kS19ShopAssistantSequenceIds[_vm->getRandom(5)];
+ _nextShopAssistantSequenceId = _currShopAssistantSequenceId;
+ gameSys.setAnimation(_currShopAssistantSequenceId, 20, 4);
+ gameSys.insertSequence(0x6E, 254, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(_currShopAssistantSequenceId, 20, 0, 0, kSeqNone, 0, 0, 0);
+ _shopAssistantCtr = 0;
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(4, 9), -1, 0x107B9, 1);
+ updateHotspots();
+ } else {
+ _currShopAssistantSequenceId = 0x6D;
+ _nextShopAssistantSequenceId = -1;
+ gameSys.setAnimation(0x6D, 20, 4);
+ gameSys.insertSequence(_currShopAssistantSequenceId, 20, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_timers[6] = _vm->getRandom(40) + 50;
+ gnap.initPos(3, 6, kDirBottomRight);
+ plat.initPos(4, 6, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(4, 9), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(5, 9), -1, 0x107C2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 5, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS19Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS19Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS19ExitOutsideToyStore:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 18;
+ _vm->_hotspots[kHS19WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[1], 0, 0x107B2, 1);
+ gnap._actionStatus = kAS19LeaveScene;
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant))
+ _vm->setFlag(kGFUnk27);
+ else
+ plat.walkTo(_vm->_hotspotsWalkPos[1] + Common::Point(1, 0), -1, 0x107C5, 1);
+ _vm->_hotspots[kHS19WalkArea1]._flags &= ~SF_WALKABLE;
+ }
+ break;
+
+ case kHS19Picture:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 6, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(6, 2));
+ break;
+ case GRAB_CURSOR:
+ if (!_vm->isFlag(kGFPictureTaken)) {
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot]) | 0x10000, 1);
+ gnap._actionStatus = kAS19GrabPicture;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS19ShopAssistant:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 6, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(6, 2));
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS19TalkShopAssistant;
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS19Toy1:
+ case kHS19Toy2:
+ case kHS19Toy3:
+ case kHS19Toy4:
+ case kHS19Toy5:
+ case kHS19Toy6:
+ case kHS19Toy7:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot]);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot]);
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 0, -1, 1);
+ gnap.playIdle(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot]);
+ gnap._actionStatus = kAS19GrabToy;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS19Phone:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 9, 1);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(9, 1));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 0, -1, 1);
+ gnap.playIdle(Common::Point(8, 2));
+ gnap._actionStatus = kAS19UsePhone;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS19WalkArea1:
+ case kHS19WalkArea2:
+ case kHS19WalkArea3:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = 0;
+ }
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ gnap.updateIdleSequence();
+ if (!_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ plat.updateIdleSequence();
+ if (!_vm->_timers[6] && _nextShopAssistantSequenceId == -1) {
+ _vm->_timers[6] = _vm->getRandom(40) + 50;
+ if (_vm->getRandom(4) != 0) {
+ _nextShopAssistantSequenceId = 0x64;
+ } else if (_vm->isFlag(kGFPictureTaken)) {
+ _nextShopAssistantSequenceId = 0x64;
+ } else {
+ _nextShopAssistantSequenceId = 0x6C;
+ }
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+
+ if (_pictureSurface)
+ _vm->deleteSurface(&_pictureSurface);
+}
+
+void Scene19::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS19UsePhone:
+ _nextShopAssistantSequenceId = 0x67;
+ break;
+ case kAS19GrabToy:
+ ++_toyGrabCtr;
+ switch (_toyGrabCtr) {
+ case 1:
+ _nextShopAssistantSequenceId = 0x62;
+ break;
+ case 2:
+ _nextShopAssistantSequenceId = 0x6B;
+ break;
+ case 3:
+ _nextShopAssistantSequenceId = 0x66;
+ break;
+ default:
+ _nextShopAssistantSequenceId = 0x65;
+ break;
+ }
+ break;
+ case kAS19GrabPicture:
+ gnap.playPullOutDevice(Common::Point(6, 2));
+ gnap.playUseDevice();
+ gameSys.setAnimation(0x68, 19, 0);
+ gameSys.insertSequence(0x68, 19, 105, 19, kSeqSyncWait, 0, 0, 0);
+ _vm->invAdd(kItemPicture);
+ _vm->setFlag(kGFPictureTaken);
+ updateHotspots();
+ gnap._actionStatus = kAS19GrabPictureDone;
+ break;
+ case kAS19GrabPictureDone:
+ _vm->setGrabCursorSprite(-1);
+ _vm->hideCursor();
+ _pictureSurface = _vm->addFullScreenSprite(0xF, 255);
+ gameSys.setAnimation(0x61, 256, 0);
+ gameSys.insertSequence(0x61, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ _vm->setFlag(kGFUnk27);
+ _vm->showCursor();
+ _vm->_newSceneNum = 17;
+ _vm->_isLeavingScene = true;
+ _vm->_sceneDone = true;
+ _nextShopAssistantSequenceId = -1;
+ break;
+ case kAS19TalkShopAssistant:
+ _nextShopAssistantSequenceId = 0x6D;
+ gnap._actionStatus = -1;
+ break;
+ case kAS19LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2) {
+ switch (_nextShopAssistantSequenceId) {
+ case 0x6F:
+ case 0x70:
+ case 0x71:
+ case 0x72:
+ case 0x73:
+ _shopAssistantCtr = (_shopAssistantCtr + 1) % 5;
+ _nextShopAssistantSequenceId = kS19ShopAssistantSequenceIds[_shopAssistantCtr];
+ gameSys.setAnimation(_nextShopAssistantSequenceId, 20, 4);
+ gameSys.insertSequence(_nextShopAssistantSequenceId, 20, _currShopAssistantSequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x6E, 254, 0x6E, 254, kSeqSyncWait, 0, 0, 0);
+ _currShopAssistantSequenceId = _nextShopAssistantSequenceId;
+ break;
+ case 0x62:
+ case 0x66:
+ case 0x6B:
+ gameSys.setAnimation(_nextShopAssistantSequenceId, 20, 4);
+ gameSys.insertSequence(_nextShopAssistantSequenceId, 20, _currShopAssistantSequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currShopAssistantSequenceId = _nextShopAssistantSequenceId;
+ _nextShopAssistantSequenceId = -1;
+ _vm->_timers[5] = 10;
+ while (_vm->_timers[5] && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ gnap.playIdle(Common::Point(6, 2));
+ gnap._actionStatus = -1;
+ break;
+ case 0x67:
+ gameSys.setAnimation(_nextShopAssistantSequenceId, 20, 4);
+ gameSys.insertSequence(_nextShopAssistantSequenceId, 20, _currShopAssistantSequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currShopAssistantSequenceId = _nextShopAssistantSequenceId;
+ _nextShopAssistantSequenceId = -1;
+ gnap._actionStatus = -1;
+ break;
+ case 0x65:
+ gnap.playIdle(Common::Point(6, 2));
+ gameSys.setAnimation(_nextShopAssistantSequenceId, 20, 0);
+ gameSys.insertSequence(_nextShopAssistantSequenceId, 20, _currShopAssistantSequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currShopAssistantSequenceId = _nextShopAssistantSequenceId;
+ _nextShopAssistantSequenceId = -1;
+ _vm->_newSceneNum = 18;
+ gnap._actionStatus = kAS19LeaveScene;
+ break;
+ case 0x6D:
+ gameSys.setAnimation(_nextShopAssistantSequenceId, 20, 4);
+ gameSys.insertSequence(_nextShopAssistantSequenceId, 20, _currShopAssistantSequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x69, 19, 0x69, 19, kSeqSyncWait, _vm->getSequenceTotalDuration(_nextShopAssistantSequenceId), 0, 0);
+ _currShopAssistantSequenceId = _nextShopAssistantSequenceId;
+ _nextShopAssistantSequenceId = -1;
+ break;
+ case 0x64:
+ case 0x6C:
+ gameSys.setAnimation(_nextShopAssistantSequenceId, 20, 4);
+ gameSys.insertSequence(_nextShopAssistantSequenceId, 20, _currShopAssistantSequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currShopAssistantSequenceId = _nextShopAssistantSequenceId;
+ _nextShopAssistantSequenceId = -1;
+ break;
+ }
+ }
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/group1.h b/engines/gnap/scenes/group1.h
new file mode 100644
index 0000000000..30771d017a
--- /dev/null
+++ b/engines/gnap/scenes/group1.h
@@ -0,0 +1,454 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GNAP_GROUP1_H
+#define GNAP_GROUP1_H
+
+#include "gnap/debugger.h"
+
+namespace Gnap {
+
+enum {
+ kHS10Platypus = 0,
+ kHS10ExitBar = 1,
+ kHS10ExitBackdoor = 2,
+ kHS10Cook = 3,
+ kHS10Tongs = 4,
+ kHS10Box = 5,
+ kHS10Oven = 6,
+ kHS10WalkArea1 = 7,
+ kHS10Device = 8,
+ kHS10WalkArea2 = 9,
+ kHS10WalkArea3 = 10,
+ kHS10WalkArea4 = 11
+};
+
+enum {
+ kHS11Platypus = 0,
+ kHS11ExitKitchen = 1,
+ kHS11ExitToilet = 2,
+ kHS11ExitLeft = 3,
+ kHS11GoggleGuy = 4,
+ kHS11HookGuy = 5,
+ kHS11Billard = 6,
+ kHS11WalkArea1 = 7,
+ kHS11Device = 8,
+ kHS11WalkArea2 = 9,
+ kHS11WalkArea3 = 10,
+ kHS11WalkArea4 = 11,
+ kHS11WalkArea5 = 12
+};
+
+enum {
+ kHS12Platypus = 0,
+ kHS12ExitRight = 1,
+ kHS12ToothGuy = 2,
+ kHS12Barkeeper = 3,
+ kHS12BeardGuy = 4,
+ kHS12Jukebox = 5,
+ kHS12WalkArea1 = 6,
+ kHS12Device = 7,
+ kHS12WalkArea2 = 8,
+ kHS12WalkArea3 = 9,
+ kHS12WalkArea4 = 10
+};
+
+enum {
+ kHS13Platypus = 0,
+ kHS13ExitBar = 1,
+ kHS13WalkArea1 = 2,
+ kHS13BackToilet = 3,
+ kHS13FrontToilet= 4,
+ kHS13Urinal = 5,
+ kHS13Scribble = 6,
+ kHS13Sink = 7,
+ kHS13WalkArea2 = 8,
+ kHS13Device = 9,
+ kHS13WalkArea3 = 10,
+ kHS13WalkArea4 = 11,
+ kHS13WalkArea5 = 12,
+ kHS13WalkArea6 = 13,
+ kHS13WalkArea7 = 14,
+ kHS13WalkArea8 = 15,
+ kHS13WalkArea9 = 16
+};
+
+enum {
+ kHS14Platypus = 0,
+ kHS14Exit = 1,
+ kHS14Coin = 2,
+ kHS14Toilet = 3,
+ kHS14Device = 4
+};
+
+enum {
+ kHS15Platypus = 0,
+ kHS15Exit = 1,
+ kHS15Button1 = 2,
+ kHS15Button2 = 3,
+ kHS15Button3 = 4,
+ kHS15Button4 = 5,
+ kHS15Button5 = 6,
+ kHS15Button6 = 7,
+ kHS15ButtonA = 8,
+ kHS15ButtonB = 9,
+ kHS15ButtonC = 10,
+ kHS15ButtonD = 11,
+ kHS15ButtonE = 12,
+ kHS15ButtonF = 13,
+ kHS15CoinSlot = 14,
+ kHS15PlayButton = 15,
+ kHS15Device = 16
+};
+
+enum {
+ kHS17Platypus = 0,
+ kHS17Phone1 = 1,
+ kHS17Phone2 = 2,
+ kHS17ExitGrubCity = 3,
+ kHS17Device = 4,
+ kHS17ExitToyStore = 5,
+ kHS17Wrench = 6,
+ kHS17WalkArea1 = 7,
+ kHS17WalkArea2 = 8,
+ kHS17WalkArea3 = 9
+};
+
+enum {
+ kHS18Platypus = 0,
+ kHS18GarbageCan = 1,
+ kHS18Device = 2,
+ kHS18ExitToyStore = 3,
+ kHS18ExitPhoneBooth = 4,
+ kHS18ExitGrubCity = 5,
+ kHS18HydrantTopValve = 6,
+ kHS18HydrantRightValve = 7,
+ kHS18CowboyHat = 8,
+ kHS18WalkArea1 = 9,
+ kHS18WalkArea2 = 10
+};
+
+enum {
+ kHS19Platypus = 0,
+ kHS19ExitOutsideToyStore= 1,
+ kHS19Device = 2,
+ kHS19Picture = 3,
+ kHS19ShopAssistant = 4,
+ kHS19Toy1 = 5,
+ kHS19Toy2 = 6,
+ kHS19Toy3 = 7,
+ kHS19Phone = 8,
+ kHS19Toy4 = 9,
+ kHS19Toy5 = 10,
+ kHS19Toy6 = 11,
+ kHS19Toy7 = 12,
+ kHS19WalkArea1 = 13,
+ kHS19WalkArea2 = 14,
+ kHS19WalkArea3 = 15
+};
+
+enum {
+ kAS10LeaveScene = 0,
+ kAS10AnnoyCook = 1,
+ kAS10PlatWithBox = 4
+};
+
+enum {
+ kAS11LeaveScene = 0,
+ kAS11ShowMagazineToGoggleGuy = 3,
+ kAS11TalkGoggleGuy = 4,
+ kAS11GrabHookGuy = 6,
+ kAS11ShowItemToHookGuy = 8,
+ kAS11TalkHookGuy = 9,
+ kAS11GrabBillardBall = 11
+};
+
+enum {
+ kAS12LeaveScene = 0,
+ kAS12QuarterToToothGuyDone = 1,
+ kAS12TalkToothGuy = 2,
+ kAS12GrabToothGuy = 4,
+ kAS12ShowItemToToothGuy = 5,
+ kAS12QuarterWithHoleToToothGuy = 6,
+ kAS12QuarterToToothGuy = 7,
+ kAS12TalkBeardGuy = 8,
+ kAS12LookBeardGuy = 9,
+ kAS12GrabBeardGuy = 10,
+ kAS12ShowItemToBeardGuy = 11,
+ kAS12TalkBarkeeper = 12,
+ kAS12LookBarkeeper = 13,
+ kAS12ShowItemToBarkeeper = 15,
+ kAS12QuarterWithBarkeeper = 16,
+ kAS12PlatWithBarkeeper = 17,
+ kAS12PlatWithToothGuy = 18,
+ kAS12PlatWithBeardGuy = 19
+};
+
+enum {
+ kAS13LeaveScene = 0,
+ kAS13BackToilet = 1,
+ kAS13FrontToilet = 2,
+ kAS13LookScribble = 6,
+ kAS13GrabSink = 7,
+ kAS13GrabSinkDone = 8,
+ kAS13Wait = 12,
+ kAS13GrabUrinal = 13
+};
+
+enum {
+ kAS17TryGetWrench = 0,
+ kAS17GetWrench2 = 1,
+ kAS17GetWrenchDone = 2,
+ kAS17GetWrench1 = 3,
+ kAS17PlatUsePhone = 4,
+ kAS17PutCoinIntoPhone = 5,
+ kAS17GetCoinFromPhone = 6,
+ kAS17GetCoinFromPhoneDone = 7,
+ kAS17PutCoinIntoPhoneDone = 8,
+ kAS17GnapUsePhone = 9,
+ kAS17GetWrenchGnapReady = 10,
+ kAS17GnapHangUpPhone = 11,
+ kAS17PlatPhoningAssistant = 12,
+ kAS17PlatHangUpPhone = 14,
+ kAS17LeaveScene = 15
+};
+
+enum {
+ kAS18OpenRightValveNoGarbageCanDone = 0,
+ kAS18OpenRightValveNoGarbageCan = 1,
+ kAS18CloseRightValveNoGarbageCan = 2,
+ kAS18OpenTopValveDone = 3,
+ kAS18OpenTopValve = 4,
+ kAS18CloseTopValve = 5,
+ kAS18GrabGarbageCanFromStreet = 6,
+ kAS18GrabCowboyHat = 7,
+ kAS18GrabGarbageCanFromHydrant = 8,
+ kAS18PutGarbageCanOnRunningHydrant = 9,
+ kAS18PutGarbageCanOnRunningHydrant2 = 10,
+ kAS18GrabCowboyHatDone = 11,
+ kAS18StandingOnHydrant = 12,
+ kAS18OpenRightValveWithGarbageCan = 13,
+ kAS18OpenRightValveWithGarbageCanDone = 14,
+ kAS18CloseRightValveWithGarbageCan = 15,
+ kAS18PutGarbageCanOnHydrant = 16,
+ kAS18PutGarbageCanOnHydrantDone = 17,
+ kAS18PlatComesHere = 18,
+ kAS18CloseRightValveWithGarbageCanDone = 19,
+ kAS18LeaveScene = 20
+};
+
+enum {
+ kAS19UsePhone = 0,
+ kAS19GrabToy = 1,
+ kAS19GrabPicture = 2,
+ kAS19GrabPictureDone = 3,
+ kAS19TalkShopAssistant = 4,
+ kAS19LeaveScene = 5
+};
+
+/*****************************************************************************/
+
+class GnapEngine;
+class CutScene;
+
+class Scene10: public Scene {
+public:
+ Scene10(GnapEngine *vm);
+ virtual ~Scene10() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb();
+
+private:
+ int _nextCookSequenceId;
+ int _currCookSequenceId;
+};
+
+class Scene11: public Scene {
+public:
+ Scene11(GnapEngine *vm);
+ virtual ~Scene11() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _billardBallCtr;
+ int _nextHookGuySequenceId;
+ int _currHookGuySequenceId;
+ int _nextGoggleGuySequenceId;
+ int _currGoggleGuySequenceId;
+};
+
+class Scene12: public Scene {
+public:
+ Scene12(GnapEngine *vm);
+ virtual ~Scene12() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _nextBeardGuySequenceId;
+ int _currBeardGuySequenceId;
+ int _nextToothGuySequenceId;
+ int _currToothGuySequenceId;
+ int _nextBarkeeperSequenceId;
+ int _currBarkeeperSequenceId;
+};
+
+class Scene13: public Scene {
+public:
+ Scene13(GnapEngine *vm);
+ virtual ~Scene13() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _backToiletCtr;
+
+ void showScribble();
+};
+
+class Scene14: public Scene {
+public:
+ Scene14(GnapEngine *vm);
+ virtual ~Scene14() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+};
+
+class Scene15: public Scene {
+public:
+ Scene15(GnapEngine *vm);
+ virtual ~Scene15() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _nextRecordSequenceId;
+ int _currRecordSequenceId;
+ int _nextSlotSequenceId;
+ int _currSlotSequenceId;
+ int _nextUpperButtonSequenceId;
+ int _currUpperButtonSequenceId;
+ int _nextLowerButtonSequenceId;
+ int _currLowerButtonSequenceId;
+};
+
+class Scene17: public Scene {
+public:
+ Scene17(GnapEngine *vm);
+ virtual ~Scene17() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ bool _canTryGetWrench;
+ int _wrenchCtr;
+ int _platPhoneCtr;
+ int _platTryGetWrenchCtr;
+ int _nextPhoneSequenceId;
+ int _currPhoneSequenceId;
+ int _nextWrenchSequenceId;
+ int _currWrenchSequenceId;
+ int _nextCarWindowSequenceId;
+ int _currCarWindowSequenceId;
+
+ void update();
+ void platHangUpPhone();
+};
+
+class Scene18: public Scene {
+public:
+ Scene18(GnapEngine *vm);
+ virtual ~Scene18();
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ Graphics::Surface *_cowboyHatSurface;
+
+ int _platPhoneCtr;
+ int _platPhoneIter;
+ int _nextPhoneSequenceId;
+ int _currPhoneSequenceId;
+
+ void gnapCarryGarbageCanTo(int a5);
+ void putDownGarbageCan(int animationIndex);
+ void platEndPhoning(bool platFl);
+ void closeHydrantValve();
+ void waitForGnapAction();
+};
+
+class Scene19: public Scene {
+public:
+ Scene19(GnapEngine *vm);
+ virtual ~Scene19();
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currShopAssistantSequenceId;
+ int _nextShopAssistantSequenceId;
+ int _toyGrabCtr;
+ int _shopAssistantCtr;
+
+ Graphics::Surface *_pictureSurface;
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_GROUP1_H
diff --git a/engines/gnap/scenes/group2.cpp b/engines/gnap/scenes/group2.cpp
new file mode 100644
index 0000000000..522a3f4337
--- /dev/null
+++ b/engines/gnap/scenes/group2.cpp
@@ -0,0 +1,3423 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/group2.h"
+
+namespace Gnap {
+
+Scene20::Scene20(GnapEngine *vm) : Scene(vm) {
+ _stonerGuyCtr = 3;
+ _stonerGuyShowingJoint = false;
+ _groceryStoreGuyCtr = 0;
+ _currStonerGuySequenceId = -1;
+ _nextStonerGuySequenceId = -1;
+ _currGroceryStoreGuySequenceId = -1;
+ _nextGroceryStoreGuySequenceId = -1;
+}
+
+int Scene20::init() {
+ return 0x186;
+}
+
+void Scene20::updateHotspots() {
+ _vm->setHotspot(kHS20Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS20GroceryStoreHat, 114, 441, 174, 486, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 0, 7);
+ _vm->setHotspot(kHS20ExitParkingLot, 0, 300, 15, 600, SF_EXIT_L_CURSOR | SF_WALKABLE, 0, 7);
+ _vm->setHotspot(kHS20StonerGuy, 276, 290, 386, 450, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 8);
+ _vm->setHotspot(kHS20GroceryStoreGuy, 123, 282, 258, 462, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 7);
+ _vm->setHotspot(kHS20ExitInsideGrubCity, 519, 250, 581, 413, SF_EXIT_L_CURSOR, 8, 7);
+ _vm->setHotspot(kHS20ExitOutsideCircusWorld, 660, 222, 798, 442, SF_EXIT_NE_CURSOR, 9, 6);
+ _vm->setHotspot(kHS20ExitOutsideToyStore, 785, 350, 800, 600, SF_EXIT_R_CURSOR, 11, 8);
+ _vm->setHotspot(kHS20ExitPhone, 250, 585, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 10);
+ _vm->setHotspot(kHS20WalkArea1, 0, 0, 800, 468);
+ _vm->setHotspot(kHS20WalkArea2, 605, 0, 800, 600);
+ _vm->setDeviceHotspot(kHS20Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 12;
+}
+
+void Scene20::updateAnimationsCb() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ switch (_nextStonerGuySequenceId) {
+ case 0x16B:
+ if (!_vm->_timers[4]) {
+ _stonerGuyShowingJoint = false;
+ gameSys.insertSequence(0x16B, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ _currStonerGuySequenceId = 0x16B;
+ _nextStonerGuySequenceId = -1;
+ }
+ break;
+ case 0x16A:
+ // Grab joint
+ gnap.playPullOutDevice(Common::Point(4, 4));
+ gnap.playUseDevice();
+ gameSys.setAnimation(0x16A, 21, 0);
+ gameSys.insertSequence(0x16A, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ _currStonerGuySequenceId = 0x16A;
+ _nextStonerGuySequenceId = -1;
+ _vm->invAdd(kItemJoint);
+ _vm->setFlag(kGFJointTaken);
+ _stonerGuyShowingJoint = false;
+ gnap._actionStatus = kAS20GrabJointDone;
+ break;
+ case 0x16E:
+ gameSys.setAnimation(0x16E, 21, 2);
+ gameSys.insertSequence(0x16E, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ _currStonerGuySequenceId = 0x16E;
+ _nextStonerGuySequenceId = -1;
+ _nextGroceryStoreGuySequenceId = 0x175;
+ break;
+ case 0x16D:
+ gameSys.setAnimation(_nextStonerGuySequenceId, 21, 2);
+ gameSys.setAnimation(_nextStonerGuySequenceId, 21, 0);
+ gameSys.insertSequence(_nextStonerGuySequenceId, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ _currStonerGuySequenceId = _nextStonerGuySequenceId;
+ _nextStonerGuySequenceId = -1;
+ gnap._actionStatus = kAS20ActionDone;
+ break;
+ case 0x16F:
+ gameSys.setAnimation(_nextStonerGuySequenceId, 21, 2);
+ gameSys.setAnimation(0x17A, 20, 3);
+ gameSys.insertSequence(_nextStonerGuySequenceId, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x17A, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currGroceryStoreGuySequenceId = 0x17A;
+ _nextGroceryStoreGuySequenceId = -1;
+ _currStonerGuySequenceId = _nextStonerGuySequenceId;
+ _nextStonerGuySequenceId = -1;
+ break;
+ case 0x171:
+ _stonerGuyCtr = (_stonerGuyCtr + 1) % 3;
+ switch (_stonerGuyCtr) {
+ case 1:
+ _nextStonerGuySequenceId = 0x171;
+ break;
+ case 2:
+ _nextStonerGuySequenceId = 0x172;
+ break;
+ case 3:
+ _nextStonerGuySequenceId = 0x173;
+ break;
+ default:
+ _nextStonerGuySequenceId = 0x171;
+ break;
+ }
+ gameSys.insertSequence(_nextStonerGuySequenceId, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x17C, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x17C, 20, 3);
+ gameSys.setAnimation(_nextStonerGuySequenceId, 21, 2);
+ _currGroceryStoreGuySequenceId = 0x17C;
+ _nextGroceryStoreGuySequenceId = -1;
+ _currStonerGuySequenceId = _nextStonerGuySequenceId;
+ _nextStonerGuySequenceId = -1;
+ break;
+ default:
+ _nextStonerGuySequenceId = 0x16C;
+ gameSys.setAnimation(0x16C, 21, 2);
+ gameSys.insertSequence(_nextStonerGuySequenceId, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ _currStonerGuySequenceId = _nextStonerGuySequenceId;
+ _nextStonerGuySequenceId = -1;
+ break;
+ }
+ }
+}
+
+void Scene20::stopSounds() {
+ _vm->stopSound(0x18E);
+ _vm->stopSound(0x18F);
+ _vm->stopSound(0x190);
+ _vm->stopSound(0x191);
+ _vm->stopSound(0x194);
+ _vm->stopSound(0x195);
+ _vm->stopSound(0x192);
+ _vm->stopSound(0x193);
+ _vm->stopSound(0x196);
+ _vm->stopSound(0x197);
+ _vm->stopSound(0x198);
+ _vm->stopSound(0x199);
+ _vm->stopSound(0x19A);
+}
+
+void Scene20::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x10940, true);
+ _vm->startSoundTimerA(8);
+
+ _stonerGuyShowingJoint = false;
+ _vm->_timers[7] = _vm->getRandom(100) + 100;
+
+ _stonerGuyCtr = (_stonerGuyCtr + 1) % 3;
+ switch (_stonerGuyCtr) {
+ case 1:
+ _currStonerGuySequenceId = 0x171;
+ break;
+ case 2:
+ _currStonerGuySequenceId = 0x172;
+ break;
+ case 3:
+ _currStonerGuySequenceId = 0x173;
+ break;
+ }
+
+ _nextStonerGuySequenceId = -1;
+ gameSys.setAnimation(_currStonerGuySequenceId, 21, 2);
+ gameSys.insertSequence(_currStonerGuySequenceId, 21, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->_timers[6] = _vm->getRandom(20) + 30;
+
+ _currGroceryStoreGuySequenceId = 0x17C;
+ _nextGroceryStoreGuySequenceId = -1;
+ gameSys.setAnimation(0x17C, 20, 3);
+ gameSys.insertSequence(0x17C, 20, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->_timers[5] = _vm->getRandom(50) + 130;
+ if (_vm->isFlag(kGFGroceryStoreHatTaken))
+ gameSys.insertSequence(0x17F, 20, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x174, 20, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->isFlag(kGFSceneFlag1)) {
+ _vm->clearFlag(kGFSceneFlag1);
+ _vm->endSceneInit();
+ gameSys.setAnimation(0x182, 140, 0);
+ gameSys.insertSequence(0x182, 140, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ gnap.initPos(11, 8, kDirBottomLeft);
+ plat.initPos(11, 9, kDirIdleRight);
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(6, 9), -1, 0x107C2, 1);
+ } else {
+ switch (_vm->_prevSceneNum) {
+ case 17:
+ gnap.initPos(5, 11, kDirBottomRight);
+ plat.initPos(6, 11, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(6, 9), -1, 0x107C2, 1);
+ break;
+ case 18:
+ gnap.initPos(11, 8, kDirBottomLeft);
+ plat.initPos(11, 9, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(6, 9), -1, 0x107C2, 1);
+ break;
+ case 21:
+ gnap.initPos(-1, 8, kDirBottomLeft);
+ plat.initPos(-1, 9, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(3, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(3, 9), -1, 0x107C2, 1);
+ break;
+ case 22:
+ gnap.initPos(7, 6, kDirBottomRight);
+ plat.initPos(8, 6, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(9, 9), -1, 0x107C2, 1);
+ break;
+ default:
+ gnap.initPos(8, 6, kDirBottomLeft);
+ plat.initPos(9, 6, kDirIdleRight);
+ _vm->endSceneInit();
+ _vm->_hotspots[kHS20WalkArea2]._flags |= SF_WALKABLE;
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 9), -1, 0x107C2, 1);
+ _vm->_hotspots[kHS20WalkArea2]._flags &= ~SF_WALKABLE;
+ break;
+ }
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+ _vm->testWalk(0, 1, 7, 9, 8, 9);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS20Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS20Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(20);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS20ExitParkingLot:
+ if (gnap._actionStatus < 0) {
+ if (_stonerGuyShowingJoint)
+ _vm->_timers[4] = 0;
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 21;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20ExitParkingLot], 0, 0x107AF, 1);
+ gnap._actionStatus = kAS20LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS20ExitParkingLot] + Common::Point(0, 1), -1, 0x107CF, 1);
+ plat._idleFacing = kDirIdleRight;
+ }
+ break;
+
+ case kHS20ExitPhone:
+ if (gnap._actionStatus < 0) {
+ if (_stonerGuyShowingJoint)
+ _vm->_timers[4] = 0;
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 17;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20ExitPhone], 0, 0x107AE, 1);
+ gnap._actionStatus = kAS20LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS20ExitPhone] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS20ExitOutsideToyStore:
+ if (gnap._actionStatus < 0) {
+ if (_stonerGuyShowingJoint)
+ _vm->_timers[4] = 0;
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 18;
+ _vm->_hotspots[kHS20WalkArea2]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20ExitOutsideToyStore], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS20LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS20ExitOutsideToyStore] + Common::Point(0, 1), -1, 0x107CD, 1);
+ _vm->_hotspots[kHS20WalkArea2]._flags &= ~SF_WALKABLE;
+ }
+ break;
+
+ case kHS20ExitInsideGrubCity:
+ if (gnap._actionStatus < 0) {
+ if (_stonerGuyShowingJoint)
+ _vm->_timers[4] = 0;
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 22;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20ExitInsideGrubCity] + Common::Point(0, - 1), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS20LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS20ExitInsideGrubCity] + Common::Point(1, 0), -1, 0x107C2, 1);
+ plat._idleFacing = kDirIdleRight;
+ }
+ break;
+
+ case kHS20ExitOutsideCircusWorld:
+ if (gnap._actionStatus < 0) {
+ if (_stonerGuyShowingJoint)
+ _vm->_timers[4] = 0;
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 24;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20ExitOutsideCircusWorld], 0, 0x107BB, 1);
+ gnap._actionStatus = kAS20LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS20ExitOutsideCircusWorld] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS20StonerGuy:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS20StonerGuy], 5, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2(Common::Point(5, 4));
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20StonerGuy], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ if (_stonerGuyShowingJoint)
+ gnap._actionStatus = kAS20GrabJoint;
+ else
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20StonerGuy], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ if (_vm->isFlag(kGFJointTaken))
+ gnap._actionStatus = kAS20TalkStonerGuyNoJoint;
+ else
+ gnap._actionStatus = kAS20TalkStonerGuyHasJoint;
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS20GroceryStoreGuy:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS20GroceryStoreGuy], 2, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(2, 3));
+ break;
+ case GRAB_CURSOR:
+ _stonerGuyShowingJoint = false;
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20GroceryStoreGuy], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS20GrabGroceryStoreGuy;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20GroceryStoreGuy], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS20TalkGroceryStoreGuy;
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS20GroceryStoreHat:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemCowboyHat) {
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20GroceryStoreHat], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS20SwitchGroceryStoreHat;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS20GroceryStoreHat], 1, 6);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(1, 6));
+ break;
+ case GRAB_CURSOR:
+ _stonerGuyShowingJoint = false;
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20GroceryStoreGuy], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS20GrabGroceryStoreHat;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS20WalkArea1:
+ case kHS20WalkArea2:
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x10940))
+ _vm->playSound(0x10940, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0) {
+ _vm->_hotspots[kHS20WalkArea1]._rect.bottom += 48;
+ plat.updateIdleSequence();
+ _vm->_hotspots[kHS20WalkArea1]._rect.bottom -= 48;
+ }
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (gnap._actionStatus < 0 && !_vm->_timers[5] && _nextGroceryStoreGuySequenceId == -1) {
+ _vm->_timers[5] = _vm->getRandom(50) + 130;
+ if (_vm->getRandom(4) != 0)
+ _nextGroceryStoreGuySequenceId = 0x17C;
+ else
+ _nextGroceryStoreGuySequenceId = 0x17A;
+ }
+ if (!_vm->_timers[7]) {
+ _vm->_timers[7] = _vm->getRandom(100) + 100;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0) {
+ switch (_vm->getRandom(3)) {
+ case 0:
+ gameSys.insertSequence(0x183, 253, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 1:
+ gameSys.insertSequence(0x184, 253, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 2:
+ gameSys.insertSequence(0x185, 253, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ }
+ }
+ }
+ _vm->playSoundA();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene20::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS20LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS20TalkStonerGuyNoJoint:
+ gameSys.setAnimation(0x170, 21, 2);
+ gameSys.setAnimation(0x17B, 20, 3);
+ gameSys.insertSequence(0x17B, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncExists, 0, 0, 0);
+ gameSys.insertSequence(0x170, 21, _currStonerGuySequenceId, 21, kSeqSyncExists, 0, 0, 0);
+ _vm->stopSound(0x1A1);
+ stopSounds();
+ _currGroceryStoreGuySequenceId = 0x17B;
+ _currStonerGuySequenceId = 0x170;
+ _nextGroceryStoreGuySequenceId = -1;
+ _nextStonerGuySequenceId = 0x16E;
+ _vm->_timers[5] = 100;
+ _vm->_timers[6] = 100;
+ break;
+ case kAS20TalkStonerGuyHasJoint:
+ gameSys.setAnimation(0x168, 21, 2);
+ gameSys.setAnimation(379, 20, 3);
+ gameSys.insertSequence(0x17B, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncExists, 0, 0, 0);
+ gameSys.insertSequence(0x170, 21, _currStonerGuySequenceId, 21, kSeqSyncExists, 0, 0, 0);
+ gameSys.insertSequence(0x168, 21, 0x170, 21, kSeqSyncWait, 0, 0, 0);
+ _vm->stopSound(0x1A1);
+ stopSounds();
+ _currGroceryStoreGuySequenceId = 0x17B;
+ _currStonerGuySequenceId = 0x168;
+ _nextGroceryStoreGuySequenceId = -1;
+ _nextStonerGuySequenceId = 0x16B;
+ _vm->_timers[5] = 200;
+ _vm->_timers[6] = 200;
+ _vm->_timers[4] = 100;
+ _stonerGuyShowingJoint = true;
+ gnap._actionStatus = -1;
+ break;
+ case kAS20GrabJoint:
+ _nextStonerGuySequenceId = 0x16A;
+ break;
+ case kAS20ActionDone:
+ gnap._actionStatus = -1;
+ break;
+ case kAS20TalkGroceryStoreGuy:
+ gameSys.setAnimation(0x170, 21, 2);
+ gameSys.setAnimation(0x17B, 20, 3);
+ gameSys.insertSequence(0x17B, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncExists, 0, 0, 0);
+ gameSys.insertSequence(0x170, 21, _currStonerGuySequenceId, 21, kSeqSyncExists, 0, 0, 0);
+ _vm->stopSound(0x1A1);
+ stopSounds();
+ _currGroceryStoreGuySequenceId = 0x17B;
+ _currStonerGuySequenceId = 0x170;
+ _groceryStoreGuyCtr = (_groceryStoreGuyCtr + 1) % 2;
+ if (_groceryStoreGuyCtr != 0)
+ _nextGroceryStoreGuySequenceId = 0x176;
+ else
+ _nextGroceryStoreGuySequenceId = 0x177;
+ _vm->_timers[5] = 100;
+ _vm->_timers[6] = 100;
+ break;
+ case kAS20GrabGroceryStoreGuy:
+ gameSys.setAnimation(0x170, 21, 2);
+ gameSys.setAnimation(0x17B, 20, 3);
+ gameSys.insertSequence(0x170, 21, _currStonerGuySequenceId, 21, kSeqSyncExists, 0, 0, 0);
+ gameSys.insertSequence(0x17B, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncExists, 0, 0, 0);
+ _vm->stopSound(0x1A1);
+ stopSounds();
+ _currGroceryStoreGuySequenceId = 0x17B;
+ _currStonerGuySequenceId = 0x170;
+ _vm->_timers[5] = 120;
+ _vm->_timers[6] = 120;
+ _nextGroceryStoreGuySequenceId = 0x178;
+ break;
+ case kAS20GrabGroceryStoreHat:
+ gameSys.setAnimation(0x170, 21, 2);
+ gameSys.setAnimation(0x17B, 20, 3);
+ gameSys.insertSequence(0x17B, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncExists, 0, 0, 0);
+ gameSys.insertSequence(0x170, 21, _currStonerGuySequenceId, 21, kSeqSyncExists, 0, 0, 0);
+ _vm->stopSound(0x1A1);
+ stopSounds();
+ _currGroceryStoreGuySequenceId = 0x17B;
+ _currStonerGuySequenceId = 0x170;
+ _nextGroceryStoreGuySequenceId = 0x179;
+ break;
+ case kAS20SwitchGroceryStoreHat:
+ _vm->setGrabCursorSprite(-1);
+ gameSys.setAnimation(0x180, gnap._id, 0);
+ gameSys.insertSequence(0x180, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x180;
+ gnap._sequenceDatNum = 0;
+ _vm->invRemove(kItemCowboyHat);
+ _vm->invAdd(kItemGroceryStoreHat);
+ gnap._actionStatus = kAS20SwitchGroceryStoreHatDone;
+ break;
+ case kAS20SwitchGroceryStoreHatDone:
+ gameSys.insertSequence(0x17F, 20, 372, 20, kSeqSyncWait, 0, 0, 0);
+ _vm->setFlag(kGFGroceryStoreHatTaken);
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+ _vm->addFullScreenSprite(0x12C, 255);
+ gameSys.setAnimation(0x181, 256, 0);
+ gameSys.insertSequence(0x181, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->removeFullScreenSprite();
+ _vm->showCursor();
+ _vm->setGrabCursorSprite(kItemGroceryStoreHat);
+ gnap._idleFacing = kDirBottomRight;
+ gnap.walkTo(Common::Point(3, 8), -1, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = -1;
+ break;
+ case kAS20GrabJointDone:
+ _vm->setGrabCursorSprite(kItemJoint);
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ switch (_nextGroceryStoreGuySequenceId) {
+ case 0x176:
+ case 0x177:
+ gameSys.setAnimation(_nextGroceryStoreGuySequenceId, 20, 3);
+ gameSys.insertSequence(_nextGroceryStoreGuySequenceId, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currGroceryStoreGuySequenceId = _nextGroceryStoreGuySequenceId;
+ _nextGroceryStoreGuySequenceId = -1;
+ _nextStonerGuySequenceId = 0x16D;
+ break;
+ case 0x178:
+ gameSys.setAnimation(_nextGroceryStoreGuySequenceId, 20, 3);
+ gameSys.setAnimation(0x17D, gnap._id, 0);
+ gameSys.insertSequence(_nextGroceryStoreGuySequenceId, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x17D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x17D;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS20ActionDone;
+ gameSys.setAnimation(0x16D, 21, 2);
+ gameSys.insertSequence(0x16D, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ _currStonerGuySequenceId = 0x16D;
+ _currGroceryStoreGuySequenceId = 0x178;
+ _nextGroceryStoreGuySequenceId = -1;
+ _nextStonerGuySequenceId = -1;
+ break;
+ case 0x179:
+ gameSys.setAnimation(_nextGroceryStoreGuySequenceId, 20, 3);
+ gameSys.setAnimation(0x16D, 21, 0);
+ gameSys.insertSequence(_nextGroceryStoreGuySequenceId, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x17E, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x17E;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS20ActionDone;
+ gameSys.setAnimation(0x16D, 21, 2);
+ gameSys.insertSequence(0x16D, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ _currStonerGuySequenceId = 0x16D;
+ _currGroceryStoreGuySequenceId = 377;
+ _nextGroceryStoreGuySequenceId = -1;
+ _nextStonerGuySequenceId = -1;
+ gnap.walkTo(Common::Point(4, 8), -1, 0x107BB, 1);
+ break;
+ case 0x17C:
+ gameSys.setAnimation(0, 0, 3);
+ _nextStonerGuySequenceId = 0x171;
+ break;
+ case 0x17A:
+ gameSys.setAnimation(0, 0, 3);
+ _nextStonerGuySequenceId = 0x16F;
+ break;
+ case 0x175:
+ gameSys.setAnimation(0x175, 20, 0);
+ gameSys.setAnimation(0x175, 20, 3);
+ gameSys.insertSequence(0x175, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currGroceryStoreGuySequenceId = 0x175;
+ _nextGroceryStoreGuySequenceId = -1;
+ gnap._actionStatus = kAS20ActionDone;
+ break;
+ default:
+ if (_nextGroceryStoreGuySequenceId != -1) {
+ gameSys.setAnimation(_nextGroceryStoreGuySequenceId, 20, 3);
+ gameSys.insertSequence(_nextGroceryStoreGuySequenceId, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currGroceryStoreGuySequenceId = _nextGroceryStoreGuySequenceId;
+ _nextGroceryStoreGuySequenceId = -1;
+ }
+ break;
+ }
+ }
+
+ updateAnimationsCb();
+}
+
+/*****************************************************************************/
+
+Scene21::Scene21(GnapEngine *vm) : Scene(vm) {
+ _currOldLadySequenceId = -1;
+ _nextOldLadySequenceId = -1;
+}
+
+int Scene21::init() {
+ _vm->_gameSys->setAnimation(0, 0, 3);
+
+ return _vm->isFlag(kGFTwigTaken) ? 0x94 : 0x93;
+}
+
+void Scene21::updateHotspots() {
+ _vm->setHotspot(kHS21Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS21Banana, 94, 394, 146, 430, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 2, 6);
+ _vm->setHotspot(kHS21OldLady, 402, 220, 528, 430, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 7);
+ _vm->setHotspot(kHS21ExitOutsideGrubCity, 522, 498, 800, 600, SF_EXIT_SE_CURSOR | SF_WALKABLE, 5, 10);
+ _vm->setHotspot(kHS21WalkArea1, 0, 0, 800, 440);
+ _vm->setHotspot(kHS21WalkArea2, 698, 0, 800, 600);
+ _vm->setDeviceHotspot(kHS21Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFUnk04) || !_vm->isFlag(kGFTwigTaken))
+ _vm->_hotspots[kHS21Banana]._flags = SF_WALKABLE | SF_DISABLED;
+ if (_vm->isFlag(kGFTwigTaken))
+ _vm->_hotspots[kHS21OldLady]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 7;
+}
+
+void Scene21::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x10940, true);
+ _vm->startSoundTimerA(6);
+ _vm->_timers[5] = _vm->getRandom(100) + 100;
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->isFlag(kGFTwigTaken)) {
+ if (_vm->isFlag(kGFKeysTaken)) {
+ gnap.initPos(5, 8, kDirBottomRight);
+ plat.initPos(6, 8, kDirIdleLeft);
+ gameSys.insertSequence(0x8E, 2, 0, 0, kSeqNone, 0, 0, 0);
+ if (!_vm->isFlag(kGFUnk04))
+ gameSys.insertSequence(0x8D, 59, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+ _vm->clearFlag(kGFKeysTaken);
+ } else {
+ gnap.initPos(5, 11, kDirBottomRight);
+ plat.initPos(6, 11, kDirIdleLeft);
+ if (!_vm->isFlag(kGFUnk04))
+ gameSys.insertSequence(0x8D, 59, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+ }
+ } else {
+ gnap.initPos(5, 11, kDirBottomRight);
+ plat.initPos(6, 11, kDirIdleLeft);
+ _currOldLadySequenceId = 0x89;
+ gameSys.setAnimation(0x89, 79, 3);
+ gameSys.insertSequence(_currOldLadySequenceId, 79, 0, 0, kSeqNone, 0, 0, 0);
+ _nextOldLadySequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(30) + 50;
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS21Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS21Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS21Banana:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 2, 5);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(2, 5));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[kHS21Banana]) | 0x10000, 1);
+ gnap.playPullOutDevice(Common::Point(2, 5));
+ gnap.playUseDevice();
+ gnap._actionStatus = kAS21GrabBanana;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS21OldLady:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemGroceryStoreHat) {
+ _vm->_newSceneNum = 47;
+ gnap.walkTo(Common::Point(4, 6), 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS21UseHatWithOldLady;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(4, 6), 7, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(7, 4));
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ _vm->_hotspots[kHS21WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(Common::Point(7, 6), 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS21GrabOldLady;
+ _vm->_hotspots[kHS21WalkArea1]._flags &= ~SF_WALKABLE;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS21OldLady], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS21TalkOldLady;
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS21ExitOutsideGrubCity:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 20;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS21ExitOutsideGrubCity], 0, 0x107B3, 1);
+ gnap._actionStatus = kAS21LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS21ExitOutsideGrubCity] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS21WalkArea1:
+ case kHS21WalkArea2:
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x10940))
+ _vm->playSound(0x10940, true);
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->isFlag(kGFTwigTaken) && !_vm->_timers[4] && _nextOldLadySequenceId == -1 && gnap._actionStatus == -1) {
+ _vm->_timers[4] = _vm->getRandom(30) + 50;
+ switch (_vm->getRandom(5)) {
+ case 0:
+ _nextOldLadySequenceId = 0x88;
+ break;
+ case 1:
+ _nextOldLadySequenceId = 0x8A;
+ break;
+ default:
+ _nextOldLadySequenceId = 0x89;
+ break;
+ }
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(100) + 100;
+ gameSys.insertSequence(0x92, 255, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ _vm->playSoundA();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene21::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS21TalkOldLady:
+ _nextOldLadySequenceId = 0x8B;
+ gnap._actionStatus = -1;
+ break;
+ case kAS21GrabBanana:
+ gameSys.setAnimation(0x8C, 59, 0);
+ gameSys.insertSequence(0x8C, 59, 141, 59, kSeqSyncWait, 0, 0, 0);
+ _vm->setFlag(kGFUnk04);
+ _vm->invAdd(kItemBanana);
+ updateHotspots();
+ gnap._actionStatus = kAS21GrabBananaDone;
+ break;
+ case kAS21GrabBananaDone:
+ _vm->setGrabCursorSprite(kItemBanana);
+ gnap._actionStatus = -1;
+ break;
+ case kAS21GrabOldLady:
+ _vm->_timers[4] = _vm->getRandom(30) + 50;
+ _nextOldLadySequenceId = 0x87;
+ break;
+ case kAS21UseHatWithOldLady:
+ gameSys.setAnimation(0x8F, gnap._id, 0);
+ gameSys.insertSequence(0x8F, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x8F;
+ gnap._actionStatus = kAS21UseHatWithOldLadyDone;
+ _vm->invAdd(kItemTickets);
+ _vm->invRemove(kItemGroceryStoreHat);
+ _vm->setGrabCursorSprite(-1);
+ break;
+ case kAS21UseHatWithOldLadyDone:
+ _nextOldLadySequenceId = 0x91;
+ break;
+ case kAS21LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2 && _nextOldLadySequenceId != -1) {
+ if (_nextOldLadySequenceId == 0x87) {
+ gameSys.setAnimation(_nextOldLadySequenceId, 79, 3);
+ gameSys.insertSequence(_nextOldLadySequenceId, 79, _currOldLadySequenceId, 79, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x86, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x86;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = -1;
+ _currOldLadySequenceId = _nextOldLadySequenceId;
+ _nextOldLadySequenceId = -1;
+ } else if (_nextOldLadySequenceId == 0x91) {
+ gameSys.setAnimation(0x91, 79, 0);
+ gameSys.insertSequence(_nextOldLadySequenceId, 79, _currOldLadySequenceId, 79, kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = kAS21LeaveScene;
+ _currOldLadySequenceId = _nextOldLadySequenceId;
+ _nextOldLadySequenceId = -1;
+ } else {
+ gameSys.setAnimation(_nextOldLadySequenceId, 79, 3);
+ gameSys.insertSequence(_nextOldLadySequenceId, 79, _currOldLadySequenceId, 79, kSeqSyncWait, 0, 0, 0);
+ _currOldLadySequenceId = _nextOldLadySequenceId;
+ _nextOldLadySequenceId = -1;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene22::Scene22(GnapEngine *vm) : Scene(vm) {
+ _caughtBefore = false;
+ _cashierCtr = 3;
+ _nextCashierSequenceId = -1;
+}
+
+int Scene22::init() {
+ return 0x5E;
+}
+
+void Scene22::updateHotspots() {
+ _vm->setHotspot(kHS22Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS22ExitOutsideGrubCity, 0, 180, 184, 472, SF_EXIT_L_CURSOR, 3, 6);
+ _vm->setHotspot(kHS22ExitBackGrubCity, 785, 405, 800, 585, SF_EXIT_R_CURSOR, 11, 9);
+ _vm->setHotspot(kHS22Cashier, 578, 230, 660, 376, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 8);
+ _vm->setHotspot(kHS22WalkArea1, 553, 0, 800, 542);
+ _vm->setHotspot(kHS22WalkArea2, 0, 0, 552, 488);
+ _vm->setDeviceHotspot(kHS22Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 7;
+}
+
+void Scene22::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ gameSys.insertSequence(0x5D, 254, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currCashierSequenceId = 0x59;
+ _nextCashierSequenceId = -1;
+
+ gameSys.setAnimation(0x59, 1, 3);
+ gameSys.insertSequence(_currCashierSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->_timers[6] = _vm->getRandom(30) + 20;
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->_prevSceneNum == 20) {
+ gnap.initPos(2, 8, kDirBottomRight);
+ plat.initPos(1, 8, kDirIdleLeft);
+ _vm->endSceneInit();
+ } else {
+ gnap.initPos(11, _vm->_hotspotsWalkPos[kHS22ExitBackGrubCity].y, kDirBottomRight);
+ plat.initPos(11, _vm->_hotspotsWalkPos[kHS22ExitBackGrubCity].y + 1, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(9, 8), -1, 0x107C2, 1);
+ }
+
+ if (_vm->isFlag(kGFSceneFlag1)) {
+ int storeDetectiveSeqId;
+ _vm->setGrabCursorSprite(-1);
+ _vm->invRemove(kItemCereals);
+ if (_caughtBefore) {
+ switch (_vm->getRandom(3)) {
+ case 0:
+ storeDetectiveSeqId = 0x55;
+ break;
+ case 1:
+ storeDetectiveSeqId = 0x56;
+ break;
+ default:
+ storeDetectiveSeqId = 0x57;
+ break;
+ }
+ } else {
+ _caughtBefore = true;
+ storeDetectiveSeqId = 0x54;
+ }
+ gameSys.waitForUpdate();
+ gameSys.requestClear1();
+ gameSys.drawSpriteToBackground(0, 0, 0x44);
+ gameSys.setAnimation(storeDetectiveSeqId, 256, 4);
+ gameSys.insertSequence(storeDetectiveSeqId, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(4) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 20;
+ _caughtBefore = true;
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS22Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS22Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS22ExitOutsideGrubCity:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 20;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS22ExitOutsideGrubCity], 0, 0x107AF, 1);
+ gnap._actionStatus = kAS22LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS22ExitOutsideGrubCity] + Common::Point(0, 1), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS22ExitBackGrubCity:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 23;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS22ExitBackGrubCity], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS22LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS22ExitBackGrubCity] + Common::Point(0, 1), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS22Cashier:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS22Cashier], 8, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(8, 4));
+ break;
+ case GRAB_CURSOR:
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS22Cashier], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS22TalkCashier;
+ break;
+ case PLAT_CURSOR:
+ gnap.useDeviceOnPlatypus();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS22WalkArea1:
+ case kHS22WalkArea2:
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[6] && _nextCashierSequenceId == -1) {
+ _vm->_timers[6] = _vm->getRandom(30) + 20;
+ if (_vm->getRandom(8) != 0) {
+ _nextCashierSequenceId = 0x59;
+ } else {
+ _cashierCtr = (_cashierCtr + 1) % 3;
+ switch (_cashierCtr) {
+ case 1:
+ _nextCashierSequenceId = 0x58;
+ break;
+ case 2:
+ _nextCashierSequenceId = 0x5A;
+ break;
+ case 3:
+ _nextCashierSequenceId = 0x5B;
+ break;
+ default:
+ _nextCashierSequenceId = 0x58;
+ break;
+ }
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = 400;
+ _vm->_timers[1] = _vm->getRandom(20) + 30;
+ _vm->_timers[0] = _vm->getRandom(75) + 75;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene22::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS22LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS22TalkCashier:
+ _nextCashierSequenceId = 0x5C;
+ break;
+ }
+ gnap._actionStatus = -1;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2 && _nextCashierSequenceId != -1) {
+ gameSys.setAnimation(_nextCashierSequenceId, 1, 3);
+ gameSys.insertSequence(_nextCashierSequenceId, 1, _currCashierSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ _currCashierSequenceId = _nextCashierSequenceId;
+ _nextCashierSequenceId = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene23::Scene23(GnapEngine *vm) : Scene(vm) {
+ _currStoreClerkSequenceId = -1;
+ _nextStoreClerkSequenceId = -1;
+}
+
+int Scene23::init() {
+ return 0xC0;
+}
+
+void Scene23::updateHotspots() {
+ _vm->setHotspot(kHS23Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS23ExitFrontGrubCity, 0, 250, 15, 550, SF_EXIT_L_CURSOR | SF_WALKABLE, 0, 7);
+ _vm->setHotspot(kHS23Cereals, 366, 332, 414, 408, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 7);
+ _vm->setHotspot(kHS23WalkArea1, 0, 0, 340, 460);
+ _vm->setHotspot(kHS23WalkArea2, 340, 0, 800, 501);
+ _vm->setDeviceHotspot(kHS23Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 6;
+}
+
+void Scene23::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->_timers[4] = _vm->getRandom(100) + 200;
+ _vm->_timers[5] = _vm->getRandom(100) + 200;
+
+ _currStoreClerkSequenceId = 0xB4;
+ _nextStoreClerkSequenceId = -1;
+
+ gameSys.setAnimation(0xB4, 1, 4);
+ gameSys.insertSequence(_currStoreClerkSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ gnap.initPos(-1, 7, kDirBottomRight);
+ plat.initPos(-2, 7, kDirIdleLeft);
+ gameSys.insertSequence(0xBD, 255, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0xBF, 2, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+
+ plat.walkTo(Common::Point(1, 7), -1, 0x107C2, 1);
+
+ if (_vm->isFlag(kGFUnk24)) {
+ gnap.walkTo(Common::Point(2, 7), -1, 0x107B9, 1);
+ } else {
+ gnap.walkTo(Common::Point(2, 7), 0, 0x107B9, 1);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ _vm->playSequences(0x48, 0xBA, 0xBB, 0xBC);
+ _vm->setFlag(kGFUnk24);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 3, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS23Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS23Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS23Cereals:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS23Cereals], 5, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFSceneFlag1))
+ gnap.playMoan2();
+ else {
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS23Cereals], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS23LookCereals;
+ }
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFSceneFlag1))
+ gnap.playImpossible();
+ else {
+ gnap._idleFacing = kDirBottomRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS23Cereals], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ _vm->setFlag(kGFSceneFlag1);
+ gnap._actionStatus = kAS23GrabCereals;
+ _vm->invAdd(kItemCereals);
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS23ExitFrontGrubCity:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 22;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS23ExitFrontGrubCity], 0, 0x107AF, 1);
+ gnap._actionStatus = kAS23LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS23ExitFrontGrubCity] + Common::Point(0, -1), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS23WalkArea1:
+ case kHS23WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4] && gnap._actionStatus == -1) {
+ _vm->_timers[4] = _vm->getRandom(100) + 200;
+ switch (_vm->getRandom(4)) {
+ case 0:
+ gameSys.insertSequence(0xB7, 256, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 1:
+ gameSys.insertSequence(0xB8, 256, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 2:
+ case 3:
+ gameSys.insertSequence(0xB9, 256, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ }
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(100) + 200;
+ switch (_vm->getRandom(3)) {
+ case 0:
+ _vm->playSound(0xCE, false);
+ break;
+ case 1:
+ _vm->playSound(0xD0, false);
+ break;
+ case 2:
+ _vm->playSound(0xCF, false);
+ break;
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene23::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS23LookCereals:
+ _vm->showFullScreenSprite(0x48);
+ gnap._actionStatus = -1;
+ break;
+ case kAS23GrabCereals:
+ gameSys.setAnimation(0xBE, gnap._id, 0);
+ gameSys.insertSequence(0xBE, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.requestRemoveSequence(0xBF, 2);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0xBE;
+ gnap._actionStatus = kAS23GrabCerealsDone;
+ break;
+ case kAS23GrabCerealsDone:
+ _vm->setGrabCursorSprite(kItemCereals);
+ gnap._actionStatus = -1;
+ break;
+ case kAS23LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2 && _nextStoreClerkSequenceId == -1) {
+ switch (_vm->getRandom(8)) {
+ case 0:
+ case 1:
+ case 2:
+ _nextStoreClerkSequenceId = 0xB4;
+ break;
+ case 3:
+ case 4:
+ case 5:
+ _nextStoreClerkSequenceId = 0xB5;
+ break;
+ default:
+ _nextStoreClerkSequenceId = 0xB6;
+ break;
+ }
+ gameSys.setAnimation(_nextStoreClerkSequenceId, 1, 4);
+ gameSys.insertSequence(_nextStoreClerkSequenceId, 1, _currStoreClerkSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ _currStoreClerkSequenceId = _nextStoreClerkSequenceId;
+ _nextStoreClerkSequenceId = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene24::Scene24(GnapEngine *vm) : Scene(vm) {
+ _currWomanSequenceId = -1;
+ _nextWomanSequenceId = -1;
+ _boySequenceId = -1;
+ _girlSequenceId = -1;
+}
+
+int Scene24::init() {
+ return 0x3B;
+}
+
+void Scene24::updateHotspots() {
+ _vm->setHotspot(kHS24Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS24ExitCircusWorld, 785, 128, 800, 600, SF_EXIT_R_CURSOR, 8, 7);
+ _vm->setHotspot(kHS24ExitOutsideGrubCity, 0, 213, 91, 600, SF_EXIT_NW_CURSOR, 1, 8);
+ _vm->setHotspot(kHS24WalkArea1, 0, 0, 0, 0);
+ _vm->setHotspot(kHS24WalkArea2, 530, 0, 800, 600);
+ _vm->setHotspot(kHS24WalkArea3, 0, 0, 800, 517);
+ _vm->setDeviceHotspot(kHS24Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 7;
+}
+
+void Scene24::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ int counter = 0;
+
+ _vm->playSound(0x10940, true);
+ _vm->startSoundTimerA(9);
+
+ _vm->_timers[7] = _vm->getRandom(100) + 100;
+
+ gameSys.insertSequence(0x2F, 256, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->_timers[4] = _vm->getRandom(20) + 50;
+ _vm->_timers[5] = _vm->getRandom(20) + 40;
+ _vm->_timers[6] = _vm->getRandom(50) + 30;
+
+ gameSys.insertSequence(0x36, 20, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x30, 20, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x35, 20, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currWomanSequenceId = 0x35;
+ _girlSequenceId = 0x36;
+ _boySequenceId = 0x30;
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->_prevSceneNum == 20) {
+ gnap.initPos(1, 8, kDirBottomRight);
+ plat.initPos(2, 8, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(1, 9), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(2, 9), -1, 0x107C2, 1);
+ } else {
+ gnap.initPos(8, 8, kDirBottomLeft);
+ plat.initPos(8, 8, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(3, 8), -1, 0x107C2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+
+ case kHS24Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS24Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS24ExitCircusWorld:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 25;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS24ExitCircusWorld], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS24LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS24ExitCircusWorld] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS24ExitOutsideGrubCity:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 20;
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS24ExitOutsideGrubCity], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS24LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS24ExitOutsideGrubCity] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS24WalkArea1:
+ case kHS24WalkArea2:
+ case kHS24WalkArea3:
+ if (gnap._actionStatus == -1)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x10940))
+ _vm->playSound(0x10940, true);
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(20) + 50;
+ gameSys.insertSequence(0x37, 20, _girlSequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _girlSequenceId = 0x37;
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(20) + 40;
+ gameSys.insertSequence(0x31, 20, _boySequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _boySequenceId = 0x31;
+ }
+ if (!_vm->_timers[6]) {
+ _vm->_timers[6] = _vm->getRandom(50) + 30;
+ counter = (counter + 1) % 3;
+ switch (counter) {
+ case 0:
+ _nextWomanSequenceId = 0x32;
+ break;
+ case 1:
+ _nextWomanSequenceId = 0x33;
+ break;
+ case 2:
+ _nextWomanSequenceId = 0x34;
+ break;
+ }
+ gameSys.insertSequence(_nextWomanSequenceId, 20, _currWomanSequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currWomanSequenceId = _nextWomanSequenceId;
+ }
+ if (!_vm->_timers[7]) {
+ _vm->_timers[7] = _vm->getRandom(100) + 100;
+ switch (_vm->getRandom(3)) {
+ case 0:
+ gameSys.insertSequence(0x38, 253, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 1:
+ gameSys.insertSequence(0x39, 253, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 2:
+ gameSys.insertSequence(0x3A, 253, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ }
+ }
+ _vm->playSoundA();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene24::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ if (gnap._actionStatus == kAS24LeaveScene)
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene25::Scene25(GnapEngine *vm) : Scene(vm) {
+ _currTicketVendorSequenceId = -1;
+ _nextTicketVendorSequenceId = -1;
+}
+
+int Scene25::init() {
+ return 0x62;
+}
+
+void Scene25::updateHotspots() {
+ _vm->setHotspot(kHS25Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS25TicketVendor, 416, 94, 574, 324, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 5);
+ _vm->setHotspot(kHS25ExitOutsideCircusWorld, 0, 519, 205, 600, SF_EXIT_SW_CURSOR, 5, 10);
+ _vm->setHotspot(kHS25ExitInsideCircusWorld, 321, 70, 388, 350, SF_EXIT_NE_CURSOR, 3, 6);
+ _vm->setHotspot(kHS25Posters1, 0, 170, 106, 326, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 7);
+ _vm->setHotspot(kHS25Posters2, 146, 192, 254, 306, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 7);
+ _vm->setHotspot(kHS25Posters3, 606, 162, 654, 368, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 7);
+ _vm->setHotspot(kHS25Posters4, 708, 114, 754, 490, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 8);
+ _vm->setHotspot(kHS25WalkArea1, 0, 0, 800, 439);
+ _vm->setHotspot(kHS25WalkArea2, 585, 0, 800, 600);
+ _vm->setDeviceHotspot(kHS25Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 11;
+}
+
+void Scene25::playAnims(int index) {
+ if (index > 4)
+ return;
+
+ GameSys& gameSys = *_vm->_gameSys;
+
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+ switch (index) {
+ case 1:
+ _vm->_largeSprite = gameSys.createSurface(0x25);
+ break;
+ case 2:
+ _vm->_largeSprite = gameSys.createSurface(0x26);
+ break;
+ case 3:
+ _vm->_largeSprite = gameSys.createSurface(0x27);
+ break;
+ case 4:
+ _vm->_largeSprite = gameSys.createSurface(0x28);
+ break;
+ }
+ gameSys.insertSpriteDrawItem(_vm->_largeSprite, 0, 0, 300);
+ _vm->delayTicksCursor(5);
+ while (!_vm->_mouseClickState._left && !_vm->isKeyStatus1(Common::KEYCODE_ESCAPE) && !_vm->isKeyStatus1(Common::KEYCODE_SPACE) &&
+ !_vm->isKeyStatus1(Common::KEYCODE_RETURN) && !_vm->_gameDone) {
+ _vm->gameUpdateTick();
+ }
+ _vm->_mouseClickState._left = false;
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _vm->clearKeyStatus1(Common::KEYCODE_RETURN);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ gameSys.removeSpriteDrawItem(_vm->_largeSprite, 300);
+ _vm->delayTicksCursor(5);
+ _vm->deleteSurface(&_vm->_largeSprite);
+ _vm->showCursor();
+}
+
+void Scene25::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x10940, true);
+ _vm->startSoundTimerA(5);
+
+ _currTicketVendorSequenceId = 0x52;
+ gameSys.setAnimation(0x52, 39, 3);
+ gameSys.insertSequence(_currTicketVendorSequenceId, 39, 0, 0, kSeqNone, 0, 0, 0);
+
+ _nextTicketVendorSequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->_prevSceneNum == 24) {
+ gnap.initPos(5, 11, kDirUpLeft);
+ plat.initPos(6, 11, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(5, 7), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(6, 7), -1, 0x107C2, 1);
+ } else {
+ gnap.initPos(5, 6, kDirBottomRight);
+ plat.initPos(6, 6, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS25Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS25Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS25TicketVendor:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemTickets) {
+ gnap._actionStatus = kAS25ShowTicketToVendor;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS25TicketVendor], 0, gnap.getSequenceId(kGSIdle, Common::Point(9, 4)) | 0x10000, 1);
+ gnap.playPullOutDevice();
+ gnap.playUseDevice();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS25TicketVendor], 6, 1);
+ _nextTicketVendorSequenceId = 0x5B;
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(6, 1));
+ _nextTicketVendorSequenceId = (_vm->getRandom(2) == 1) ? 0x59 : 0x56;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS25TicketVendor], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS25TalkTicketVendor;
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS25ExitOutsideCircusWorld:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 24;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS25ExitOutsideCircusWorld], 0, 0x107B4, 1);
+ gnap._actionStatus = kAS25LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS25ExitOutsideCircusWorld] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS25ExitInsideCircusWorld:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFNeedleTaken)) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 26;
+ _vm->_hotspots[kHS25WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS25ExitInsideCircusWorld], 0, 0x107B1, 1);
+ gnap._actionStatus = kAS25LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS25ExitInsideCircusWorld] + Common::Point(1, 0), -1, 0x107C2, 1);
+ _vm->_hotspots[kHS25WalkArea1]._flags &= ~SF_WALKABLE;
+ } else {
+ _vm->_hotspots[kHS25WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(Common::Point(4, 5), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS25EnterCircusWihoutTicket;
+ _vm->_hotspots[kHS25WalkArea1]._flags &= ~SF_WALKABLE;
+ }
+ }
+ break;
+
+ case kHS25Posters1:
+ case kHS25Posters2:
+ case kHS25Posters3:
+ case kHS25Posters4:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.walkTo(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], -1, -1, 1);
+ if (_vm->_sceneClickedHotspot == 5 || _vm->_sceneClickedHotspot == 6)
+ gnap._idleFacing = kDirUpLeft;
+ else if (_vm->_sceneClickedHotspot == 8)
+ gnap._idleFacing = kDirBottomRight;
+ else
+ gnap._idleFacing = kDirUpRight;
+ gnap.playIdle();
+ playAnims(8 - _vm->_sceneClickedHotspot + 1);
+ break;
+ case GRAB_CURSOR:
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playMoan2();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS25WalkArea1:
+ case kHS25WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4] && _nextTicketVendorSequenceId == -1 && gnap._actionStatus == -1) {
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ switch (_vm->getRandom(13)) {
+ case 0:
+ _nextTicketVendorSequenceId = 0x54;
+ break;
+ case 1:
+ _nextTicketVendorSequenceId = 0x58;
+ break;
+ case 2:
+ _nextTicketVendorSequenceId = 0x55;
+ break;
+ case 3:
+ _nextTicketVendorSequenceId = 0x5A;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ _nextTicketVendorSequenceId = 0x5B;
+ break;
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ _nextTicketVendorSequenceId = 0x5C;
+ break;
+ case 12:
+ _nextTicketVendorSequenceId = 0x5D;
+ break;
+ default:
+ _nextTicketVendorSequenceId = 0x52;
+ break;
+ }
+ }
+ _vm->playSoundA();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene25::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS25TalkTicketVendor:
+ _nextTicketVendorSequenceId = (_vm->getRandom(2) == 1) ? 0x57 : 0x5F;
+ gnap._actionStatus = -1;
+ break;
+ case kAS25EnterCircusWihoutTicket:
+ _nextTicketVendorSequenceId = 0x5E;
+ gameSys.setAnimation(0x5E, 39, 0);
+ gameSys.setAnimation(_nextTicketVendorSequenceId, 39, 3);
+ gameSys.insertSequence(_nextTicketVendorSequenceId, 39, _currTicketVendorSequenceId, 39, kSeqSyncExists, 0, 0, 0);
+ gameSys.insertSequence(0x60, 2, 0, 0, kSeqNone, 0, 0, 0);
+ _currTicketVendorSequenceId = _nextTicketVendorSequenceId;
+ _nextTicketVendorSequenceId = -1;
+ _vm->_hotspots[kHS25WalkArea1]._flags |= SF_WALKABLE;
+ gnap.playIdle();
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], -1, 0x107BB, 1);
+ _vm->_hotspots[kHS25WalkArea1]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = kAS25EnterCircusWihoutTicketDone;
+ break;
+ case kAS25EnterCircusWihoutTicketDone:
+ gnap._actionStatus = -1;
+ break;
+ case kAS25ShowTicketToVendor:
+ _vm->setGrabCursorSprite(-1);
+ _vm->invRemove(kItemTickets);
+ _vm->setFlag(kGFNeedleTaken);
+ gameSys.setAnimation(0x61, 40, 0);
+ gameSys.insertSequence(0x61, 40, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._actionStatus = kAS25ShowTicketToVendorDone;
+ break;
+ case kAS25ShowTicketToVendorDone:
+ _nextTicketVendorSequenceId = 0x53;
+ break;
+ case kAS25LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ if (_nextTicketVendorSequenceId == 0x53) {
+ gameSys.insertSequence(_nextTicketVendorSequenceId, 39, _currTicketVendorSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ _currTicketVendorSequenceId = _nextTicketVendorSequenceId;
+ _nextTicketVendorSequenceId = -1;
+ gnap._actionStatus = -1;
+ } else if (_nextTicketVendorSequenceId != -1) {
+ gameSys.setAnimation(_nextTicketVendorSequenceId, 39, 3);
+ gameSys.insertSequence(_nextTicketVendorSequenceId, 39, _currTicketVendorSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ _currTicketVendorSequenceId = _nextTicketVendorSequenceId;
+ _nextTicketVendorSequenceId = -1;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene26::Scene26(GnapEngine *vm) : Scene(vm) {
+ _currKidSequenceId = -1;
+ _nextKidSequenceId = -1;
+}
+
+int Scene26::init() {
+ return _vm->isFlag(kGFUnk23) ? 0x61 : 0x60;
+}
+
+void Scene26::updateHotspots() {
+ _vm->setHotspot(kHS26Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS26ExitOutsideCircusWorld, 0, 590, 300, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 1, 10);
+ _vm->setHotspot(kHS26ExitOutsideClown, 200, 265, 265, 350, SF_EXIT_U_CURSOR, 3, 8);
+ _vm->setHotspot(kHS26ExitArcade, 0, 295, 150, 400, SF_EXIT_NW_CURSOR, 2, 8);
+ _vm->setHotspot(kHS26ExitElephant, 270, 290, 485, 375, SF_EXIT_U_CURSOR, 5, 8);
+ _vm->setHotspot(kHS26ExitBeerStand, 530, 290, 620, 350, SF_EXIT_NE_CURSOR, 5, 8);
+ _vm->setHotspot(kHS26WalkArea1, 0, 0, 800, 500);
+ _vm->setHotspot(kHS26WalkArea2, 281, 0, 800, 600);
+ _vm->setDeviceHotspot(kHS26Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 9;
+}
+
+void Scene26::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->startSoundTimerB(7);
+ _vm->playSound(0x1093B, true);
+
+ _currKidSequenceId = 0x5B;
+ _nextKidSequenceId = -1;
+ gameSys.setAnimation(0x5B, 160, 3);
+ gameSys.insertSequence(_currKidSequenceId, 160, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->_timers[5] = _vm->getRandom(20) + 50;
+ _vm->_timers[4] = _vm->getRandom(20) + 50;
+ _vm->_timers[6] = _vm->getRandom(50) + 100;
+
+ _vm->queueInsertDeviceIcon();
+
+ gameSys.insertSequence(0x58, 40, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x5C, 40, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x5D, 40, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x5E, 40, 0, 0, kSeqLoop, 0, 0, 0);
+
+ if (_vm->_prevSceneNum == 25) {
+ gnap.initPos(-1, 8, kDirBottomRight);
+ plat.initPos(-2, 8, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1);
+ } else {
+ gnap.initPos(2, 8, kDirBottomRight);
+ plat.initPos(3, 8, kDirIdleLeft);
+ _vm->endSceneInit();
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS26Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS26Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS26ExitOutsideCircusWorld:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 25;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS26ExitOutsideCircusWorld].y), 0, 0x107AE, 1);
+ gnap._actionStatus = kAS26LeaveScene;
+ }
+ break;
+
+ case kHS26ExitOutsideClown:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 27;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS26ExitOutsideClown].y), 0, 0x107BC, 1);
+ gnap._actionStatus = kAS26LeaveScene;
+ }
+ break;
+
+ case kHS26ExitArcade:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 29;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS26ExitArcade].y), 0, 0x107BC, 1);
+ gnap._actionStatus = kAS26LeaveScene;
+ }
+ break;
+
+ case kHS26ExitElephant:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 30;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS26ExitElephant].y), 0, 0x107BC, 1);
+ gnap._actionStatus = kAS26LeaveScene;
+ }
+ break;
+
+ case kHS26ExitBeerStand:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 31;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS26ExitBeerStand].y), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS26LeaveScene;
+ }
+ break;
+
+ case kHS26WalkArea1:
+ case kHS26WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1093B))
+ _vm->playSound(0x1093B, true);
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[5] && _nextKidSequenceId == -1) {
+ _vm->_timers[5] = _vm->getRandom(20) + 50;
+ if (_vm->getRandom(5) != 0)
+ _nextKidSequenceId = 0x5B;
+ else
+ _nextKidSequenceId = 0x5A;
+ }
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(20) + 130;
+ gameSys.insertSequence(0x59, 40, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ if (!_vm->_timers[6]) {
+ _vm->_timers[6] = _vm->getRandom(50) + 100;
+ gameSys.insertSequence(0x5F, 40, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ _vm->playSoundB();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene26::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ if (gnap._actionStatus == kAS26LeaveScene)
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2 && _nextKidSequenceId != -1) {
+ gameSys.insertSequence(_nextKidSequenceId, 160, _currKidSequenceId, 160, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextKidSequenceId, 160, 3);
+ _currKidSequenceId = _nextKidSequenceId;
+ _nextKidSequenceId = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene27::Scene27(GnapEngine *vm) : Scene(vm) {
+ _nextJanitorSequenceId = -1;
+ _currJanitorSequenceId = -1;
+}
+
+int Scene27::init() {
+ return 0xD5;
+}
+
+void Scene27::updateHotspots() {
+ _vm->setHotspot(kHS27Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS27Janitor, 488, 204, 664, 450, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 8, 8);
+ _vm->setHotspot(kHS27Bucket, 129, 406, 186, 453, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 6);
+ _vm->setHotspot(kHS27ExitCircus, 200, 585, 700, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS27ExitArcade, 0, 0, 15, 600, SF_EXIT_L_CURSOR, 0, 6);
+ _vm->setHotspot(kHS27ExitBeerStand, 785, 0, 800, 600, SF_EXIT_R_CURSOR, 11, 7);
+ _vm->setHotspot(kHS27ExitClown, 340, 240, 460, 420, SF_EXIT_U_CURSOR, 6, 8);
+ _vm->setHotspot(kHS27WalkArea1, 0, 0, 800, 507);
+ _vm->setDeviceHotspot(kHS27Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFUnk13))
+ _vm->_hotspots[kHS27Bucket]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 9;
+}
+
+void Scene27::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1093B, true);
+ _vm->startSoundTimerB(4);
+ _vm->_timers[7] = _vm->getRandom(100) + 300;
+ _vm->queueInsertDeviceIcon();
+
+ if (!_vm->isFlag(kGFUnk13))
+ gameSys.insertSequence(0xD3, 39, 0, 0, kSeqNone, 0, 0, 0);
+
+ gameSys.insertSequence(0xCB, 39, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currJanitorSequenceId = 0xCB;
+ _nextJanitorSequenceId = -1;
+
+ gameSys.setAnimation(0xCB, 39, 3);
+ _vm->_timers[5] = _vm->getRandom(20) + 60;
+
+ switch (_vm->_prevSceneNum) {
+ case 26:
+ gnap.initPos(7, 12, kDirBottomRight);
+ plat.initPos(6, 12, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(7, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+ break;
+ case 29:
+ gnap.initPos(-1, 8, kDirBottomRight);
+ plat.initPos(-1, 9, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(3, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(3, 9), -1, 0x107C2, 1);
+ break;
+ case 31:
+ gnap.initPos(12, 8, kDirBottomLeft);
+ plat.initPos(12, 9, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(8, 9), -1, 0x107C2, 1);
+ break;
+ default:
+ gnap.initPos(6, 8, kDirBottomRight);
+ plat.initPos(5, 9, kDirIdleLeft);
+ _vm->endSceneInit();
+ break;
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+ _vm->_sceneClickedHotspot = -1;
+ if (gnap._actionStatus < 0)
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS27Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS27Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS27Janitor:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemPicture) {
+ gnap._idleFacing = kDirUpLeft;
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[kHS27Janitor], 0, 0x107BC, 1))
+ gnap._actionStatus = kAS27ShowPictureToJanitor;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS27Janitor], 7, 3);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(6, 3));
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS27Janitor], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS27TalkJanitor;
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS27Bucket:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 3, 3);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(3, 3));
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[kHS27Bucket]) | 0x10000, 1);
+ gnap._actionStatus = kAS27GrabBucket;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS27ExitCircus:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 26;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS27ExitCircus].y), 0, 0x107AE, 1);
+ gnap._actionStatus = kAS27LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS27ExitCircus] + Common::Point(1, 0), -1, 0x107C7, 1);
+ }
+ break;
+
+ case kHS27ExitArcade:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 29;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS27ExitArcade].y), 0, 0x107AF, 1);
+ gnap._actionStatus = kAS27LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS27ExitArcade] + Common::Point(0, 1), -1, 0x107CF, 1);
+ }
+ break;
+
+ case kHS27ExitBeerStand:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 31;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS27ExitBeerStand].y), 0, 0x107AB, 1);
+ gnap._actionStatus = kAS27LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS27ExitBeerStand] + Common::Point(0, 1), -1, 0x107CD, 1);
+ }
+ break;
+
+ case kHS27ExitClown:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypus)) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 28;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS27ExitClown], 0, 0x107AD, 1);
+ gnap._actionStatus = kAS27LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS27ExitClown] + Common::Point(1, 0), -1, 0x107C4, 1);
+ } else {
+ _vm->_hotspots[kHS27WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS27ExitClown].x, 7), 0, 0x107BC, 1);
+ _vm->_hotspots[kHS27WalkArea1]._flags &= SF_WALKABLE;
+ gnap._actionStatus = kAS27TryEnterClownTent;
+ }
+ }
+ break;
+
+ case kHS27WalkArea1:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1093B))
+ _vm->playSound(0x1093B, true);
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(20) + 60;
+ if (gnap._actionStatus < 0) {
+ if (_vm->getRandom(3) != 0)
+ _nextJanitorSequenceId = 0xCB;
+ else
+ _nextJanitorSequenceId = 0xCF;
+ }
+ }
+ if (!_vm->_timers[7]) {
+ _vm->_timers[7] = _vm->getRandom(100) + 300;
+ if (gnap._actionStatus < 0)
+ gameSys.insertSequence(0xD4, 120, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ _vm->playSoundB();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene27::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS27TalkJanitor:
+ switch (_vm->getRandom(3)) {
+ case 0:
+ _nextJanitorSequenceId = 0xCC;
+ break;
+ case 1:
+ _nextJanitorSequenceId = 0xCD;
+ break;
+ case 2:
+ _nextJanitorSequenceId = 0xCE;
+ break;
+ }
+ break;
+ case kAS27GrabBucket:
+ gnap.playPullOutDevice();
+ gnap.playUseDevice();
+ _vm->_hotspots[kHS27Bucket]._flags = SF_DISABLED;
+ _vm->invAdd(kItemEmptyBucket);
+ _vm->setFlag(kGFUnk13);
+ gameSys.setAnimation(0xD2, 39, 0);
+ gameSys.insertSequence(0xD2, 39, 211, 39, kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = kAS27GrabBucketDone;
+ break;
+ case kAS27GrabBucketDone:
+ _vm->setGrabCursorSprite(kItemEmptyBucket);
+ gnap._actionStatus = -1;
+ break;
+ case kAS27ShowPictureToJanitor:
+ _nextJanitorSequenceId = 0xD0;
+ break;
+ case kAS27TryEnterClownTent:
+ _nextJanitorSequenceId = 0xD1;
+ gameSys.insertSequence(0xD1, 39, _currJanitorSequenceId, 39, kSeqSyncExists, 0, 0, 0);
+ gameSys.setAnimation(_nextJanitorSequenceId, 39, 3);
+ gameSys.setAnimation(_nextJanitorSequenceId, 39, 0);
+ _currJanitorSequenceId = _nextJanitorSequenceId;
+ _nextJanitorSequenceId = -1;
+ gnap._actionStatus = kAS27TryEnterClownTentDone;
+ break;
+ case kAS27TryEnterClownTentDone:
+ _vm->_hotspots[kHS27WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[7].x, 9), -1, 0x107BC, 1);
+ _vm->_hotspots[kHS27WalkArea1]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = -1;
+ break;
+ case kAS27EnterClownTent:
+ gnap.walkTo(gnap._pos, 0, 0x107B2, 1);
+ gnap._actionStatus = kAS27LeaveScene;
+ break;
+ case kAS27LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ switch (_nextJanitorSequenceId) {
+ case -1:
+ _nextJanitorSequenceId = 0xCB;
+ gameSys.insertSequence(0xCB, 39, _currJanitorSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextJanitorSequenceId, 39, 3);
+ _currJanitorSequenceId = _nextJanitorSequenceId;
+ _nextJanitorSequenceId = -1;
+ break;
+ case 0xCC:
+ case 0xCD:
+ case 0xCE:
+ gnap._actionStatus = -1;
+ gameSys.insertSequence(_nextJanitorSequenceId, 39, _currJanitorSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextJanitorSequenceId, 39, 3);
+ gameSys.setAnimation(_nextJanitorSequenceId, 39, 0);
+ _currJanitorSequenceId = _nextJanitorSequenceId;
+ _nextJanitorSequenceId = -1;
+ break;
+ case 0xD0:
+ // Show picture to janitor
+ gnap.playPullOutDevice();
+ gnap.playUseDevice();
+ gameSys.insertSequence(_nextJanitorSequenceId, 39, _currJanitorSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextJanitorSequenceId, 39, 0);
+ gnap._actionStatus = kAS27EnterClownTent;
+ _currJanitorSequenceId = _nextJanitorSequenceId;
+ _nextJanitorSequenceId = -1;
+ _vm->setFlag(kGFPlatypus);
+ _vm->setGrabCursorSprite(-1);
+ _vm->invRemove(kItemPicture);
+ _vm->_newSceneNum = 28;
+ break;
+ default:
+ gameSys.insertSequence(_nextJanitorSequenceId, 39, _currJanitorSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextJanitorSequenceId, 39, 3);
+ _currJanitorSequenceId = _nextJanitorSequenceId;
+ _nextJanitorSequenceId = -1;
+ break;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene28::Scene28(GnapEngine *vm) : Scene(vm) {
+ _currClownSequenceId = -1;
+ _nextClownSequenceId = -1;
+ _clownTalkCtr = 0;
+}
+
+int Scene28::init() {
+ return 0x125;
+}
+
+void Scene28::updateHotspots() {
+ _vm->setHotspot(kHS28Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS28Horn, 148, 352, 215, 383, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 7);
+ _vm->setHotspot(kHS28Clown, 130, 250, 285, 413, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 5);
+ _vm->setHotspot(kHS28ExitOutsideClown, 660, 190, 799, 400, SF_EXIT_R_CURSOR, 9, 6);
+ _vm->setHotspot(kHS28EmptyBucket, 582, 421, 643, 478, SF_WALKABLE | SF_DISABLED, 9, 7);
+ _vm->setHotspot(kHS28WalkArea1, 0, 0, 799, 523);
+ _vm->setHotspot(kHS28WalkArea2, 0, 0, 0, 0, 7, SF_DISABLED);
+ _vm->setDeviceHotspot(kHS28Device, -1, -1, -1, -1);
+ if (_vm->invHas(kItemHorn))
+ _vm->_hotspots[kHS28Horn]._flags = SF_DISABLED;
+ if (_vm->isFlag(kGFUnk22))
+ _vm->_hotspots[kHS28EmptyBucket]._flags = SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ _vm->_hotspotsCount = 8;
+}
+
+void Scene28::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1093C, true);
+ _nextClownSequenceId = -1;
+ _vm->queueInsertDeviceIcon();
+ gameSys.insertSequence(0x124, 255, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFUnk22))
+ gameSys.insertSequence(0x112, 99, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFMudTaken)) {
+ if (_vm->isFlag(kGFUnk21)) {
+ gameSys.setAnimation(0x11C, 39, 3);
+ gameSys.insertSequence(0x11C, 39, 0, 0, kSeqNone, 0, 0, 0);
+ if (!_vm->invHas(kItemHorn))
+ gameSys.insertSequence(0x118, 59, 0, 0, kSeqNone, 0, 0, 0);
+ _currClownSequenceId = 0x11C;
+ } else {
+ _currClownSequenceId = 0x11B;
+ gameSys.setAnimation(0x11B, 39, 3);
+ gameSys.insertSequence(_currClownSequenceId, 39, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_timers[4] = _vm->getRandom(20) + 80;
+ }
+ gnap.initPos(8, 8, kDirBottomLeft);
+ plat.initPos(9, 8, kDirIdleRight);
+ _vm->endSceneInit();
+ } else {
+ gameSys.insertSequence(0x11B, 39, 0, 0, kSeqNone, 0, 0, 0);
+ gnap.initPos(8, 8, kDirBottomLeft);
+ plat.initPos(9, 8, kDirIdleRight);
+ _vm->endSceneInit();
+ _vm->playSequences(0xF7, 0x121, 0x122, 0x123);
+ _currClownSequenceId = 0x115;
+ _vm->setFlag(kGFMudTaken);
+ gameSys.setAnimation(0x115, 39, 3);
+ gameSys.insertSequence(_currClownSequenceId, 39, 0x11B, 39, kSeqSyncWait, 0, 0, 0);
+ _nextClownSequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(20) + 80;
+ gnap._actionStatus = kAS28GnapWaiting;
+ while (gameSys.getAnimationStatus(3) != 2 && !_vm->_gameDone) {
+ _vm->gameUpdateTick();
+ _vm->updateMouseCursor();
+ }
+ gnap._actionStatus = -1;
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS28Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS28Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS28Horn:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(2, 8), 3, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(2, 4));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFUnk21)) {
+ if (!_vm->invHas(kItemHorn)) {
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[kHS28Horn]) | 0x10000, 1);
+ gnap._actionStatus = kAS28GrabHornSuccess;
+ }
+ } else {
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(Common::Point(2, 8), 0, 0x107BB, 1);
+ _vm->_hotspots[kHS28WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS28Horn], 0, 0x107BB, 1);
+ _vm->_hotspots[kHS28WalkArea1]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = kAS28GrabHornFails;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS28Clown:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFUnk21)) {
+ if (_vm->_verbCursor == LOOK_CURSOR)
+ gnap.playScratchingHead(Common::Point(5, 2));
+ else
+ gnap.playImpossible();
+ } else if (_vm->_grabCursorSpriteIndex == kItemBucketWithBeer) {
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS28Clown], 0, 0x107BC, 1);
+ gnap.playPullOutDevice();
+ gnap.playUseDevice();
+ gnap._actionStatus = kAS28UseBeerBucketWithClown;
+ } else if (_vm->_grabCursorSpriteIndex == kItemBucketWithPill) {
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS28Clown], 0, 0x107BC, 1);
+ gnap.playPullOutDevice();
+ gnap.playUseDevice();
+ gnap._actionStatus = kAS28UsePillBucketWithClown;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS28Clown], 2, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(5, 2));
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(Common::Point(5, 8), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS28TalkClown;
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS28ExitOutsideClown:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 27;
+ _vm->_hotspots[kHS28WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS28ExitOutsideClown], 0, 0x107BF, 1);
+ gnap._actionStatus = kAS28LeaveScene;
+ _vm->_hotspots[kHS28WalkArea1]._flags &= ~SF_WALKABLE;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS28ExitOutsideClown] + Common::Point(-1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS28EmptyBucket:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 8, 6);
+ } else if (_vm->isFlag(kGFUnk21)) {
+ gnap.playImpossible(Common::Point(8, 6));
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(8, 6));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[kHS28EmptyBucket]) | 0x10000, 1);
+ gnap._actionStatus = kAS28GrabEmptyBucket;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS28WalkArea1:
+ case kHS28WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1093C))
+ _vm->playSound(0x1093C, true);
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(20) + 80;
+ if (gnap._actionStatus < 0 && !_vm->isFlag(kGFUnk21))
+ _nextClownSequenceId = 0x114;
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene28::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS28UseBeerBucketWithClown:
+ _vm->setFlag(kGFUnk22);
+ _nextClownSequenceId = 0x113;
+ _vm->invRemove(kItemBucketWithBeer);
+ updateHotspots();
+ break;
+ case kAS28UsePillBucketWithClown:
+ _nextClownSequenceId = 0x116;
+ _vm->invRemove(kItemBucketWithPill);
+ _vm->setFlag(kGFUnk22);
+ _vm->setFlag(kGFUnk21);
+ updateHotspots();
+ break;
+ case kAS28GrabHornFails:
+ _nextClownSequenceId = 0x119;
+ break;
+ case kAS28GrabHornSuccess:
+ gnap.playPullOutDevice();
+ gnap.playUseDevice();
+ gameSys.setAnimation(0x117, 59, 0);
+ gameSys.insertSequence(0x117, 59, 280, 59, kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = kAS28GrabHornSuccessDone;
+ break;
+ case kAS28GrabHornSuccessDone:
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+ _vm->addFullScreenSprite(0xF6, 255);
+ gameSys.setAnimation(0x120, 256, 0);
+ gameSys.insertSequence(0x120, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ _vm->removeFullScreenSprite();
+ _vm->showCursor();
+ _vm->setGrabCursorSprite(kItemHorn);
+ _vm->invAdd(kItemHorn);
+ updateHotspots();
+ gnap._actionStatus = -1;
+ break;
+ case kAS28GrabEmptyBucket:
+ gnap.playPullOutDevice();
+ gnap.playUseDevice();
+ gameSys.setAnimation(0x111, 99, 0);
+ gameSys.insertSequence(0x111, 99, 274, 99, kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = kAS28GrabEmptyBucketDone;
+ break;
+ case kAS28GrabEmptyBucketDone:
+ _vm->setGrabCursorSprite(kItemEmptyBucket);
+ _vm->clearFlag(kGFUnk22);
+ updateHotspots();
+ _vm->invAdd(kItemEmptyBucket);
+ gnap._actionStatus = -1;
+ break;
+ case kAS28GrabHornFailsDone:
+ gameSys.insertSequence(0x107B5, gnap._id, 281, 39, kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = 0x7B5;
+ gnap._sequenceDatNum = 1;
+ gameSys.insertSequence(0x11B, 39, 0, 0, kSeqNone, 0, 0, 0);
+ _currClownSequenceId = 0x11B;
+ _nextClownSequenceId = -1;
+ gnap._actionStatus = -1;
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107BB, 1);
+ break;
+ case kAS28TalkClown:
+ // The original was only using the first two sequences,
+ // due to a bug.
+ _clownTalkCtr = (_clownTalkCtr + 1) % 3;
+ if (_clownTalkCtr == 0)
+ _nextClownSequenceId = 0x11D;
+ else if (_clownTalkCtr == 1)
+ _nextClownSequenceId = 0x11E;
+ else if (_clownTalkCtr == 2)
+ _nextClownSequenceId = 0x11F;
+ break;
+ case kAS28GnapWaiting:
+ gnap._actionStatus = -1;
+ break;
+ case kAS28LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ switch (_nextClownSequenceId) {
+ case 0x113:
+ _vm->setGrabCursorSprite(-1);
+ gameSys.setAnimation(_nextClownSequenceId, 39, 0);
+ gameSys.insertSequence(0x112, 99, 0, 0, kSeqNone, _vm->getSequenceTotalDuration(_nextClownSequenceId), 0, 0);
+ gameSys.insertSequence(_nextClownSequenceId, 39, _currClownSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x11B, 39, _nextClownSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ _currClownSequenceId = 0x11B;
+ _nextClownSequenceId = -1;
+ gnap._actionStatus = kAS28GnapWaiting;
+ break;
+ case 0x116:
+ _vm->setGrabCursorSprite(-1);
+ gameSys.setAnimation(_nextClownSequenceId, 39, 0);
+ gameSys.insertSequence(0x112, 99, 0, 0, kSeqNone, _vm->getSequenceTotalDuration(_nextClownSequenceId), 0, 0);
+ gameSys.insertSequence(_nextClownSequenceId, 39, _currClownSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x11C, 39, _nextClownSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x118, 59, 0, 0, kSeqNone, _vm->getSequenceTotalDuration(_nextClownSequenceId), 0, 0);
+ _currClownSequenceId = _nextClownSequenceId;
+ _nextClownSequenceId = -1;
+ gnap._actionStatus = kAS28GnapWaiting;
+ break;
+ case 0x11D:
+ case 0x11E:
+ case 0x11F:
+ gnap._actionStatus = -1;
+ break;
+ case 0x119:
+ gameSys.insertSequence(_nextClownSequenceId, 39, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextClownSequenceId, 39, 0);
+ gameSys.removeSequence(_currClownSequenceId, 39, true);
+ gnap._actionStatus = kAS28GrabHornFailsDone;
+ gnap._sequenceId = _nextClownSequenceId;
+ gnap._sequenceDatNum = 0;
+ _nextClownSequenceId = -1;
+ break;
+ }
+ if (_nextClownSequenceId != -1) {
+ gameSys.insertSequence(_nextClownSequenceId, 39, _currClownSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextClownSequenceId, 39, 3);
+ _currClownSequenceId = _nextClownSequenceId;
+ _nextClownSequenceId = -1;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene29::Scene29(GnapEngine *vm) : Scene(vm) {
+ _currMonkeySequenceId = -1;
+ _nextMonkeySequenceId = -1;
+ _currManSequenceId = -1;
+ _nextManSequenceId = -1;
+}
+
+int Scene29::init() {
+ return 0xF6;
+}
+
+void Scene29::updateHotspots() {
+ _vm->setHotspot(kHS29Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS29Monkey, 410, 374, 518, 516, SF_WALKABLE | SF_DISABLED, 3, 7);
+ _vm->setHotspot(kHS29ExitCircus, 150, 585, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS29ExitOutsideClown, 785, 0, 800, 600, SF_EXIT_R_CURSOR | SF_WALKABLE, 11, 9);
+ _vm->setHotspot(kHS29Arcade, 88, 293, 155, 384, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 8);
+ _vm->setHotspot(kHS29WalkArea1, 0, 0, 800, 478);
+ _vm->setDeviceHotspot(kHS29Device, -1, -1, -1, -1);
+ if (_vm->invHas(kItemHorn))
+ _vm->_hotspots[kHS29Monkey]._flags = SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ _vm->_hotspotsCount = 7;
+}
+
+void Scene29::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1093B, true);
+ _vm->startSoundTimerB(6);
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->invHas(kItemHorn)) {
+ _currMonkeySequenceId = 0xE8;
+ _nextMonkeySequenceId = -1;
+ gameSys.setAnimation(0xE8, 159, 4);
+ gameSys.insertSequence(_currMonkeySequenceId, 159, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0xED, 39, 0, 0, kSeqNone, 0, 0, 0);
+ _currManSequenceId = 0xED;
+ _nextManSequenceId = -1;
+ gameSys.setAnimation(0xED, 39, 3);
+ _vm->_timers[4] = _vm->getRandom(20) + 60;
+ } else {
+ gameSys.insertSequence(0xF4, 19, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(0, 0, 4);
+ gameSys.insertSequence(0xED, 39, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(0, 0, 3);
+ }
+
+ gameSys.insertSequence(0xF3, 39, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0xF5, 38, 0, 0, kSeqLoop, 0, 0, 0);
+
+ if (_vm->_prevSceneNum == 27) {
+ gnap.initPos(12, 7, kDirBottomRight);
+ plat.initPos(12, 8, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 7), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(8, 8), -1, 0x107C2, 1);
+ } else {
+ gnap.initPos(-1, 7, kDirBottomRight);
+ plat.initPos(-2, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(2, 7), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(1, 7), -1, 0x107C2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS29Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS29Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS29Monkey:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemBanana) {
+ gnap._idleFacing = kDirBottomRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS29Monkey], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS29UseBananaWithMonkey;
+ _vm->_newSceneNum = 51;
+ _vm->_isLeavingScene = true;
+ _vm->setGrabCursorSprite(-1);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS29Monkey], 5, 6);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(5, 6));
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(_vm->_hotspotsWalkPos[kHS29Monkey]);
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS29ExitCircus:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 26;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS29ExitCircus], 0, 0x107AE, 1);
+ gnap._actionStatus = kAS29LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS29ExitCircus] + Common::Point(1, 0), -1, -1, 1);
+ }
+ break;
+
+ case kHS29ExitOutsideClown:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 27;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS29ExitOutsideClown], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS29LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS29ExitOutsideClown] + Common::Point(0, -1), -1, 0x107CD, 1);
+ }
+ break;
+
+ case kHS29Arcade:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole) {
+ _vm->setGrabCursorSprite(-1);
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 52;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS29Arcade], 0, -1, 1);
+ gnap.playIdle(_vm->_hotspotsWalkPos[kHS29Arcade]);
+ gnap._actionStatus = kAS29LeaveScene;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS29Arcade], 2, 3);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2();
+ break;
+ case GRAB_CURSOR:
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS29WalkArea1:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1093B))
+ _vm->playSound(0x1093B, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (gnap._actionStatus < 0) {
+ gnap.updateIdleSequence();
+ plat.updateIdleSequence();
+ }
+ if (!_vm->_timers[4]) {
+ if (_vm->invHas(kItemHorn)) {
+ _vm->_timers[4] = _vm->getRandom(20) + 60;
+ if (gnap._actionStatus < 0) {
+ switch (_vm->getRandom(5)) {
+ case 0:
+ _nextManSequenceId = 0xED;
+ break;
+ case 1:
+ _nextManSequenceId = 0xEE;
+ break;
+ case 2:
+ _nextManSequenceId = 0xEF;
+ break;
+ case 3:
+ _nextManSequenceId = 0xF0;
+ break;
+ case 4:
+ _nextManSequenceId = 0xF1;
+ break;
+ }
+ }
+ }
+ }
+ _vm->playSoundB();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene29::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS29UseBananaWithMonkey:
+ _nextMonkeySequenceId = 0xE5;
+ break;
+ case kAS29LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2 && _nextManSequenceId != -1) {
+ gameSys.insertSequence(_nextManSequenceId, 39, _currManSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextManSequenceId, 39, 3);
+ _currManSequenceId = _nextManSequenceId;
+ _nextManSequenceId = -1;
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2) {
+ if (_nextMonkeySequenceId == 0xE5) {
+ gameSys.insertSequence(0xF2, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0xF2;
+ gameSys.setAnimation(0xE6, 159, 0);
+ gameSys.setAnimation(0, 159, 4);
+ gameSys.insertSequence(_nextMonkeySequenceId, 159, _currMonkeySequenceId, 159, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0xE6, 159, _nextMonkeySequenceId, 159, kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = kAS29LeaveScene;
+ _currMonkeySequenceId = 0xE6;
+ _nextMonkeySequenceId = -1;
+ _vm->_timers[5] = 30;
+ while (_vm->_timers[5] && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ _vm->_plat->walkTo(Common::Point(0, 8), 1, 0x107CF, 1);
+
+ while (gameSys.getAnimationStatus(1) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ } else if (_nextMonkeySequenceId == -1) {
+ switch (_vm->getRandom(6)) {
+ case 0:
+ _nextMonkeySequenceId = 0xE8;
+ break;
+ case 1:
+ _nextMonkeySequenceId = 0xE9;
+ break;
+ case 2:
+ _nextMonkeySequenceId = 0xEA;
+ break;
+ case 3:
+ _nextMonkeySequenceId = 0xEB;
+ break;
+ case 4:
+ _nextMonkeySequenceId = 0xEC;
+ break;
+ case 5:
+ _nextMonkeySequenceId = 0xE7;
+ break;
+ }
+ gameSys.insertSequence(_nextMonkeySequenceId, 159, _currMonkeySequenceId, 159, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextMonkeySequenceId, 159, 4);
+ _currMonkeySequenceId = _nextMonkeySequenceId;
+ _nextMonkeySequenceId = -1;
+ } else {
+ gameSys.insertSequence(_nextMonkeySequenceId, 159, _currMonkeySequenceId, 159, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextMonkeySequenceId, 159, 4);
+ _currMonkeySequenceId = _nextMonkeySequenceId;
+ _nextMonkeySequenceId = -1;
+ }
+ }
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/group2.h b/engines/gnap/scenes/group2.h
new file mode 100644
index 0000000000..8f56594f16
--- /dev/null
+++ b/engines/gnap/scenes/group2.h
@@ -0,0 +1,407 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 GNAP_GROUP2_H
+#define GNAP_GROUP2_H
+
+#include "gnap/debugger.h"
+
+namespace Gnap {
+
+enum {
+ kHS20Platypus = 0,
+ kHS20GroceryStoreHat = 1,
+ kHS20ExitParkingLot = 2,
+ kHS20StonerGuy = 3,
+ kHS20GroceryStoreGuy = 4,
+ kHS20Device = 5,
+ kHS20ExitInsideGrubCity = 6,
+ kHS20ExitOutsideCircusWorld = 7,
+ kHS20ExitOutsideToyStore = 8,
+ kHS20ExitPhone = 9,
+ kHS20WalkArea1 = 10,
+ kHS20WalkArea2 = 11
+};
+
+enum {
+ kHS21Platypus = 0,
+ kHS21Banana = 1,
+ kHS21OldLady = 2,
+ kHS21Device = 3,
+ kHS21ExitOutsideGrubCity = 4,
+ kHS21WalkArea1 = 5,
+ kHS21WalkArea2 = 6
+};
+
+enum {
+ kHS22Platypus = 0,
+ kHS22ExitOutsideGrubCity = 1,
+ kHS22ExitBackGrubCity = 2,
+ kHS22Cashier = 3,
+ kHS22Device = 4,
+ kHS22WalkArea1 = 5,
+ kHS22WalkArea2 = 6
+};
+
+enum {
+ kHS23Platypus = 0,
+ kHS23ExitFrontGrubCity = 1,
+ kHS23Device = 2,
+ kHS23Cereals = 3,
+ kHS23WalkArea1 = 4,
+ kHS23WalkArea2 = 5
+};
+
+enum {
+ kHS24Platypus = 0,
+ kHS24ExitCircusWorld = 1,
+ kHS24ExitOutsideGrubCity = 2,
+ kHS24Device = 3,
+ kHS24WalkArea1 = 4,
+ kHS24WalkArea2 = 5,
+ kHS24WalkArea3 = 6
+};
+
+enum {
+ kHS25Platypus = 0,
+ kHS25TicketVendor = 1,
+ kHS25ExitOutsideCircusWorld = 2,
+ kHS25ExitInsideCircusWorld = 3,
+ kHS25Device = 4,
+ kHS25Posters1 = 5,
+ kHS25Posters2 = 6,
+ kHS25Posters3 = 7,
+ kHS25Posters4 = 8,
+ kHS25WalkArea1 = 9,
+ kHS25WalkArea2 = 10
+};
+
+enum {
+ kHS26Platypus = 0,
+ kHS26ExitOutsideCircusWorld = 1,
+ kHS26ExitOutsideClown = 2,
+ kHS26ExitArcade = 3,
+ kHS26ExitElephant = 4,
+ kHS26ExitBeerStand = 5,
+ kHS26Device = 6,
+ kHS26WalkArea1 = 7,
+ kHS26WalkArea2 = 8
+};
+
+enum {
+ kHS27Platypus = 0,
+ kHS27Janitor = 1,
+ kHS27Device = 2,
+ kHS27Bucket = 3,
+ kHS27ExitCircus = 4,
+ kHS27ExitArcade = 5,
+ kHS27ExitBeerStand = 6,
+ kHS27ExitClown = 7,
+ kHS27WalkArea1 = 8
+};
+
+enum {
+ kHS28Platypus = 0,
+ kHS28Horn = 1,
+ kHS28Clown = 2,
+ kHS28ExitOutsideClown = 3,
+ kHS28EmptyBucket = 4,
+ kHS28Device = 5,
+ kHS28WalkArea1 = 6,
+ kHS28WalkArea2 = 7
+};
+
+enum {
+ kHS29Platypus = 0,
+ kHS29Monkey = 1,
+ kHS29Device = 2,
+ kHS29ExitCircus = 3,
+ kHS29ExitOutsideClown = 4,
+ kHS29Arcade = 5,
+ kHS29WalkArea1 = 6
+};
+
+enum {
+ kAS20LeaveScene = 0,
+ kAS20TalkStonerGuyNoJoint = 2,
+ kAS20TalkStonerGuyHasJoint = 3,
+ kAS20GrabJoint = 4,
+ kAS20ActionDone = 5,
+ kAS20TalkGroceryStoreGuy = 6,
+ kAS20GrabGroceryStoreGuy = 9,
+ kAS20GrabGroceryStoreHat = 10,
+ kAS20SwitchGroceryStoreHat = 11,
+ kAS20SwitchGroceryStoreHatDone = 12,
+ kAS20GrabJointDone = 13
+};
+
+enum {
+ kAS21TalkOldLady = 0,
+ kAS21GrabBanana = 1,
+ kAS21GrabBananaDone = 2,
+ kAS21GrabOldLady = 3,
+ kAS21UseHatWithOldLady = 4,
+ kAS21UseHatWithOldLadyDone = 5,
+ kAS21LeaveScene = 6
+};
+
+enum {
+ kAS22LeaveScene = 0,
+ kAS22TalkCashier = 1
+};
+
+enum {
+ kAS23LookCereals = 0,
+ kAS23GrabCereals = 1,
+ kAS23GrabCerealsDone = 2,
+ kAS23LeaveScene = 3
+};
+
+enum {
+ kAS24LeaveScene = 0
+};
+
+enum {
+ kAS25TalkTicketVendor = 0,
+ kAS25EnterCircusWihoutTicket = 1,
+ kAS25ShowTicketToVendor = 2,
+ kAS25ShowTicketToVendorDone = 3,
+ kAS25EnterCircusWihoutTicketDone = 4,
+ kAS25LeaveScene = 5
+};
+
+enum {
+ kAS26LeaveScene = 0
+};
+
+enum {
+ kAS27TalkJanitor = 0,
+ kAS27GrabBucket = 1,
+ kAS27GrabBucketDone = 2,
+ kAS27ShowPictureToJanitor = 3,
+ kAS27TryEnterClownTent = 4,
+ kAS27TryEnterClownTentDone = 5,
+ kAS27EnterClownTent = 6,
+ kAS27LeaveScene = 7
+};
+
+enum {
+ kAS28UseBeerBucketWithClown = 0,
+ kAS28UsePillBucketWithClown = 1,
+ kAS28GrabHornFails = 2,
+ kAS28GrabEmptyBucket = 3,
+ kAS28GrabHornSuccess = 4,
+ kAS28GrabHornSuccessDone = 5,
+ kAS28GrabEmptyBucketDone = 6,
+ kAS28GrabHornFailsDone = 7,
+ kAS28TalkClown = 8,
+ kAS28GnapWaiting = 9,
+ kAS28LeaveScene = 10
+};
+
+enum {
+ kAS29UseBananaWithMonkey = 0,
+ kAS29LeaveScene = 2
+};
+
+class GnapEngine;
+class CutScene;
+
+class Scene20: public Scene {
+public:
+ Scene20(GnapEngine *vm);
+ virtual ~Scene20() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb();
+
+private:
+ int _currStonerGuySequenceId;
+ int _nextStonerGuySequenceId;
+ int _currGroceryStoreGuySequenceId;
+ int _nextGroceryStoreGuySequenceId;
+ int _stonerGuyCtr;
+ int _groceryStoreGuyCtr;
+ bool _stonerGuyShowingJoint;
+
+ void stopSounds();
+};
+
+class Scene21: public Scene {
+public:
+ Scene21(GnapEngine *vm);
+ virtual ~Scene21() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currOldLadySequenceId;
+ int _nextOldLadySequenceId;
+};
+
+class Scene22: public Scene {
+public:
+ Scene22(GnapEngine *vm);
+ virtual ~Scene22() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currCashierSequenceId;
+ int _nextCashierSequenceId;
+ bool _caughtBefore;
+ int _cashierCtr;
+};
+
+class Scene23: public Scene {
+public:
+ Scene23(GnapEngine *vm);
+ virtual ~Scene23() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currStoreClerkSequenceId;
+ int _nextStoreClerkSequenceId;
+};
+
+class Scene24: public Scene {
+public:
+ Scene24(GnapEngine *vm);
+ virtual ~Scene24() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currWomanSequenceId;
+ int _nextWomanSequenceId;
+ int _boySequenceId;
+ int _girlSequenceId;
+};
+
+class Scene25: public Scene {
+public:
+ Scene25(GnapEngine *vm);
+ virtual ~Scene25() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currTicketVendorSequenceId;
+ int _nextTicketVendorSequenceId;
+
+ void playAnims(int index);
+};
+
+class Scene26: public Scene {
+public:
+ Scene26(GnapEngine *vm);
+ virtual ~Scene26() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currKidSequenceId;
+ int _nextKidSequenceId;
+};
+
+class Scene27: public Scene {
+public:
+ Scene27(GnapEngine *vm);
+ virtual ~Scene27() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _nextJanitorSequenceId;
+ int _currJanitorSequenceId;
+};
+
+class Scene28: public Scene {
+public:
+ Scene28(GnapEngine *vm);
+ virtual ~Scene28() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currClownSequenceId;
+ int _nextClownSequenceId;
+ int _clownTalkCtr;
+};
+
+class Scene29: public Scene {
+public:
+ Scene29(GnapEngine *vm);
+ virtual ~Scene29() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currMonkeySequenceId;
+ int _nextMonkeySequenceId;
+ int _currManSequenceId;
+ int _nextManSequenceId;
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_GROUP1_H
diff --git a/engines/gnap/scenes/group3.cpp b/engines/gnap/scenes/group3.cpp
new file mode 100644
index 0000000000..98a4f6c454
--- /dev/null
+++ b/engines/gnap/scenes/group3.cpp
@@ -0,0 +1,1612 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/group3.h"
+
+namespace Gnap {
+
+Scene30::Scene30(GnapEngine *vm) : Scene(vm) {
+ _kidSequenceId = -1;
+}
+
+int Scene30::init() {
+ return _vm->isFlag(kGFUnk23) ? 0x10B : 0x10A;
+}
+
+void Scene30::updateHotspots() {
+ _vm->setHotspot(kHS30Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS30PillMachine, 598, 342, 658, 426, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 9, 7);
+ _vm->setHotspot(kHS30ExitCircus, 100, 590 - _vm->_deviceY1, 700, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS30WalkArea1, 0, 0, 800, 514);
+ _vm->setDeviceHotspot(kHS30Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 5;
+}
+
+void Scene30::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ bool hasTakenPill = false;
+
+ _vm->playSound(0x1093B, true);
+ _vm->startSoundTimerB(6);
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->isFlag(kGFUnk23))
+ gameSys.insertSequence(0x106, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (!_vm->isFlag(kGFUnk13))
+ gameSys.insertSequence(0x107, 1, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_timers[5] = _vm->getRandom(50) + 180;
+
+ gameSys.insertSequence(0x101, 40, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+
+ _kidSequenceId = 0x101;
+ gnap.initPos(7, 12, kDirBottomRight);
+ plat.initPos(6, 12, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(7, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS30Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS30Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS30PillMachine:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole && !_vm->isFlag(kGFUnk23)) {
+ _vm->_hotspots[kHS30WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS30PillMachine], 0, 0x107BC, 1);
+ _vm->_hotspots[kHS30WalkArea1]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = kAS30UsePillMachine;
+ hasTakenPill = true;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS30PillMachine], 8, 5);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.walkTo(Common::Point(9, 8), 0, 0x107BC, 1);
+ gnap._actionStatus = kAS30LookPillMachine;
+ break;
+ case GRAB_CURSOR:
+ gnap.playScratchingHead(Common::Point(8, 5));
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible(Common::Point(8, 5));
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS30ExitCircus:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ if (hasTakenPill)
+ _vm->_newSceneNum = 47;
+ else
+ _vm->_newSceneNum = 26;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS30ExitCircus].y), 0, 0x107AE, 1);
+ gnap._actionStatus = kAS30LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS30ExitCircus] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS30WalkArea1:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1093B))
+ _vm->playSound(0x1093B, true);
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+ if (gnap._actionStatus < 0) {
+ if (_vm->getRandom(5) == 1) {
+ gameSys.insertSequence(0xFF, 40, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x100, 40, _kidSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _kidSequenceId = 0x100;
+ } else {
+ gameSys.insertSequence(0xFE, 40, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ }
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(50) + 180;
+ if (gnap._actionStatus < 0) {
+ if (!_vm->isFlag(kGFUnk23) || hasTakenPill)
+ gameSys.insertSequence(0x109, 20, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x108, 20, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ }
+ _vm->playSoundB();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene30::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS30LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS30UsePillMachine:
+ _vm->setGrabCursorSprite(-1);
+ gameSys.setAnimation(0x105, gnap._id, 0);
+ gameSys.insertSequence(0x105, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x105;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS30UsePillMachine2;
+ break;
+ case kAS30UsePillMachine2:
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+ _vm->addFullScreenSprite(0x3F, 255);
+ gameSys.removeSequence(0x105, gnap._id, true);
+ gameSys.setAnimation(0x102, 256, 0);
+ gameSys.insertSequence(0x102, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ gameSys.setAnimation(0x103, gnap._id, 0);
+ gameSys.insertSequence(0x103, gnap._id, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->removeFullScreenSprite();
+ _vm->showCursor();
+ gnap._actionStatus = kAS30UsePillMachine3;
+ _vm->invAdd(kItemPill);
+ _vm->setFlag(kGFUnk23);
+ break;
+ case kAS30UsePillMachine3:
+ gameSys.setAnimation(0x104, gnap._id, 0);
+ gameSys.insertSequence(0x104, gnap._id, makeRid(gnap._sequenceDatNum, 0x103), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x104;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS30UsePillMachine4;
+ _vm->setGrabCursorSprite(kItemDiceQuarterHole);
+ break;
+ case kAS30UsePillMachine4:
+ gameSys.insertSequence(0x106, 1, 0, 0, kSeqNone, 0, 0, 0);
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS30PillMachine] + Common::Point(0, 1), -1, 0x107BC, 1);
+ gnap._actionStatus = -1;
+ break;
+ case kAS30LookPillMachine:
+ if (_vm->isFlag(kGFUnk23))
+ _vm->showFullScreenSprite(0xE3);
+ else
+ _vm->showFullScreenSprite(0xE2);
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene31::Scene31(GnapEngine *vm) : Scene(vm) {
+ _beerGuyDistracted = false;
+ _currClerkSequenceId = -1;
+ _nextClerkSequenceId = -1;
+ _clerkMeasureCtr = -1;
+ _clerkMeasureMaxCtr = 3;
+}
+
+int Scene31::init() {
+ return 0x105;
+}
+
+void Scene31::updateHotspots() {
+ _vm->setHotspot(kHS31Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS31MeasuringClown, 34, 150, 256, 436, SF_WALKABLE | SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 0, 6);
+ _vm->setHotspot(kHS31BeerBarrel, 452, 182, 560, 306, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 7);
+ _vm->setHotspot(kHS31ExitCircus, 150, 585, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS31ExitOutsideClown, 0, 0, 15, 600, SF_EXIT_L_CURSOR | SF_WALKABLE, 0, 8);
+ _vm->setHotspot(kHS31WalkArea1, 0, 0, 800, 480);
+ _vm->setDeviceHotspot(kHS31Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 7;
+}
+
+void Scene31::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1093B, true);
+ _vm->startSoundTimerB(6);
+ _vm->queueInsertDeviceIcon();
+
+ _beerGuyDistracted = false;
+ gameSys.insertSequence(0xFB, 39, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currClerkSequenceId = 0xFB;
+ _nextClerkSequenceId = -1;
+
+ gameSys.setAnimation(0xFB, 39, 3);
+
+ _vm->_timers[4] = _vm->getRandom(20) + 60;
+ _vm->_timers[5] = _vm->getRandom(50) + 180;
+
+ if (_vm->_prevSceneNum == 27) {
+ gnap.initPos(-1, 8, kDirBottomLeft);
+ plat.initPos(-1, 9, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(3, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(3, 9), -1, 0x107D2, 1);
+ } else {
+ gnap.initPos(7, 12, kDirBottomRight);
+ plat.initPos(6, 12, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(7, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(6, 8), -1, 0x107D2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS31Device:
+ if (gnap._actionStatus < 0 || gnap._actionStatus == kAS31PlatMeasuringClown) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS31Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS31MeasuringClown:
+ if (gnap._actionStatus < 0 || gnap._actionStatus == kAS31PlatMeasuringClown) {
+ if (gnap._actionStatus == kAS31PlatMeasuringClown) {
+ if (_vm->_verbCursor == LOOK_CURSOR)
+ gnap.playScratchingHead(Common::Point(2, 2));
+ else
+ gnap.playImpossible();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS31MeasuringClown] + Common::Point(0, 1), 2, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(2, 2));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS31MeasuringClown] + Common::Point(0, 1), -1, -1, 1);
+ _vm->_hotspots[kHS31WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS31MeasuringClown], 0, 0x107B9, 1);
+ _vm->_hotspots[kHS31WalkArea1]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = kAS31UseMeasuringClown;
+ _vm->_timers[4] = 300;
+ break;
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ case PLAT_CURSOR:
+ if (!_vm->invHas(kItemBucketWithBeer)) {
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS31MeasuringClown] + Common::Point(0, 1), 1, 0x107C2, 1);
+ _vm->_hotspots[kHS31WalkArea1]._flags |= SF_WALKABLE;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS31MeasuringClown], 1, 0x107C2, 1);
+ _vm->_hotspots[kHS31WalkArea1]._flags &= ~SF_WALKABLE;
+ plat._actionStatus = kAS31PlatMeasuringClown;
+ gnap._actionStatus = kAS31PlatMeasuringClown;
+ _vm->_timers[4] = 300;
+ } else
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS31BeerBarrel:
+ if (gnap._actionStatus < 0 || gnap._actionStatus == kAS31PlatMeasuringClown) {
+ if (_vm->_grabCursorSpriteIndex == kItemEmptyBucket && _beerGuyDistracted) {
+ _vm->setGrabCursorSprite(-1);
+ gnap.walkTo(gnap._pos, -1, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[kHS31BeerBarrel]) | 0x10000, 1);
+ _clerkMeasureMaxCtr += 5;
+ gameSys.insertSequence(0xF8, 59, 0, 0, kSeqNone, 0, 0, 0);
+ gnap.playPullOutDevice(Common::Point(6, 8));
+ gnap.playUseDevice();
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS31BeerBarrel], 0, 0x107BC, 1);
+ gnap._actionStatus = kAS31FillEmptyBucketWithBeer;
+ _vm->_timers[4] = 300;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS31BeerBarrel], 6, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(6, 2));
+ break;
+ case GRAB_CURSOR:
+ if (_beerGuyDistracted) {
+ gnap.playScratchingHead(Common::Point(6, 2));
+ } else {
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS31BeerBarrel], 0, 0x107BC, 1);
+ gnap._actionStatus = kAS31UseBeerBarrel;
+ gnap._idleFacing = kDirUpLeft;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS31ExitCircus:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 26;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS31ExitCircus].y), 0, 0x107AE, 1);
+ gnap._actionStatus = kAS31LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS31ExitCircus] + Common::Point(1, 0), -1, -1, 1);
+ }
+ break;
+
+ case kHS31ExitOutsideClown:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 27;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS31ExitOutsideClown].y), 0, 0x107AF, 1);
+ gnap._actionStatus = kAS31LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS31ExitOutsideClown] + Common::Point(0, 1), -1, 0x107CF, 1);
+ }
+ break;
+
+ case kHS31WalkArea1:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1093B))
+ _vm->playSound(0x1093B, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0)
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(20) + 60;
+ if (gnap._actionStatus < 0 && _nextClerkSequenceId == -1) {
+ switch (_vm->getRandom(6)){
+ case 0:
+ _nextClerkSequenceId = 0xFF;
+ break;
+ case 1:
+ _nextClerkSequenceId = 0x100;
+ break;
+ case 2:
+ _nextClerkSequenceId = 0x101;
+ break;
+ default:
+ _nextClerkSequenceId = 0xFB;
+ break;
+ }
+ }
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(50) + 180;
+ if (gnap._actionStatus < 0) {
+ if (_vm->getRandom(2) != 0)
+ gameSys.insertSequence(0x104, 20, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x103, 20, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ }
+ _vm->playSoundB();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene31::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS31UseBeerBarrel:
+ _nextClerkSequenceId = 0xFE;
+ break;
+ case kAS31FillEmptyBucketWithBeer:
+ gameSys.setAnimation(0x102, 59, 0);
+ gameSys.insertSequence(0x102, 59, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._pos = Common::Point(5, 7);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x102;
+ gnap._id = 59;
+ gnap._actionStatus = kAS31FillEmptyBucketWithBeerDone;
+ break;
+ case kAS31FillEmptyBucketWithBeerDone:
+ gnap._idleFacing = kDirBottomLeft;
+ gnap.playPullOutDevice();
+ gnap.playUseDevice();
+ gameSys.insertSequence(0xF9, 59, 0xF8, 59, kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = -1;
+ _vm->invAdd(kItemBucketWithBeer);
+ _vm->invRemove(kItemEmptyBucket);
+ _vm->setGrabCursorSprite(kItemBucketWithBeer);
+ break;
+ case kAS31UseMeasuringClown:
+ _nextClerkSequenceId = 0xFA;
+ _clerkMeasureMaxCtr = 1;
+ break;
+ case kAS31LeaveScene:
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ if (plat._actionStatus == kAS31PlatMeasuringClown) {
+ _vm->_sceneWaiting = true;
+ _beerGuyDistracted = true;
+ _nextClerkSequenceId = 0xFA;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ switch (_nextClerkSequenceId) {
+ case 0xFA:
+ gameSys.insertSequence(_nextClerkSequenceId, 39, _currClerkSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0xFC, 39, _nextClerkSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0xFC, 39, 3);
+ _currClerkSequenceId = 0xFC;
+ _nextClerkSequenceId = 0xFC;
+ _clerkMeasureCtr = 0;
+ break;
+ case 0xFC:
+ ++_clerkMeasureCtr;
+ if (_clerkMeasureCtr >= _clerkMeasureMaxCtr) {
+ if (gnap._actionStatus != 5)
+ plat._actionStatus = -1;
+ _vm->_timers[0] = 40;
+ gameSys.insertSequence(0xFD, 39, _currClerkSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ _currClerkSequenceId = 0xFD;
+ _nextClerkSequenceId = -1;
+ if (gnap._actionStatus != kAS31FillEmptyBucketWithBeerDone && gnap._actionStatus != kAS31FillEmptyBucketWithBeer)
+ gnap._actionStatus = -1;
+ _beerGuyDistracted = false;
+ _clerkMeasureMaxCtr = 3;
+ gameSys.setAnimation(0xFD, 39, 3);
+ _vm->_sceneWaiting = false;
+ } else {
+ gameSys.insertSequence(_nextClerkSequenceId, 39, _currClerkSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ _currClerkSequenceId = _nextClerkSequenceId;
+ _nextClerkSequenceId = 0xFC;
+ gameSys.setAnimation(0xFC, 39, 3);
+ }
+ break;
+ case 0xFE:
+ gameSys.insertSequence(_nextClerkSequenceId, 39, _currClerkSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextClerkSequenceId, 39, 3);
+ _currClerkSequenceId = _nextClerkSequenceId;
+ _nextClerkSequenceId = -1;
+ gnap._actionStatus = -1;
+ break;
+ default:
+ if (_nextClerkSequenceId != -1) {
+ gameSys.insertSequence(_nextClerkSequenceId, 39, _currClerkSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextClerkSequenceId, 39, 3);
+ _currClerkSequenceId = _nextClerkSequenceId;
+ _nextClerkSequenceId = -1;
+ }
+ break;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene32::Scene32(GnapEngine *vm) : Scene(vm) {}
+
+int Scene32::init() {
+ _vm->_gameSys->setAnimation(0, 0, 0);
+ return _vm->isFlag(kGFPlatypusTalkingToAssistant) ? 0xF : 0x10;
+}
+
+void Scene32::updateHotspots() {
+ _vm->setHotspot(kHS32Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS32ExitTruck, 780, 226, 800, 455, SF_EXIT_R_CURSOR | SF_WALKABLE, 10, 6);
+ _vm->setHotspot(kHS32WalkArea1, 0, 0, 162, 426);
+ _vm->setHotspot(kHS32WalkArea2, 162, 0, 237, 396);
+ _vm->setHotspot(kHS32WalkArea3, 237, 0, 319, 363);
+ _vm->setHotspot(kHS32WalkArea4, 520, 0, 800, 404);
+ _vm->setHotspot(kHS32WalkArea5, 300, 447, 800, 600);
+ _vm->setHotspot(kHS32WalkArea6, 678, 0, 800, 404);
+ _vm->setHotspot(kHS32WalkArea7, 0, 0, 520, 351);
+ _vm->setHotspot(kHS32WalkArea8, 0, 546, 300, 600);
+ _vm->setDeviceHotspot(kHS32Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 11;
+}
+
+void Scene32::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1091C, true);
+ _vm->startSoundTimerC(5);
+ _vm->queueInsertDeviceIcon();
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+
+ if (_vm->_prevSceneNum == 33) {
+ gnap.initPos(11, 6, kDirBottomLeft);
+ plat.initPos(12, 6, kDirIdleRight);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(9, 6), -1, 0x107D2, 1);
+ gnap.walkTo(Common::Point(8, 6), -1, 0x107BA, 1);
+ } else {
+ gnap.initPos(1, 6, kDirBottomRight);
+ plat.initPos(1, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS32Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS32Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS32ExitTruck:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->setGrabCursorSprite(-1);
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS32ExitTruck], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS32LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS32ExitTruck] + Common::Point(0, 1), -1, 0x107CD, 1);
+ _vm->_newSceneNum = 33;
+ }
+ break;
+
+ case kHS32WalkArea1:
+ case kHS32WalkArea2:
+ case kHS32WalkArea3:
+ case kHS32WalkArea4:
+ case kHS32WalkArea5:
+ case kHS32WalkArea6:
+ case kHS32WalkArea7:
+ case kHS32WalkArea8:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ }
+
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = 0;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1091C))
+ _vm->playSound(0x1091C, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0)
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+ if (_vm->getRandom(2) != 0)
+ gameSys.insertSequence(0x0E, 180, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x0D, 180, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ _vm->playSoundC();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene32::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ if (_vm->_gnap->_actionStatus == kAS32LeaveScene)
+ _vm->_sceneDone = true;
+ }
+}
+
+/*****************************************************************************/
+
+Scene33::Scene33(GnapEngine *vm) : Scene(vm) {
+ _currChickenSequenceId = -1;
+ _nextChickenSequenceId = -1;
+}
+
+int Scene33::init() {
+ return _vm->isFlag(kGFPlatypusTalkingToAssistant) ? 0x84 : 0x85;
+}
+
+void Scene33::updateHotspots() {
+ _vm->setHotspot(kHS33Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS33Chicken, 606, 455, 702, 568, SF_WALKABLE | SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 8);
+ _vm->setHotspot(kHS33ExitHouse, 480, 120, 556, 240, SF_EXIT_U_CURSOR, 7, 3);
+ _vm->setHotspot(kHS33ExitBarn, 610, 75, 800, 164, SF_EXIT_U_CURSOR, 10, 3);
+ _vm->setHotspot(kHS33ExitCreek, 780, 336, 800, 556, SF_EXIT_R_CURSOR | SF_WALKABLE, 10, 8);
+ _vm->setHotspot(kHS33ExitPigpen, 0, 300, 20, 600, SF_EXIT_L_CURSOR | SF_WALKABLE, 0, 8);
+ _vm->setHotspot(kHS33WalkArea1, 120, 0, 514, 458);
+ _vm->setHotspot(kHS33WalkArea2, 0, 0, 800, 452);
+ _vm->setDeviceHotspot(kHS33Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 9;
+}
+
+void Scene33::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1091C, true);
+ _vm->startSoundTimerC(6);
+ _vm->queueInsertDeviceIcon();
+
+ _currChickenSequenceId = 0x7E;
+ gameSys.setAnimation(0x7E, 179, 2);
+ gameSys.insertSequence(_currChickenSequenceId, 179, 0, 0, kSeqNone, 0, 0, 0);
+ _nextChickenSequenceId = -1;
+ _vm->_timers[5] = _vm->getRandom(20) + 30;
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+
+ switch (_vm->_prevSceneNum) {
+ case 34:
+ gnap.initPos(11, 7, kDirBottomLeft);
+ plat.initPos(12, 7, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 7), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 7), -1, 0x107D2, 1);
+ break;
+ case 37:
+ gnap.initPos(7, 7, kDirBottomRight);
+ plat.initPos(8, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ break;
+ case 32:
+ gnap.initPos(-1, 6, kDirBottomRight);
+ plat.initPos(-1, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(2, 7), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ break;
+ default:
+ gnap.initPos(3, 7, kDirBottomRight);
+ plat.initPos(2, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ break;
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+ _vm->testWalk(0, 0, 7, 6, 8, 6);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS33Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS33Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS33Chicken:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(7, 9), 9, 8);
+ } else {
+ switch (_vm->_verbCursor) {
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirBottomRight;
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[kHS33Chicken], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1))
+ gnap._actionStatus = kAS33UseChicken;
+ else
+ gnap._actionStatus = -1;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirBottomRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS33Chicken], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS33TalkChicken;
+ break;
+ case LOOK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS33ExitHouse:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap._actionStatus = kAS33LeaveScene;
+ _vm->_newSceneNum = 37;
+ if (gnap._pos.x > 6)
+ gnap.walkTo(gnap._pos, 0, 0x107AD, 1);
+ else
+ gnap.walkTo(Common::Point(6, 7), 0, 0x107B1, 1);
+ }
+ break;
+
+ case kHS33ExitBarn:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap._actionStatus = kAS33LeaveScene;
+ _vm->_newSceneNum = 35;
+ if (gnap._pos.x > 7)
+ gnap.walkTo(gnap._pos, 0, 0x107AD, 1);
+ else
+ gnap.walkTo(Common::Point(7, 7), 0, 0x107B1, 1);
+ }
+ break;
+
+ case kHS33ExitCreek:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS33ExitCreek], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS33LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS33ExitCreek], -1, 0x107CD, 1);
+ _vm->_newSceneNum = 34;
+ }
+ break;
+
+ case kHS33ExitPigpen:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS33ExitPigpen], 0, 0x107AF, 1);
+ gnap._actionStatus = kAS33LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS33ExitPigpen], -1, 0x107CF, 1);
+ _vm->_newSceneNum = 32;
+ }
+ break;
+
+ case kHS33WalkArea1:
+ case kHS33WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1091C))
+ _vm->playSound(0x1091C, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0)
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+ if (_vm->getRandom(2) != 0)
+ gameSys.insertSequence(0x83, 256, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x82, 256, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ if (!_vm->_timers[5] && _nextChickenSequenceId == -1 && gnap._actionStatus != kAS33TalkChicken && gnap._actionStatus != kAS33UseChicken) {
+ if (_vm->getRandom(6) != 0) {
+ _nextChickenSequenceId = 0x7E;
+ _vm->_timers[5] = _vm->getRandom(20) + 30;
+ } else {
+ _nextChickenSequenceId = 0x80;
+ _vm->_timers[5] = _vm->getRandom(20) + 50;
+ }
+ }
+ _vm->playSoundC();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene33::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ switch (gnap._actionStatus) {
+ case kAS33LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS33TalkChicken:
+ _nextChickenSequenceId = 0x7F;
+ break;
+ case kAS33UseChicken:
+ _nextChickenSequenceId = 0x81;
+ _vm->_timers[2] = 100;
+ break;
+ case kAS33UseChickenDone:
+ gameSys.insertSequence(0x107B5, gnap._id, 0x81, 179, kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = 0x7B5;
+ gnap._sequenceDatNum = 1;
+ _currChickenSequenceId = 0x7E;
+ gameSys.setAnimation(0x7E, 179, 2);
+ gameSys.insertSequence(_currChickenSequenceId, 179, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._actionStatus = -1;
+ _vm->_timers[5] = 30;
+ break;
+ default:
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ if (_nextChickenSequenceId == 0x81) {
+ gameSys.setAnimation(_nextChickenSequenceId, 179, 0);
+ gameSys.insertSequence(_nextChickenSequenceId, 179, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(_currChickenSequenceId, 179, true);
+ _nextChickenSequenceId = -1;
+ _currChickenSequenceId = -1;
+ gnap._actionStatus = kAS33UseChickenDone;
+ _vm->_timers[5] = 500;
+ } else if (_nextChickenSequenceId == 0x7F) {
+ gameSys.setAnimation(_nextChickenSequenceId, 179, 2);
+ gameSys.insertSequence(_nextChickenSequenceId, 179, _currChickenSequenceId, 179, kSeqSyncWait, 0, 0, 0);
+ _currChickenSequenceId = _nextChickenSequenceId;
+ _nextChickenSequenceId = -1;
+ gnap._actionStatus = -1;
+ } else if (_nextChickenSequenceId != -1) {
+ gameSys.setAnimation(_nextChickenSequenceId, 179, 2);
+ gameSys.insertSequence(_nextChickenSequenceId, 179, _currChickenSequenceId, 179, kSeqSyncWait, 0, 0, 0);
+ _currChickenSequenceId = _nextChickenSequenceId;
+ _nextChickenSequenceId = -1;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene38::Scene38(GnapEngine *vm) : Scene(vm) {
+}
+
+int Scene38::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ return 0xA5;
+}
+
+void Scene38::updateHotspots() {
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->setHotspot(kHS38Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS38ExitHouse, 150, 585, 650, 600, SF_EXIT_D_CURSOR, 0, 8);
+ _vm->setHotspot(kHS38ExitCave, 430, 440, 655, 470, SF_WALKABLE, 0, 8);
+ _vm->setHotspot(kHS38TrapDoorLid1, 525, 265, 640, 350, SF_DISABLED);
+ _vm->setHotspot(kHS38TrapDoorLid2, 555, 350, 670, 430, SF_DISABLED);
+ _vm->setHotspot(kHS38HuntingTrophy, 170, 85, 250, 190, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 0, 8);
+ _vm->setHotspot(kHS38WalkArea1, 330, 270, 640, 380, SF_DISABLED | SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 0, 8);
+ _vm->setHotspot(kHS38WalkArea2, 0, 0, 799, 396);
+ _vm->setHotspot(kHS38WalkArea3, 0, 585, 799, 599, SF_WALKABLE | SF_DISABLED);
+ _vm->setHotspot(kHS38WalkArea4, 0, 0, 97, 445);
+ _vm->setHotspot(kHS38WalkArea5, 770, 0, 799, 445);
+ _vm->setHotspot(kHS38WalkArea6, 393, 0, 698, 445, SF_WALKABLE | SF_DISABLED);
+ _vm->setDeviceHotspot(kHS38Device, -1, -1, -1, -1);
+ if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor)
+ _vm->_hotspots[kHS38Platypus]._flags = SF_WALKABLE | SF_DISABLED;
+ if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor)
+ _vm->_hotspots[kHS38ExitCave]._flags = SF_EXIT_D_CURSOR;
+ else if (gnap._actionStatus == kAS38HoldingHuntingTrophy)
+ _vm->_hotspots[kHS38ExitCave]._flags = SF_EXIT_D_CURSOR;
+ if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor)
+ _vm->_hotspots[kHS38TrapDoorLid1]._flags = SF_DISABLED;
+ else if (gnap._actionStatus == kAS38HoldingHuntingTrophy)
+ _vm->_hotspots[kHS38TrapDoorLid1]._flags = SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor)
+ _vm->_hotspots[kHS38TrapDoorLid2]._flags = SF_DISABLED;
+ else if (gnap._actionStatus == kAS38HoldingHuntingTrophy)
+ _vm->_hotspots[kHS38TrapDoorLid2]._flags = SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor)
+ _vm->_hotspots[kHS38WalkArea6]._flags = SF_NONE;
+ _vm->_hotspotsCount = 13;
+}
+
+void Scene38::run() {
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+ _vm->_gameSys->insertSequence(0x9B, 0, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->_prevSceneNum == 39) {
+ gnap.initPos(3, 7, kDirBottomLeft);
+ plat.initPos(4, 7, kDirIdleRight);
+ } else {
+ gnap.initPos(3, 8, kDirBottomRight);
+ plat.initPos(4, 8, kDirIdleLeft);
+ }
+ _vm->endSceneInit();
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS38Device:
+ _vm->runMenu();
+ updateHotspots();
+ break;
+
+ case kHS38Platypus:
+ if (gnap._actionStatus == kAS38HoldingHuntingTrophy) {
+ gnap._actionStatus = kAS38ReleaseHuntingTrophy;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ break;
+
+ case kHS38ExitHouse:
+ if (gnap._actionStatus == kAS38HoldingHuntingTrophy) {
+ gnap._actionStatus = kAS38ReleaseHuntingTrophy;
+ } else {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(-1, -1), 0, 0x107AE, 1);
+ gnap._actionStatus = kAS38LeaveScene;
+ _vm->_newSceneNum = 37;
+ }
+ break;
+
+ case kHS38ExitCave:
+ if (gnap._actionStatus == kAS38HoldingHuntingTrophy) {
+ gnap._actionStatus = kAS38ReleaseHuntingTrophy;
+ if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor)
+ _vm->_isLeavingScene = true;
+ } else if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor) {
+ _vm->_sceneWaiting = false;
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(5, 7), 0, 0x107BB, 1);
+ _vm->_newSceneNum = 39;
+ gnap._actionStatus = kAS38ExitCave;
+ }
+ break;
+
+ case kHS38TrapDoorLid1:
+ case kHS38TrapDoorLid2:
+ if (gnap._actionStatus == kAS38HoldingHuntingTrophy) {
+ if (_vm->_verbCursor == PLAT_CURSOR && plat._actionStatus != kAS38PlatypusHoldingTrapDoor)
+ gnap._actionStatus = kAS38UsePlatypusWithTrapDoor;
+ else
+ gnap._actionStatus = kAS38ReleaseHuntingTrophy;
+ }
+ break;
+
+ case kHS38HuntingTrophy:
+ if (gnap._actionStatus != kAS38HoldingHuntingTrophy) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(3, 6), 2, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead();
+ break;
+ case GRAB_CURSOR:
+ if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor)
+ gnap.playImpossible();
+ else {
+ gnap.walkTo(Common::Point(3, 6), 0, 0x107BB, 1);
+ plat.walkTo(Common::Point(4, 8), -1, -1, 1);
+ gnap._actionStatus = kAS38UseHuntingTrophy;
+ }
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(Common::Point(2, 0));
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS38WalkArea1:
+ // Nothing
+ break;
+
+ case kHS38WalkArea2:
+ case kHS38WalkArea3:
+ case kHS38WalkArea4:
+ case kHS38WalkArea5:
+ case kHS38WalkArea6:
+ if (gnap._actionStatus == kAS38HoldingHuntingTrophy)
+ gnap._actionStatus = kAS38ReleaseHuntingTrophy;
+ else if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ if (gnap._actionStatus == kAS38HoldingHuntingTrophy)
+ gnap._actionStatus = kAS38ReleaseHuntingTrophy;
+ else if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene38::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS38LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS38ExitCave:
+ gameSys.removeSequence(plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, true);
+ gameSys.insertSequence(0xA3, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0xA3;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0xA3, gnap._id, 0);
+ gnap._actionStatus = kAS38LeaveScene;
+ break;
+ case kAS38UseHuntingTrophy:
+ gameSys.removeSequence(0x9B, 0, true);
+ gameSys.insertSequence(0x9C, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x9C;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0x9C, gnap._id, 0);
+ gnap._actionStatus = kAS38HoldingHuntingTrophy;
+ updateHotspots();
+ break;
+ case kAS38HoldingHuntingTrophy:
+ if (plat._actionStatus != kAS38PlatypusHoldingTrapDoor)
+ _vm->_sceneWaiting = true;
+ if (gnap._sequenceId == 0xA4) {
+ gameSys.insertSequence(0x9D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x9D;
+ } else {
+ gameSys.insertSequence(0xA4, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0xA4;
+ }
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(gnap._sequenceId, gnap._id, 0);
+ break;
+ case kAS38ReleaseHuntingTrophy:
+ if (gnap._sequenceId == 0x9E) {
+ gameSys.insertSequence(0x9B, 0, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._actionStatus = -1;
+ } else if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor) {
+ gameSys.insertSequence(0xA0, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0xA0;
+ gnap._sequenceDatNum = 0;
+ gnap._pos = Common::Point(3, 6);
+ gnap._idleFacing = kDirBottomRight;
+ if (_vm->_isLeavingScene) {
+ _vm->_sceneWaiting = false;
+ gnap.walkTo(Common::Point(5, 7), 0, 0x107BB, 1);
+ _vm->_newSceneNum = 39;
+ gnap._actionStatus = kAS38ExitCave;
+ } else {
+ gnap._actionStatus = -1;
+ }
+ } else {
+ gameSys.insertSequence(0x9E, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x9E;
+ gnap._sequenceDatNum = 0;
+ gnap._pos = Common::Point(3, 6);
+ gnap._idleFacing = kDirBottomRight;
+ gameSys.setAnimation(0x9E, gnap._id, 0);
+ _vm->_sceneWaiting = false;
+ updateHotspots();
+ }
+ break;
+ case kAS38UsePlatypusWithTrapDoor:
+ _vm->_sceneWaiting = false;
+ gameSys.insertSequence(0x9F, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x9F;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0x9F, gnap._id, 0);
+ gnap._actionStatus = kAS38HoldingHuntingTrophy;
+ if (plat._idleFacing != kDirIdleLeft)
+ plat.playSequence(0x107D5);
+ else
+ plat.playSequence(0x107D4);
+ plat.walkTo(Common::Point(8, 7), -1, 0x107D2, 1);
+ gameSys.insertSequence(0xA1, gnap._id + 1, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceId = 0xA1;
+ plat._sequenceDatNum = 0;
+ plat._id = gnap._id + 1;
+ gameSys.setAnimation(0xA1, gnap._id + 1, 1);
+ plat._actionStatus = kAS38PlatypusHoldingTrapDoor;
+ updateHotspots();
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor) {
+ gameSys.insertSequence(0xA2, plat._id, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceId = 0xA2;
+ plat._sequenceDatNum = 0;
+ updateHotspots();
+ _vm->_sceneWaiting = true;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene39::Scene39(GnapEngine *vm) : Scene(vm) {
+ _currGuySequenceId = -1;
+ _nextGuySequenceId = -1;
+}
+
+int Scene39::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ return 0x35;
+}
+
+void Scene39::updateHotspots() {
+ _vm->setHotspot(kHS39Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS39ExitInsideHouse, 0, 0, 140, 206, SF_EXIT_U_CURSOR, 4, 8);
+ _vm->setHotspot(kHS39ExitUfoParty, 360, 204, 480, 430, SF_EXIT_R_CURSOR, 6, 8);
+ _vm->setHotspot(kHS39Sign, 528, 232, 607, 397, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 3);
+ _vm->setHotspot(kHS39WalkArea1, 0, 0, 800, 466);
+ _vm->setHotspot(kHS39WalkArea2, 502, 466, 800, 600);
+ _vm->setDeviceHotspot(kHS39Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 7;
+}
+
+void Scene39::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ // Bug in the original? Timer was never initialized.
+ _vm->_timers[5] = 0;
+
+ _vm->queueInsertDeviceIcon();
+ _currGuySequenceId = 0x33;
+
+ gameSys.setAnimation(0x33, 21, 3);
+ gameSys.insertSequence(_currGuySequenceId, 21, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x34, 21, 0, 0, kSeqLoop, 0, 0, 0);
+
+ _nextGuySequenceId = -1;
+ if (_vm->_prevSceneNum == 38) {
+ gnap.initPos(3, 7, kDirUpRight);
+ plat.initPos(2, 7, kDirUpLeft);
+ _vm->endSceneInit();
+ } else {
+ gnap.initPos(4, 7, kDirBottomRight);
+ plat.initPos(5, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ }
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1094B)) {
+ _vm->playSound(0x1094B, true);
+ _vm->setSoundVolume(0x1094B, 60);
+ }
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS39Device:
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[5] = _vm->getRandom(20) + 50;
+ break;
+
+ case kHS39Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS39ExitUfoParty:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_sceneDone = true;
+ gnap.walkTo(gnap._pos, 0, 0x107AB, 1);
+ gnap._actionStatus = kAS39LeaveScene;
+ _vm->_newSceneNum = 40;
+ }
+ break;
+
+ case kHS39Sign:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS39Sign], 0, -1, 1);
+ gnap.playIdle(_vm->_hotspotsWalkPos[kHS39Sign]);
+ _vm->showFullScreenSprite(0x1C);
+ break;
+ case GRAB_CURSOR:
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS39ExitInsideHouse:
+ if (gnap._actionStatus < 0) {
+ _vm->_sceneDone = true;
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 38;
+ }
+ break;
+
+ case kHS39WalkArea1:
+ case kHS39WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0)
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(20) + 50;
+ switch (_vm->getRandom(4)) {
+ case 0:
+ _nextGuySequenceId = 0x30;
+ break;
+ case 1:
+ _nextGuySequenceId = 0x31;
+ break;
+ case 2:
+ _nextGuySequenceId = 0x32;
+ break;
+ case 3:
+ _nextGuySequenceId = 0x33;
+ break;
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[5] = _vm->getRandom(20) + 50;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene39::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ if (gnap._actionStatus == kAS39LeaveScene)
+ _vm->_sceneDone = true;
+ else
+ gnap._actionStatus = -1;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2 && _nextGuySequenceId != -1) {
+ gameSys.setAnimation(_nextGuySequenceId, 21, 3);
+ gameSys.insertSequence(_nextGuySequenceId, 21, _currGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ _currGuySequenceId = _nextGuySequenceId;
+ _nextGuySequenceId = -1;
+ }
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/group3.h b/engines/gnap/scenes/group3.h
new file mode 100644
index 0000000000..6fbbdd79aa
--- /dev/null
+++ b/engines/gnap/scenes/group3.h
@@ -0,0 +1,240 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 GNAP_GROUP3_H
+#define GNAP_GROUP3_H
+
+#include "gnap/debugger.h"
+
+namespace Gnap {
+
+enum {
+ kHS30Platypus = 0,
+ kHS30PillMachine = 1,
+ kHS30Device = 2,
+ kHS30ExitCircus = 3,
+ kHS30WalkArea1 = 4
+};
+
+enum {
+ kHS31Platypus = 0,
+ kHS31MeasuringClown = 1,
+ kHS31BeerBarrel = 2,
+ kHS31Device = 3,
+ kHS31ExitCircus = 4,
+ kHS31ExitOutsideClown = 5,
+ kHS31WalkArea1 = 6
+};
+
+enum {
+ kHS32Platypus = 0,
+ kHS32ExitTruck = 1,
+ kHS32Device = 2,
+ kHS32WalkArea1 = 3,
+ kHS32WalkArea2 = 4,
+ kHS32WalkArea3 = 5,
+ kHS32WalkArea4 = 6,
+ kHS32WalkArea5 = 7,
+ kHS32WalkArea6 = 8,
+ kHS32WalkArea7 = 9,
+ kHS32WalkArea8 = 10
+};
+
+enum {
+ kHS33Platypus = 0,
+ kHS33Chicken = 1,
+ kHS33Device = 2,
+ kHS33ExitHouse = 3,
+ kHS33ExitBarn = 4,
+ kHS33ExitCreek = 5,
+ kHS33ExitPigpen = 6,
+ kHS33WalkArea1 = 7,
+ kHS33WalkArea2 = 8
+};
+
+enum {
+ kHS38Platypus = 0,
+ kHS38ExitHouse = 1,
+ kHS38ExitCave = 2,
+ kHS38TrapDoorLid1 = 3,
+ kHS38TrapDoorLid2 = 4,
+ kHS38HuntingTrophy = 5,
+ kHS38WalkArea1 = 6,
+ kHS38Device = 7,
+ kHS38WalkArea2 = 8,
+ kHS38WalkArea3 = 9,
+ kHS38WalkArea4 = 10,
+ kHS38WalkArea5 = 11,
+ kHS38WalkArea6 = 12
+};
+
+enum {
+ kHS39Platypus = 0,
+ kHS39ExitInsideHouse = 1,
+ kHS39ExitUfoParty = 2,
+ kHS39Sign = 3,
+ kHS39Device = 4,
+ kHS39WalkArea1 = 5,
+ kHS39WalkArea2 = 6
+};
+
+enum {
+ kAS30LeaveScene = 0,
+ kAS30UsePillMachine = 1,
+ kAS30UsePillMachine2 = 2,
+ kAS30LookPillMachine = 3,
+ kAS30UsePillMachine3 = 4,
+ kAS30UsePillMachine4 = 5
+};
+
+enum {
+ kAS31UseBeerBarrel = 1,
+ kAS31FillEmptyBucketWithBeer = 2,
+ kAS31FillEmptyBucketWithBeerDone = 3,
+ kAS31PlatMeasuringClown = 4,
+ kAS31UseMeasuringClown = 5,
+ kAS31LeaveScene = 6
+};
+
+enum {
+ kAS32LeaveScene = 0
+};
+
+enum {
+ kAS33LeaveScene = 0,
+ kAS33TalkChicken = 1,
+ kAS33UseChicken = 2,
+ kAS33UseChickenDone = 3
+};
+
+enum {
+ kAS38LeaveScene = 0,
+ kAS38ExitCave = 1,
+ kAS38UseHuntingTrophy = 2,
+ kAS38HoldingHuntingTrophy = 3,
+ kAS38ReleaseHuntingTrophy = 4,
+ kAS38UsePlatypusWithTrapDoor = 5,
+ kAS38PlatypusHoldingTrapDoor = 6
+};
+
+enum {
+ kAS39LeaveScene = 0
+};
+
+/*****************************************************************************/
+
+class GnapEngine;
+class CutScene;
+
+class Scene30: public Scene {
+public:
+ Scene30(GnapEngine *vm);
+ virtual ~Scene30() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _kidSequenceId;
+};
+
+class Scene31: public Scene {
+public:
+ Scene31(GnapEngine *vm);
+ virtual ~Scene31() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ bool _beerGuyDistracted;
+ int _currClerkSequenceId;
+ int _nextClerkSequenceId;
+ int _clerkMeasureCtr;
+ int _clerkMeasureMaxCtr;
+};
+
+class Scene32: public Scene {
+public:
+ Scene32(GnapEngine *vm);
+ virtual ~Scene32() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+};
+
+class Scene33: public Scene {
+public:
+ Scene33(GnapEngine *vm);
+ virtual ~Scene33() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currChickenSequenceId;
+ int _nextChickenSequenceId;
+};
+
+class Scene38: public Scene {
+public:
+ Scene38(GnapEngine *vm);
+ virtual ~Scene38() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+};
+
+class Scene39: public Scene {
+public:
+ Scene39(GnapEngine *vm);
+ virtual ~Scene39() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currGuySequenceId;
+ int _nextGuySequenceId;
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_GROUP3_H
diff --git a/engines/gnap/scenes/group4.cpp b/engines/gnap/scenes/group4.cpp
new file mode 100644
index 0000000000..f37be2c25d
--- /dev/null
+++ b/engines/gnap/scenes/group4.cpp
@@ -0,0 +1,2799 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/group4.h"
+
+namespace Gnap {
+
+Scene40::Scene40(GnapEngine *vm) : Scene(vm) {
+}
+
+int Scene40::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ return _vm->isFlag(kGFUnk23) ? 0x01 : 0x00;
+}
+
+void Scene40::updateHotspots() {
+ _vm->setHotspot(kHS40Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_DISABLED | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS40ExitCave, 169, 510, 264, 600, SF_EXIT_D_CURSOR, 0, 8);
+ _vm->setHotspot(kHS40ExitToyStand, 238, 297, 328, 376, SF_EXIT_L_CURSOR, 0, 8);
+ _vm->setHotspot(kHS40ExitBBQ, 328, 220, 401, 306, SF_EXIT_L_CURSOR, 0, 8);
+ _vm->setHotspot(kHS40ExitUfo, 421, 215, 501, 282, SF_EXIT_U_CURSOR, 0, 8);
+ _vm->setHotspot(kHS40ExitKissinBooth, 476, 284, 556, 345, SF_EXIT_R_CURSOR, 0, 8);
+ _vm->setHotspot(kHS40ExitDancefloor, 317, 455, 445, 600, SF_EXIT_D_CURSOR, 0, 8);
+ _vm->setHotspot(kHS40ExitShoe, 455, 346, 549, 417, SF_EXIT_D_CURSOR, 0, 8);
+ _vm->setDeviceHotspot(kHS40Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 9;
+}
+
+void Scene40::run() {
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+ _vm->endSceneInit();
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1094B))
+ _vm->playSound(0x1094B, true);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS40Device:
+ _vm->runMenu();
+ updateHotspots();
+ break;
+
+ case kHS40Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS40ExitCave:
+ if (gnap._actionStatus < 0) {
+ _vm->_newSceneNum = 39;
+ _vm->_sceneDone = true;
+ }
+ break;
+
+ case kHS40ExitToyStand:
+ if (gnap._actionStatus < 0) {
+ _vm->_newSceneNum = 41;
+ _vm->_sceneDone = true;
+ }
+ break;
+
+ case kHS40ExitBBQ:
+ if (gnap._actionStatus < 0) {
+ _vm->_newSceneNum = 42;
+ _vm->_sceneDone = true;
+ }
+ break;
+
+ case kHS40ExitUfo:
+ if (gnap._actionStatus < 0) {
+ _vm->_newSceneNum = 43;
+ _vm->_sceneDone = true;
+ }
+ break;
+
+ case kHS40ExitKissinBooth:
+ if (gnap._actionStatus < 0) {
+ _vm->_newSceneNum = 44;
+ _vm->_sceneDone = true;
+ }
+ break;
+
+ case kHS40ExitDancefloor:
+ if (gnap._actionStatus < 0) {
+ _vm->_newSceneNum = 45;
+ _vm->_sceneDone = true;
+ }
+ break;
+
+ case kHS40ExitShoe:
+ if (gnap._actionStatus < 0) {
+ _vm->_newSceneNum = 46;
+ _vm->_sceneDone = true;
+ }
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0)
+ _vm->_mouseClickState._left = false;
+ break;
+
+ }
+
+ updateAnimations();
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene40::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ if (gnap._actionStatus)
+ gnap._actionStatus = -1;
+ else
+ _vm->_sceneDone = true;
+ }
+}
+
+/*****************************************************************************/
+
+Scene41::Scene41(GnapEngine *vm) : Scene(vm) {
+ _currKidSequenceId = -1;
+ _nextKidSequenceId = -1;
+ _currToyVendorSequenceId = -1;
+ _nextToyVendorSequenceId = -1;
+}
+
+int Scene41::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ return 0x129;
+}
+
+void Scene41::updateHotspots() {
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->setHotspot(kHS41Platypus, 0, 0, 0, 0, SF_DISABLED);
+ _vm->setHotspot(kHS41UfoExitLeft, 0, 0, 10, 500, SF_EXIT_L_CURSOR | SF_DISABLED);
+ _vm->setHotspot(kHS41UfoExitRight, 790, 0, 799, 500, SF_EXIT_R_CURSOR);
+ _vm->setHotspot(kHS41UfoWalkArea1, 0, 0, 800, 470, SF_DISABLED);
+ _vm->setDeviceHotspot(kHS41UfoDevice, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 5;
+ } else {
+ _vm->setHotspot(kHS41Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS41ExitCave, 150, 590, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS41Exit, 0, 100, 10, 599, SF_EXIT_L_CURSOR | SF_DISABLED, 0, 8);
+ _vm->setHotspot(kHS41ExitBBQ, 790, 100, 799, 599, SF_EXIT_R_CURSOR | SF_WALKABLE, 10, 8);
+ _vm->setHotspot(kHS41ToyVendor, 320, 150, 430, 310, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS41Kid, 615, 340, 710, 460, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS41ToyUfo, 0, 0, 0, 0, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS41WalkArea1, 0, 0, 800, 470);
+ _vm->setDeviceHotspot(kHS41Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 9;
+ }
+}
+
+void Scene41::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoX = 770;
+ if (_vm->_toyUfoY < 0 || _vm->_toyUfoY > 300)
+ _vm->_toyUfoY = 150;
+ if (!_vm->_timers[9])
+ gnap._actionStatus = kAS41GiveBackToyUfo;
+ } else {
+ if (!_vm->isFlag(kGFUnk16) && !_vm->isFlag(kGFJointTaken) && !_vm->isFlag(kGFUnk18) && !_vm->isFlag(kGFGroceryStoreHatTaken))
+ _vm->toyUfoSetStatus(kGFUnk16);
+ _vm->_toyUfoX = 600;
+ _vm->_toyUfoY = 200;
+ }
+
+ _vm->_toyUfoId = 0;
+ _vm->_toyUfoActionStatus = -1;
+ _vm->_toyUfoSequenceId = _vm->toyUfoGetSequenceId();
+ _vm->_toyUfoNextSequenceId = _vm->_toyUfoSequenceId;
+
+ gameSys.setAnimation(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 2);
+ gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ gameSys.insertSequence(0x128, 0, 0, 0, kSeqLoop, 0, 0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO))
+ _currKidSequenceId = 0x11B;
+ else
+ _currKidSequenceId = 0x11D;
+
+ _nextKidSequenceId = -1;
+
+ gameSys.setAnimation(_currKidSequenceId, 1, 4);
+ gameSys.insertSequence(_currKidSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currToyVendorSequenceId = 0x118;
+ _nextToyVendorSequenceId = -1;
+
+ gameSys.setAnimation(0x118, 1, 3);
+ gameSys.insertSequence(_currToyVendorSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x127, 2, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ gnap._sequenceId = 0x120;
+ gnap._sequenceDatNum = 0;
+ gnap._idleFacing = kDirUpRight;
+ gnap._pos = Common::Point(7, 7);
+ gnap._id = 140;
+ gameSys.insertSequence(0x120, 140, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0);
+ plat.initPos(8, 10, kDirBottomLeft);
+ _vm->endSceneInit();
+ } else if (_vm->_prevSceneNum == 45) {
+ gnap.initPos(-1, 8, kDirUpRight);
+ plat.initPos(-2, 8, kDirUpLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ } else if (_vm->_prevSceneNum == 42) {
+ gnap.initPos(11, 8, kDirUpRight);
+ plat.initPos(11, 9, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 8), -1, 0x107D2, 1);
+ } else {
+ gnap.initPos(5, 8, kDirBottomRight);
+ plat.initPos(6, 8, kDirBottomLeft);
+ _vm->endSceneInit();
+ }
+
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1094B))
+ _vm->playSound(0x1094B, true);
+
+ if (!_vm->isFlag(kGFGnapControlsToyUFO))
+ _vm->_hotspots[kHS41ToyUfo]._rect = Common::Rect(_vm->_toyUfoX - 25, _vm->_toyUfoY - 20, _vm->_toyUfoX + 25, _vm->_toyUfoY + 20);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS41UfoExitLeft:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = kAS41ToyUfoLeaveScene;
+ _vm->_newSceneNum = 45;
+ _vm->toyUfoFlyTo(-35, -1, -35, 799, 0, 300, 2);
+ }
+ break;
+
+ case kHS41UfoExitRight:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = kAS41ToyUfoLeaveScene;
+ _vm->_newSceneNum = 42;
+ _vm->toyUfoFlyTo(835, -1, 0, 835, 0, 300, 2);
+ }
+ break;
+
+ case kHS41UfoDevice:
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ break;
+ }
+ } else {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS41Device:
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ break;
+
+ case kHS41Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS41ExitCave:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS41ExitCave], 0, 0x107AE, 1);
+ gnap._actionStatus = kAS41LeaveScene;
+ _vm->_newSceneNum = 40;
+ break;
+
+ case kHS41Exit:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS41Exit].x, -1), 0, 0x107AF, 1);
+ gnap._actionStatus = kAS41LeaveScene;
+ plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS41Exit].x, -1), -1, 0x107CF, 1);
+ _vm->_newSceneNum = 45;
+ break;
+
+ case kHS41ExitBBQ:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS41ExitBBQ].x, -1), 0, 0x107AB, 1);
+ gnap._actionStatus = kAS41LeaveScene;
+ plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS41ExitBBQ].x, -1), -1, 0x107CD, 1);
+ _vm->_newSceneNum = 42;
+ break;
+
+ case kHS41ToyVendor:
+ if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole) {
+ gnap._actionStatus = kAS41UseQuarterWithToyVendor;
+ gnap.walkTo(Common::Point(4, 7), 0, 0x107BB, 9);
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 5, 0);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(4, 7), 5, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(Common::Point(5, 0));
+ break;
+ case GRAB_CURSOR:
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(Common::Point(4, 7), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS41TalkToyVendor;
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS41Kid:
+ if (_vm->_grabCursorSpriteIndex == kItemChickenBucket) {
+ gnap.walkTo(Common::Point(7, 7), 0, 0x107BB, 1);
+ gnap._idleFacing = kDirUpRight;
+ gnap._actionStatus = kAS41UseChickenBucketWithKid;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(7, 7), 8, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(9, 0));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(Common::Point(7, 7), 0, 0x107BB, 1);
+ gnap._idleFacing = kDirUpRight;
+ gnap._actionStatus = kAS41GrabKid;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(Common::Point(7, 7), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS41ToyUfo:
+ if (_vm->_grabCursorSpriteIndex == kItemGum) {
+ gnap.playPullOutDevice(Common::Point(9, 0));
+ gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0);
+ gnap._actionStatus = kAS41UseGumWithToyUfo;
+ }
+ break;
+
+ case kHS41WalkArea1:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+ }
+ }
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ if (!_vm->_timers[9] && gnap._actionStatus < 0) {
+ gnap._actionStatus = kAS41GiveBackToyUfo;
+ if (gnap._sequenceId == 0x121 || gnap._sequenceId == 0x122) {
+ gameSys.insertSequence(0x123, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x123;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0x123, gnap._id, 0);
+ }
+ }
+ }
+
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ _vm->_mouseClickState._left = false;
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ int sequenceId;
+ if (_vm->_leftClickMouseX >= 400) {
+ if (gnap._sequenceId == 0x11F || gnap._sequenceId == 0x120 || gnap._sequenceId == 0x123 || gnap._sequenceId == 0x126)
+ sequenceId = 0x120;
+ else if (_vm->_leftClickMouseX - _vm->_toyUfoX >= 400)
+ sequenceId = 0x126;
+ else
+ sequenceId = 0x123;
+ } else {
+ if (gnap._sequenceId == 0x121 || gnap._sequenceId == 0x125 || gnap._sequenceId == 0x122)
+ sequenceId = 0x122;
+ else if (_vm->_toyUfoX - _vm->_leftClickMouseX >= 400)
+ sequenceId = 0x125;
+ else
+ sequenceId = 0x121;
+ }
+ gameSys.insertSequence(sequenceId, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = sequenceId;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(sequenceId, gnap._id, 0);
+ _vm->_toyUfoActionStatus = kAS41ToyUfoRefresh;
+ _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 2);
+ } else {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ }
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0)
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _vm->_toyUfoActionStatus == -1 && _nextToyVendorSequenceId == -1) {
+ switch (_vm->getRandom(3)) {
+ case 0:
+ _nextToyVendorSequenceId = 0x113;
+ break;
+ case 1:
+ _nextToyVendorSequenceId = 0x117;
+ break;
+ case 2:
+ _nextToyVendorSequenceId = 0x119;
+ break;
+ }
+ if (_nextToyVendorSequenceId == _currToyVendorSequenceId)
+ _nextToyVendorSequenceId = -1;
+ }
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _vm->_toyUfoActionStatus == -1 && _nextKidSequenceId == -1) {
+ if (_vm->isFlag(kGFGnapControlsToyUFO))
+ _nextKidSequenceId = 0x11B;
+ else if (_vm->getRandom(3) != 0)
+ _nextKidSequenceId = 0x11D;
+ else
+ _nextKidSequenceId = 0x11E;
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ }
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene41::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ switch (gnap._actionStatus) {
+ case kAS41LeaveScene:
+ gameSys.setAnimation(0, 0, 0);
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ break;
+ case kAS41UseQuarterWithToyVendor:
+ gameSys.setAnimation(0, 0, 0);
+ _nextToyVendorSequenceId = 0x114;
+ gnap._actionStatus = -1;
+ break;
+ case kAS41TalkToyVendor:
+ gameSys.setAnimation(0, 0, 0);
+ _nextToyVendorSequenceId = 0x116;
+ gnap._actionStatus = -1;
+ break;
+ case kAS41UseGumWithToyUfo:
+ gameSys.setAnimation(0, 0, 0);
+ gnap.playUseDevice(Common::Point(9, 0));
+ gnap._actionStatus = -1;
+ _vm->setGrabCursorSprite(-1);
+ _vm->invRemove(kItemGum);
+ _vm->_toyUfoActionStatus = kAS41UfoGumAttached;
+ break;
+ case kAS41UseChickenBucketWithKid:
+ if (gameSys.getAnimationStatus(4) == 2) {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ _vm->setGrabCursorSprite(-1);
+ gameSys.insertSequence(0x11F, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x11F;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0x11F, gnap._id, 0);
+ _nextKidSequenceId = 0x11A;
+ gameSys.insertSequence(0x11A, 1, _currKidSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextKidSequenceId, 1, 4);
+ _currKidSequenceId = _nextKidSequenceId;
+ _nextKidSequenceId = 0x11B;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ gnap._actionStatus = -1;
+ _vm->setFlag(kGFGnapControlsToyUFO);
+ updateHotspots();
+ _vm->_timers[9] = 600;
+ }
+ break;
+ case kAS41GrabKid:
+ if (gameSys.getAnimationStatus(3) == 2 && gameSys.getAnimationStatus(4) == 2) {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ gameSys.insertSequence(0x110, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x110;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0x110, gnap._id, 0);
+ _nextToyVendorSequenceId = 0x111;
+ gameSys.insertSequence(0x111, 1, _currToyVendorSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextToyVendorSequenceId, 1, 3);
+ _currToyVendorSequenceId = _nextToyVendorSequenceId;
+ _nextToyVendorSequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ _nextKidSequenceId = 0x10F;
+ gameSys.insertSequence(0x10F, 1, _currKidSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextKidSequenceId, 1, 4);
+ _currKidSequenceId = _nextKidSequenceId;
+ _nextKidSequenceId = -1;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ gnap._actionStatus = -1;
+ }
+ break;
+ case kAS41GiveBackToyUfo:
+ if (gameSys.getAnimationStatus(3) == 2 && gameSys.getAnimationStatus(4) == 2) {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ gameSys.insertSequence(0x124, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x124;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0x124, gnap._id, 0);
+ _nextToyVendorSequenceId = 0x112;
+ gameSys.insertSequence(0x112, 1, _currToyVendorSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextToyVendorSequenceId, 1, 3);
+ _currToyVendorSequenceId = _nextToyVendorSequenceId;
+ _nextToyVendorSequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ _nextKidSequenceId = 0x11C;
+ gameSys.insertSequence(0x11C, 1, _currKidSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextKidSequenceId, 1, 4);
+ _currKidSequenceId = _nextKidSequenceId;
+ _nextKidSequenceId = -1;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ gnap._actionStatus = -1;
+ _vm->clearFlag(kGFGnapControlsToyUFO);
+ updateHotspots();
+ }
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ switch (_vm->_toyUfoActionStatus) {
+ case kAS41ToyUfoLeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS41UfoGumAttached:
+ _vm->_toyUfoNextSequenceId = 0x873;
+ gameSys.insertSequence(0x10873, _vm->_toyUfoId, _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId,
+ kSeqSyncWait, 0, _vm->_toyUfoX - 365, _vm->_toyUfoY - 128);
+ _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId;
+ gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId, 2);
+ _vm->toyUfoSetStatus(kGFJointTaken);
+ break;
+ default:
+ _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId();
+ gameSys.insertSequence(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId + 1, _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId,
+ kSeqSyncWait, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId;
+ ++_vm->_toyUfoId;
+ gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId, 2);
+ break;
+ }
+ _vm->_toyUfoActionStatus = -1;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2 && _nextToyVendorSequenceId != -1) {
+ gameSys.insertSequence(_nextToyVendorSequenceId, 1, _currToyVendorSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextToyVendorSequenceId, 1, 3);
+ _currToyVendorSequenceId = _nextToyVendorSequenceId;
+ _nextToyVendorSequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2 && _nextKidSequenceId != -1) {
+ gameSys.insertSequence(_nextKidSequenceId, 1, _currKidSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextKidSequenceId, 1, 4);
+ _currKidSequenceId = _nextKidSequenceId;
+ _nextKidSequenceId = -1;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ if (_currKidSequenceId == 0x11E) {
+ _vm->_toyUfoActionStatus = kAS41ToyUfoRefresh;
+ _vm->toyUfoFlyTo(_vm->getRandom(300) + 500, _vm->getRandom(225) + 75, 0, 799, 0, 300, 2);
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene42::Scene42(GnapEngine *vm) : Scene(vm) {
+ _currBBQVendorSequenceId = -1;
+ _nextBBQVendorSequenceId = -1;
+}
+
+int Scene42::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ if (_vm->isFlag(kGFPictureTaken) || (_vm->isFlag(kGFUnk18) && _vm->isFlag(kGFUnk23)))
+ return 0x153;
+ return 0x152;
+}
+
+void Scene42::updateHotspots() {
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->setHotspot(kHS42Platypus, 0, 0, 0, 0, SF_DISABLED);
+ _vm->setHotspot(kHS42UfoExitLeft, 0, 0, 10, 599, SF_EXIT_L_CURSOR);
+ _vm->setHotspot(kHS42UfoExitRight, 790, 0, 799, 599, SF_EXIT_R_CURSOR);
+ _vm->setHotspot(kHS42UfoHotSauce, 335, 110, 440, 175, SF_DISABLED);
+ _vm->setDeviceHotspot(kHS42UfoDevice, -1, 534, -1, 599);
+ if ((_vm->isFlag(kGFPictureTaken) || _vm->isFlag(kGFUnk18)) && _vm->isFlag(kGFUnk23) && !_vm->isFlag(kGFUnk24))
+ _vm->_hotspots[kHS42UfoHotSauce]._flags = SF_GRAB_CURSOR;
+ _vm->_hotspotsCount = 5;
+ } else {
+ _vm->setHotspot(kHS42Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS42ExitUfoParty, 150, 585, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS42ExitToyStand, 0, 100, 10, 599, SF_EXIT_L_CURSOR, 0, 8);
+ _vm->setHotspot(kHS42ExitUfo, 790, 100, 799, 599, SF_EXIT_R_CURSOR, 10, 8);
+ _vm->setHotspot(kHS42BBQVendor, 410, 200, 520, 365, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 8);
+ _vm->setHotspot(kHS42ChickenLeg, 530, 340, 620, 430, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 8, 7);
+ _vm->setHotspot(kHS42WalkArea1, 0, 0, 800, 445);
+ _vm->setHotspot(kHS42WalkArea2, 240, 0, 550, 495);
+ _vm->setDeviceHotspot(kHS42Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 9;
+ }
+}
+
+void Scene42::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+
+ _currBBQVendorSequenceId = 0x14A;
+ _nextBBQVendorSequenceId = -1;
+
+ gameSys.setAnimation(0x14A, 1, 2);
+ gameSys.insertSequence(_currBBQVendorSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoId = 0;
+ _vm->_toyUfoActionStatus = -1;
+ if (_vm->_prevSceneNum == 43 && _vm->isFlag(kGFUnk18)) {
+ _vm->_toyUfoSequenceId = 0x872;
+ _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId();
+ gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_toyUfoX = 317;
+ _vm->_toyUfoY = 61;
+ _vm->toyUfoSetStatus(kGFJointTaken);
+ _vm->setFlag(kGFPictureTaken);
+ _vm->_timers[9] = 600;
+ } else {
+ _vm->_toyUfoSequenceId = _vm->toyUfoGetSequenceId();
+ _vm->_toyUfoNextSequenceId = _vm->_toyUfoSequenceId;
+ if (_vm->_prevSceneNum == 41)
+ _vm->_toyUfoX = 30;
+ else
+ _vm->_toyUfoX = 770;
+ gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ }
+ gameSys.setAnimation(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 3);
+ _vm->endSceneInit();
+ if (_vm->_toyUfoSequenceId == 0x872)
+ _vm->setGrabCursorSprite(-1);
+ } else if (_vm->_prevSceneNum == 41) {
+ gnap.initPos(-1, 8, kDirUpRight);
+ plat.initPos(-1, 9, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1);
+ } else if (_vm->_prevSceneNum == 43) {
+ gnap.initPos(11, 8, kDirUpRight);
+ plat.initPos(11, 9, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 8), -1, 0x107D2, 1);
+ } else {
+ gnap.initPos(5, 11, kDirUpRight);
+ plat.initPos(6, 11, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1094B))
+ _vm->playSound(0x1094B, true);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS42UfoExitLeft:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = kAS42ToyUfoLeaveScene;
+ _vm->_newSceneNum = 41;
+ _vm->toyUfoFlyTo(-35, -1, -35, 799, 0, 300, 3);
+ }
+ break;
+
+ case kHS42UfoExitRight:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = kAS42ToyUfoLeaveScene;
+ _vm->_newSceneNum = 43;
+ _vm->toyUfoFlyTo(835, -1, 0, 835, 0, 300, 3);
+ }
+ break;
+
+ case kHS42UfoHotSauce:
+ if (_vm->isFlag(kGFJointTaken)) {
+ _vm->_toyUfoActionStatus = kAS42ToyUfoPickUpHotSauce;
+ _vm->toyUfoFlyTo(384, 77, 0, 799, 0, 300, 3);
+ _vm->_timers[9] = 600;
+ } else {
+ _vm->_toyUfoActionStatus = kAS42ToyUfoRefresh;
+ _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 3);
+ }
+ break;
+
+ case kHS42UfoDevice:
+ _vm->runMenu();
+ updateHotspots();
+ break;
+ }
+ } else {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS42Device:
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(20) + 30;
+ break;
+
+ case kHS42Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS42ExitUfoParty:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(gnap._pos.x, _vm->_hotspotsWalkPos[kHS42ExitUfoParty].y), 0, 0x107AE, 1);
+ gnap._actionStatus = kAS42LeaveScene;
+ plat.walkTo(Common::Point(plat._pos.x, _vm->_hotspotsWalkPos[kHS42ExitUfoParty].y), -1, 0x107C7, 1);
+ _vm->_newSceneNum = 40;
+ break;
+
+ case kHS42ExitToyStand:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS42ExitToyStand].x, gnap._pos.y), 0, 0x107AF, 1);
+ gnap._actionStatus = kAS42LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS42ExitToyStand], -1, 0x107CF, 1);
+ _vm->_newSceneNum = 41;
+ break;
+
+ case kHS42ExitUfo:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS42ExitUfo].x, gnap._pos.y), 0, 0x107AB, 1);
+ gnap._actionStatus = kAS42LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS42ExitUfo], -1, 0x107CD, 1);
+ _vm->_newSceneNum = 43;
+ break;
+
+ case kHS42BBQVendor:
+ if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS42BBQVendor], 0, 0x107BB, 1);
+ gnap._actionStatus = kAS42UseQuarterWithBBQVendor;
+ if (plat._pos.y < 9)
+ plat.walkTo(Common::Point(plat._pos.x, 9), -1, -1, 1);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS42BBQVendor], _vm->_hotspotsWalkPos[kHS42BBQVendor].x + 1, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(_vm->_hotspotsWalkPos[kHS42BBQVendor].x - 1, 0));
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS42BBQVendor], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS42TalkBBQVendor;
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS42ChickenLeg:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS42ChickenLeg], _vm->_hotspotsWalkPos[kHS42ChickenLeg].x - 1, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(_vm->_hotspotsWalkPos[kHS42ChickenLeg].x - 1, 0));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS42ChickenLeg], 0, 0x107BC, 1);
+ gnap._actionStatus = kAS42GrabChickenLeg;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS42WalkArea1:
+ case kHS42WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ }
+ }
+
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ _vm->_mouseClickState._left = false;
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoActionStatus = kAS42ToyUfoRefresh;
+ _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 3);
+ } else {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ }
+ }
+
+ updateAnimations();
+
+ _vm->toyUfoCheckTimer();
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(20) + 30;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextBBQVendorSequenceId == -1) {
+ switch (_vm->getRandom(8)) {
+ case 0:
+ _nextBBQVendorSequenceId = 0x14C;
+ break;
+ case 1:
+ case 2:
+ _nextBBQVendorSequenceId = 0x149;
+ break;
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ _nextBBQVendorSequenceId = 0x14D;
+ break;
+ case 7:
+ _nextBBQVendorSequenceId = 0x14A;
+ break;
+ }
+ if (_nextBBQVendorSequenceId == _currBBQVendorSequenceId && _nextBBQVendorSequenceId != 0x14D)
+ _nextBBQVendorSequenceId = -1;
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(20) + 30;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene42::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ switch (gnap._actionStatus) {
+ case kAS42LeaveScene:
+ gameSys.setAnimation(0, 0, 0);
+ gnap._actionStatus = -1;
+ _vm->_sceneDone = true;
+ break;
+ case kAS42TalkBBQVendor:
+ gameSys.setAnimation(0, 0, 0);
+ gnap._actionStatus = -1;
+ _nextBBQVendorSequenceId = 0x14B;
+ break;
+ case kAS42UseQuarterWithBBQVendor:
+ case kAS42GrabChickenLeg:
+ if (gameSys.getAnimationStatus(2) == 2) {
+ int sequenceId;
+ if (gnap._actionStatus == kAS42UseQuarterWithBBQVendor) {
+ _vm->invRemove(kItemDiceQuarterHole);
+ _vm->invAdd(kItemChickenBucket);
+ _vm->setGrabCursorSprite(-1);
+ sequenceId = 0x150;
+ _nextBBQVendorSequenceId = 0x148;
+ } else if (_vm->isFlag(kGFUnk27)) {
+ if (_vm->isFlag(kGFUnk28)) {
+ sequenceId = 0x7B7;
+ _nextBBQVendorSequenceId = 0x145;
+ } else {
+ _vm->setFlag(kGFUnk28);
+ sequenceId = 0x14F;
+ _nextBBQVendorSequenceId = 0x147;
+ }
+ } else {
+ _vm->setFlag(kGFUnk27);
+ sequenceId = 0x14E;
+ _nextBBQVendorSequenceId = 0x146;
+ }
+ if (sequenceId == 0x7B7) {
+ gameSys.insertSequence(0x107B7, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, _vm->getSequenceTotalDuration(_nextBBQVendorSequenceId),
+ 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceDatNum = 1;
+ } else {
+ gameSys.insertSequence(sequenceId, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ }
+ gnap._sequenceId = sequenceId;
+ gameSys.setAnimation(sequenceId | (gnap._sequenceDatNum << 16), gnap._id, 0);
+ if (gnap._actionStatus == kAS42UseQuarterWithBBQVendor)
+ gnap._actionStatus = kAS42UseQuarterWithBBQVendorDone;
+ else
+ gnap._actionStatus = -1;
+ gameSys.insertSequence(_nextBBQVendorSequenceId, 1, _currBBQVendorSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextBBQVendorSequenceId, 1, 2);
+ _currBBQVendorSequenceId = _nextBBQVendorSequenceId;
+ if (_nextBBQVendorSequenceId == 0x145)
+ _nextBBQVendorSequenceId = 0x14A;
+ else
+ _nextBBQVendorSequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(20) + 30;
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ }
+ break;
+ case kAS42UseQuarterWithBBQVendorDone:
+ gameSys.setAnimation(0, 0, 0);
+ _vm->setGrabCursorSprite(kItemChickenBucket);
+ gnap._actionStatus = -1;
+ break;
+ default:
+ gameSys.setAnimation(0, 0, 0);
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2 && _nextBBQVendorSequenceId != -1) {
+ gameSys.insertSequence(_nextBBQVendorSequenceId, 1, _currBBQVendorSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextBBQVendorSequenceId, 1, 2);
+ _currBBQVendorSequenceId = _nextBBQVendorSequenceId;
+ _nextBBQVendorSequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(20) + 30;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ switch (_vm->_toyUfoActionStatus) {
+ case kAS42ToyUfoLeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS42ToyUfoPickUpHotSauce:
+ gameSys.insertSequence(0x10870, _vm->_toyUfoId, _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, kSeqSyncWait, 0, 0, 0);
+ _vm->setFlag(kGFUnk24);
+ updateHotspots();
+ _vm->toyUfoSetStatus(kGFGroceryStoreHatTaken);
+ _vm->_toyUfoSequenceId = 0x870;
+ gameSys.setAnimation(0x10870, _vm->_toyUfoId, 3);
+ _vm->_toyUfoActionStatus = -1;
+ _vm->_toyUfoX = 0x181;
+ _vm->_toyUfoY = 53;
+ break;
+ default:
+ if (_vm->_toyUfoSequenceId == 0x872) {
+ _vm->hideCursor();
+ _vm->addFullScreenSprite(0x13E, 255);
+ gameSys.setAnimation(0x151, 256, 0);
+ gameSys.insertSequence(0x151, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->removeFullScreenSprite();
+ _vm->showCursor();
+ }
+ _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId();
+ gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, (_vm->_toyUfoId + 1) % 10, 3);
+ gameSys.insertSequence(_vm->_toyUfoNextSequenceId | 0x10000, (_vm->_toyUfoId + 1) % 10,
+ _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId,
+ kSeqSyncWait, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId;
+ _vm->_toyUfoId = (_vm->_toyUfoId + 1) % 10;
+ break;
+ }
+ _vm->_toyUfoActionStatus = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene43::Scene43(GnapEngine *vm) : Scene(vm) {
+ _currTwoHeadedGuySequenceId = -1;
+ _nextTwoHeadedGuySequenceId = -1;
+}
+
+int Scene43::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ return 0x13F;
+}
+
+void Scene43::updateHotspots() {
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->setHotspot(kHS43Platypus, 0, 0, 0, 0, SF_DISABLED);
+ _vm->setHotspot(kHS43UfoExitLeft, 0, 0, 10, 599, SF_EXIT_L_CURSOR);
+ _vm->setHotspot(kHS43UfoExitRight, 790, 0, 799, 599, SF_EXIT_R_CURSOR);
+ _vm->setHotspot(kHS43UfoKey, 140, 170, 185, 260, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS43UfoBucket, 475, 290, 545, 365, SF_DISABLED);
+ _vm->setDeviceHotspot(kHS43UfoDevice, -1, 534, -1, 599);
+ if (_vm->isFlag(kGFGroceryStoreHatTaken))
+ _vm->_hotspots[kHS43UfoBucket]._flags = SF_GRAB_CURSOR;
+ // NOTE Bug in the original. Key hotspot wasn't disabled.
+ if (_vm->isFlag(kGFUnk14))
+ _vm->_hotspots[kHS43UfoKey]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 6;
+ } else {
+ _vm->setHotspot(kHS43Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS43ExitUfoParty, 150, 580, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS43ExitBBQ, 0, 100, 10, 599, SF_EXIT_L_CURSOR, 0, 8);
+ _vm->setHotspot(kHS43ExitKissinBooth, 790, 100, 799, 599, SF_EXIT_R_CURSOR, 10, 8);
+ _vm->setHotspot(kHS43TwoHeadedGuy, 470, 240, 700, 470, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS43Key, 140, 170, 185, 260, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS43Ufo, 110, 0, 690, 350, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS43WalkArea1, 0, 0, 800, 445);
+ _vm->setHotspot(kHS43WalkArea2, 465, 0, 800, 493);
+ _vm->setDeviceHotspot(kHS43Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFUnk14))
+ _vm->_hotspots[kHS43Key]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 10;
+ }
+}
+
+void Scene43::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+
+ if (!_vm->isFlag(kGFUnk14))
+ gameSys.insertSequence(0x1086F, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currTwoHeadedGuySequenceId = 0x13C;
+ _nextTwoHeadedGuySequenceId = -1;
+
+ gameSys.setAnimation(0x13C, 1, 2);
+ gameSys.insertSequence(_currTwoHeadedGuySequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoId = 0;
+ _vm->_toyUfoActionStatus = -1;
+ _vm->_toyUfoSequenceId = _vm->toyUfoGetSequenceId();
+ _vm->_toyUfoNextSequenceId = _vm->_toyUfoSequenceId;
+ if (_vm->_prevSceneNum == 42)
+ _vm->_toyUfoX = 30;
+ else
+ _vm->_toyUfoX = 770;
+ gameSys.setAnimation(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 3);
+ gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->endSceneInit();
+ } else {
+ switch (_vm->_prevSceneNum) {
+ case 42:
+ gnap.initPos(-1, 8, kDirUpRight);
+ plat.initPos(-1, 9, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1);
+ break;
+ case 44:
+ gnap.initPos(11, 8, kDirUpRight);
+ plat.initPos(11, 9, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 8), -1, 0x107D2, 1);
+ break;
+ case 54:
+ gnap.initPos(4, 7, kDirBottomLeft);
+ plat.initPos(11, 8, kDirUpLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(9, 8), -1, 0x107D2, 1);
+ break;
+ default:
+ gnap.initPos(5, 11, kDirUpRight);
+ plat.initPos(6, 11, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+ break;
+ }
+ }
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1094B))
+ _vm->playSound(0x1094B, true);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS43UfoDevice:
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ break;
+
+ case kHS43UfoExitLeft:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = 4;
+ _vm->_newSceneNum = 42;
+ _vm->toyUfoFlyTo(-35, -1, -35, 799, 0, 300, 3);
+ }
+ break;
+
+ case kHS43UfoExitRight:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = 4;
+ _vm->_newSceneNum = 44;
+ _vm->toyUfoFlyTo(835, -1, 0, 835, 0, 300, 3);
+ }
+ break;
+
+ case kHS43UfoKey:
+ if (_vm->isFlag(kGFJointTaken)) {
+ _vm->_toyUfoActionStatus = 6;
+ _vm->toyUfoFlyTo(163, 145, 0, 799, 0, 300, 3);
+ } else {
+ _vm->_toyUfoActionStatus = 5;
+ _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 3);
+ }
+ break;
+
+ case kHS43UfoBucket:
+ _vm->_toyUfoActionStatus = 7;
+ _vm->toyUfoFlyTo(497, 143, 0, 799, 0, 300, 3);
+ _vm->_timers[9] = 600;
+ break;
+ }
+ } else {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS43Device:
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ break;
+
+ case kHS43Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS43ExitUfoParty:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS43ExitUfoParty], 0, 0x107AE, 1);
+ gnap._actionStatus = 0;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS43ExitUfoParty], -1, 0x107C7, 1);
+ _vm->_newSceneNum = 40;
+ break;
+
+ case kHS43ExitBBQ:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS43ExitBBQ].x, gnap._pos.y), 0, 0x107AF, 1);
+ gnap._actionStatus = 0;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS43ExitBBQ], -1, 0x107CF, 1);
+ _vm->_newSceneNum = 42;
+ break;
+
+ case kHS43ExitKissinBooth:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS43ExitKissinBooth].x, gnap._pos.y), 0, 0x107AB, 1);
+ gnap._actionStatus = 0;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS43ExitKissinBooth], -1, 0x107CD, 1);
+ _vm->_newSceneNum = 44;
+ break;
+
+ case kHS43TwoHeadedGuy:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(6, 8), 7, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(7, 0));
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(Common::Point(5, 8), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = 2;
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS43Key:
+ case kHS43Ufo:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(3, 7), 2, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead();
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(Common::Point(3, 7), 0, 67515, 1);
+ gnap._actionStatus = 1;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS43WalkArea1:
+ case kHS43WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+ }
+ }
+
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ _vm->_mouseClickState._left = false;
+ if (_vm->isFlag(kGFGnapControlsToyUFO) && (_vm->_toyUfoActionStatus == 5 || _vm->_toyUfoActionStatus == -1)) {
+ _vm->_toyUfoActionStatus = 5;
+ _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 3);
+ } else {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ }
+ }
+
+ updateAnimations();
+
+ _vm->toyUfoCheckTimer();
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4] && (!_vm->isFlag(kGFGnapControlsToyUFO) || !_vm->isFlag(kGFGroceryStoreHatTaken))) {
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextTwoHeadedGuySequenceId == -1) {
+ switch (_vm->getRandom(5)) {
+ case 0:
+ _nextTwoHeadedGuySequenceId = 0x13C;
+ break;
+ case 1:
+ _nextTwoHeadedGuySequenceId = 0x134;
+ break;
+ case 2:
+ _nextTwoHeadedGuySequenceId = 0x135;
+ break;
+ case 3:
+ _nextTwoHeadedGuySequenceId = 0x136;
+ break;
+ case 4:
+ _nextTwoHeadedGuySequenceId = 0x13A;
+ break;
+ }
+ if (_nextTwoHeadedGuySequenceId == _currTwoHeadedGuySequenceId)
+ _nextTwoHeadedGuySequenceId = -1;
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ }
+
+ _vm->gameUpdateTick();
+ }
+
+ if (_vm->_newSceneNum == 54)
+ _vm->clearFlag(kGFGnapControlsToyUFO);
+}
+
+void Scene43::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ switch (gnap._actionStatus) {
+ case 0:
+ gameSys.setAnimation(0, 0, 0);
+ _vm->_sceneDone = true;
+ break;
+
+ case 1:
+ if (gameSys.getAnimationStatus(2) == 2) {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ gameSys.insertSequence(0x13D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x13D;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0x13D, gnap._id, 0);
+ _nextTwoHeadedGuySequenceId = 0x13B;
+ gameSys.insertSequence(0x13B, 1, _currTwoHeadedGuySequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextTwoHeadedGuySequenceId, 1, 2);
+ _currTwoHeadedGuySequenceId = _nextTwoHeadedGuySequenceId;
+ _nextTwoHeadedGuySequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ gnap._actionStatus = -1;
+ }
+ break;
+
+ default:
+ gameSys.setAnimation(0, 0, 0);
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ if (_currTwoHeadedGuySequenceId == 0x13A) {
+ if (_vm->isFlag(kGFGroceryStoreHatTaken)) {
+ _nextTwoHeadedGuySequenceId = 0x13E;
+ _vm->stopSound(0x108F6);
+ } else if (_vm->getRandom(2) != 0) {
+ _nextTwoHeadedGuySequenceId = 0x137;
+ } else {
+ _nextTwoHeadedGuySequenceId = 0x138;
+ }
+ } else if (_currTwoHeadedGuySequenceId == 0x13E) {
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 54;
+ }
+ if (_nextTwoHeadedGuySequenceId != -1) {
+ gameSys.insertSequence(_nextTwoHeadedGuySequenceId, 1, _currTwoHeadedGuySequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextTwoHeadedGuySequenceId, 1, 2);
+ _currTwoHeadedGuySequenceId = _nextTwoHeadedGuySequenceId;
+ _nextTwoHeadedGuySequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ switch (_vm->_toyUfoActionStatus) {
+ case 4:
+ _vm->_sceneDone = true;
+ _vm->_toyUfoActionStatus = -1;
+ break;
+ case 6:
+ gameSys.insertSequence(0x10871, _vm->_toyUfoId, _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(0x1086F, 1, true);
+ _vm->setFlag(kGFUnk14);
+ updateHotspots();
+ _vm->toyUfoSetStatus(kGFUnk18);
+ _vm->_toyUfoSequenceId = 0x871;
+ gameSys.setAnimation(0x10871, _vm->_toyUfoId, 3);
+ _vm->_toyUfoActionStatus = -1;
+ _vm->_toyUfoX = 96;
+ _vm->_toyUfoY = 131;
+ break;
+ case 7:
+ gameSys.insertSequence(0x10874, _vm->_toyUfoId, _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, kSeqSyncWait, 0, 0, 0);
+ _vm->_toyUfoSequenceId = 0x874;
+ gameSys.setAnimation(0x10874, _vm->_toyUfoId, 3);
+ _vm->_toyUfoActionStatus = 8;
+ _vm->setFlag(kGFJointTaken);
+ gnap._actionStatus = 3;
+ break;
+ case 8:
+ _nextTwoHeadedGuySequenceId = 0x13A;
+ _vm->_toyUfoX = 514;
+ _vm->_toyUfoY = 125;
+ _vm->toyUfoFlyTo(835, 125, 0, 835, 0, 300, 3);
+ _vm->_toyUfoActionStatus = 9;
+ break;
+ case 9:
+ // Nothing
+ break;
+ default:
+ _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId();
+ gameSys.insertSequence(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId + 1,
+ _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId,
+ kSeqSyncWait, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId;
+ ++_vm->_toyUfoId;
+ gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId, 3);
+ _vm->_toyUfoActionStatus = -1;
+ break;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene44::Scene44(GnapEngine *vm) : Scene(vm) {
+ _nextSpringGuySequenceId = -1;
+ _nextKissingLadySequenceId = -1;
+ _currSpringGuySequenceId = -1;
+ _currKissingLadySequenceId = -1;
+}
+
+int Scene44::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ gameSys.setAnimation(0, 0, 3);
+ return 0xFF;
+}
+
+void Scene44::updateHotspots() {
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->setHotspot(kHS44Platypus, 0, 0, 0, 0, SF_DISABLED);
+ _vm->setHotspot(kHS44UfoExitLeft, 0, 0, 10, 599, SF_EXIT_L_CURSOR);
+ _vm->setHotspot(kHS44UfoExitRight, 790, 0, 799, 599, SF_EXIT_R_CURSOR);
+ _vm->setDeviceHotspot(kHS44UfoDevice, -1, 534, -1, 599);
+ _vm->_hotspotsCount = 4;
+ } else {
+ _vm->setHotspot(kHS44Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS44ExitUfoParty, 150, 580, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS44ExitUfo, 0, 100, 10, 599, SF_EXIT_L_CURSOR, 0, 8);
+ _vm->setHotspot(kHS44ExitShow, 790, 100, 799, 599, SF_EXIT_R_CURSOR, 10, 8);
+ _vm->setHotspot(kHS44KissingLady, 300, 160, 400, 315, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 7);
+ _vm->setHotspot(kHS44Spring, 580, 310, 635, 375, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 8);
+ _vm->setHotspot(kHS44SpringGuy, 610, 375, 690, 515, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 8);
+ _vm->setHotspot(kHS44WalkArea1, 0, 0, 800, 445);
+ _vm->setHotspot(kHS44WalkArea2, 617, 0, 800, 600);
+ _vm->setDeviceHotspot(kHS44Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFUnk13))
+ _vm->_hotspots[kHS44KissingLady]._flags = SF_DISABLED;
+ if (_vm->isFlag(kGFSpringTaken))
+ _vm->_hotspots[kHS44Spring]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 10;
+ }
+}
+
+void Scene44::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+
+ gameSys.insertSequence(0xF7, 0, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0xFC, 256, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFSpringTaken))
+ _currSpringGuySequenceId = 0xF8;
+ else
+ _currSpringGuySequenceId = 0xF9;
+
+ _nextSpringGuySequenceId = -1;
+ gameSys.setAnimation(_currSpringGuySequenceId, 1, 4);
+ gameSys.insertSequence(_currSpringGuySequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFUnk13)) {
+ if (_vm->_prevSceneNum != 50 || _vm->_sceneSavegameLoaded) {
+ _currKissingLadySequenceId = 0xF6;
+ _nextKissingLadySequenceId = -1;
+ } else {
+ _vm->setGrabCursorSprite(kItemGum);
+ _currKissingLadySequenceId = 0xF5;
+ _nextKissingLadySequenceId = 0xF6;
+ gameSys.setAnimation(0xF5, 1, 2);
+ }
+ } else {
+ _currKissingLadySequenceId = 0xEC;
+ _nextKissingLadySequenceId = -1;
+ gameSys.setAnimation(0xEC, 1, 2);
+ }
+
+ gameSys.insertSequence(_currKissingLadySequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoId = 0;
+ _vm->_toyUfoActionStatus = -1;
+ _vm->_toyUfoSequenceId = _vm->toyUfoGetSequenceId();
+ _vm->_toyUfoNextSequenceId = _vm->_toyUfoSequenceId;
+ if (_vm->_prevSceneNum == 43)
+ _vm->_toyUfoX = 30;
+ else
+ _vm->_toyUfoX = 770;
+ gameSys.setAnimation(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 3);
+ gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->endSceneInit();
+ } else {
+ switch (_vm->_prevSceneNum) {
+ case 43:
+ gnap.initPos(-1, 8, kDirUpRight);
+ plat.initPos(-1, 7, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1);
+ break;
+ case 46:
+ gnap.initPos(11, 8, kDirUpRight);
+ plat.initPos(11, 8, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(6, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(7, 8), -1, 0x107D2, 1);
+ break;
+ case 50:
+ gnap.initPos(4, 8, kDirBottomRight);
+ if (_vm->_sceneSavegameLoaded) {
+ plat.initPos(_vm->_hotspotsWalkPos[4].x, _vm->_hotspotsWalkPos[4].y, kDirIdleRight);
+ } else if (!_vm->isFlag(kGFUnk13)) {
+ _vm->_timers[0] = 50;
+ _vm->_timers[1] = 20;
+ plat._pos = Common::Point(5, 8);
+ plat._sequenceId = 0xFD;
+ plat._idleFacing = kDirIdleLeft;
+ plat._id = 160;
+ plat._sequenceDatNum = 0;
+ gameSys.insertSequence(0xFD, 160, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ _vm->endSceneInit();
+ break;
+ default:
+ gnap.initPos(5, 11, kDirUpRight);
+ plat.initPos(6, 11, kDirUpLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107BA, 1);
+ break;
+ }
+ }
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1094B))
+ _vm->playSound(0x1094B, true);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS44UfoExitLeft:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = 6;
+ _vm->_newSceneNum = 43;
+ _vm->toyUfoFlyTo(-35, -1, -35, 799, 0, 300, 3);
+ }
+ break;
+
+ case kHS44UfoExitRight:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = 6;
+ _vm->_newSceneNum = 46;
+ _vm->toyUfoFlyTo(835, -1, 0, 835, 0, 300, 3);
+ }
+ break;
+
+ case kHS44UfoDevice:
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ break;
+ }
+ } else if (_vm->_sceneClickedHotspot <= 9) {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS44Device:
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ break;
+
+ case kHS44Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS44ExitUfoParty:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS44ExitUfoParty], 0, 0x107AE, 1);
+ gnap._actionStatus = 0;
+ _vm->_newSceneNum = 40;
+ break;
+
+ case kHS44ExitUfo:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS44ExitUfo].x, gnap._pos.y), 0, 0x107AF, 1);
+ gnap._actionStatus = 0;
+ plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS44ExitUfo].x, plat._pos.y), -1, 0x107CF, 1);
+ _vm->_newSceneNum = 43;
+ break;
+
+ case kHS44ExitShow:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS44ExitShow], 0, 0x107AB, 1);
+ gnap._actionStatus = 0;
+ _vm->_newSceneNum = 46;
+ break;
+
+ case kHS44KissingLady:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap._actionStatus = 2;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS44KissingLady], 0, -1, 9);
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, _vm->_hotspotsWalkPos[kHS44KissingLady].x - 1, _vm->_hotspotsWalkPos[kHS44KissingLady].y);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(4, 3));
+ break;
+ case GRAB_CURSOR:
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS44KissingLady], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = 1;
+ break;
+ case PLAT_CURSOR:
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(Common::Point(6, 7), 1, 0x107D2, 1);
+ if (gnap._pos == Common::Point(7, 7))
+ gnap.walkStep();
+ gnap.playIdle(Common::Point(5, 7));
+ plat._actionStatus = 4;
+ break;
+ }
+ }
+ break;
+
+ case kHS44Spring:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS44Spring], 8, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(8, 7));
+ break;
+ case GRAB_CURSOR:
+ gnap.playPullOutDevice(Common::Point(8, 0));
+ gnap.playUseDevice(Common::Point(8, 0));
+ _nextSpringGuySequenceId = 0xFB;
+ _vm->invAdd(kItemSpring);
+ _vm->setFlag(kGFSpringTaken);
+ updateHotspots();
+ break;
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS44SpringGuy:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS44SpringGuy], 8, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFSpringTaken))
+ gnap.playMoan1(Common::Point(8, 7));
+ else
+ gnap.playScratchingHead(Common::Point(8, 7));
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS44SpringGuy], -1, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS44WalkArea1:
+ case kHS44WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ }
+ }
+
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ _vm->_mouseClickState._left = false;
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoActionStatus = 7;
+ _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 3);
+ } else {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ }
+ }
+
+ updateAnimations();
+ _vm->toyUfoCheckTimer();
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO) && _currKissingLadySequenceId != 0xF5)
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextKissingLadySequenceId == -1) {
+ switch (_vm->getRandom(20)) {
+ case 0:
+ _nextKissingLadySequenceId = 0xED;
+ break;
+ case 1:
+ _nextKissingLadySequenceId = 0xEE;
+ break;
+ case 2:
+ _nextKissingLadySequenceId = 0xF0;
+ break;
+ case 3:
+ _nextKissingLadySequenceId = 0xF3;
+ break;
+ case 4:
+ _nextKissingLadySequenceId = 0xF4;
+ break;
+ default:
+ _nextKissingLadySequenceId = 0xEC;
+ break;
+ }
+ if (_nextKissingLadySequenceId != 0xEC && _nextKissingLadySequenceId == _currKissingLadySequenceId)
+ _nextKissingLadySequenceId = -1;
+ }
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(20) + 20;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextSpringGuySequenceId == -1) {
+ if (_vm->getRandom(5) != 0) {
+ if (!_vm->isFlag(kGFSpringTaken))
+ _nextSpringGuySequenceId = 0xF9;
+ } else {
+ if (_vm->isFlag(kGFSpringTaken))
+ _nextSpringGuySequenceId = 0xF8;
+ else
+ _nextSpringGuySequenceId = 0xFA;
+ }
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene44::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case 0:
+ _vm->_sceneDone = true;
+ break;
+ case 1:
+ _nextKissingLadySequenceId = 0xEF;
+ break;
+ case 2:
+ _nextKissingLadySequenceId = 0xF2;
+ break;
+ }
+ gnap._actionStatus = -1;
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ switch (plat._actionStatus) {
+ case 4:
+ if (gameSys.getAnimationStatus(2) == 2) {
+ gameSys.insertSequence(0xFE, plat._id, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceId = 0xFE;
+ plat._sequenceDatNum = 0;
+ gameSys.setAnimation(0xFE, plat._id, 1);
+ gameSys.removeSequence(_currKissingLadySequenceId, 1, true);
+ plat._actionStatus = 5;
+ }
+ break;
+ case 5:
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 50;
+ break;
+ default:
+ plat._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ if (_nextKissingLadySequenceId == 0xF6) {
+ gameSys.insertSequence(_nextKissingLadySequenceId, 1, _currKissingLadySequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ plat.initPos(5, 8, kDirIdleLeft);
+ _currKissingLadySequenceId = _nextKissingLadySequenceId;
+ _nextKissingLadySequenceId = -1;
+ gameSys.setAnimation(0, 0, 2);
+ } else if (_nextKissingLadySequenceId != -1) {
+ gameSys.insertSequence(_nextKissingLadySequenceId, 1, _currKissingLadySequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextKissingLadySequenceId, 1, 2);
+ _currKissingLadySequenceId = _nextKissingLadySequenceId;
+ _nextKissingLadySequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2) {
+ if (_currSpringGuySequenceId == 0xFB) {
+ _vm->setGrabCursorSprite(kItemSpring);
+ _nextSpringGuySequenceId = 0xF8;
+ }
+ if (_nextSpringGuySequenceId != -1) {
+ gameSys.insertSequence(_nextSpringGuySequenceId, 1, _currSpringGuySequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextSpringGuySequenceId, 1, 4);
+ _currSpringGuySequenceId = _nextSpringGuySequenceId;
+ _nextSpringGuySequenceId = -1;
+ _vm->_timers[5] = _vm->getRandom(20) + 20;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ switch (_vm->_toyUfoActionStatus) {
+ case 6:
+ _vm->_sceneDone = true;
+ break;
+ default:
+ _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId();
+ gameSys.insertSequence(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId + 1,
+ _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId,
+ kSeqSyncWait, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId;
+ ++_vm->_toyUfoId;
+ gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId, 3);
+ break;
+ }
+ _vm->_toyUfoActionStatus = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene45::Scene45(GnapEngine *vm) : Scene(vm) {
+ _currDancerSequenceId = -1;
+}
+
+int Scene45::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ gameSys.setAnimation(0, 0, 3);
+ gameSys.setAnimation(0, 0, 4);
+ gameSys.setAnimation(0, 0, 5);
+ return _vm->isFlag(kGFUnk23) ? 0xA2 : 0xA1;
+}
+
+void Scene45::updateHotspots() {
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->setHotspot(kHS45Platypus, 0, 0, 0, 0, SF_DISABLED);
+ _vm->setHotspot(kHS45UfoExitLeft, 0, 0, 10, 599, SF_EXIT_L_CURSOR);
+ _vm->setHotspot(kHS45UfoExitRight, 794, 0, 799, 599, SF_EXIT_R_CURSOR | SF_DISABLED);
+ _vm->setDeviceHotspot(kHS45UfoDevice, -1, 534, -1, 599);
+ _vm->_hotspotsCount = 4;
+ } else {
+ _vm->setHotspot(kHS45Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS45ExitUfoParty, 150, 580, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS45ExitShoe, 0, 100, 10, 599, SF_EXIT_L_CURSOR, 0, 8);
+ _vm->setHotspot(kHS45ExitRight, 794, 100, 799, 599, SF_EXIT_R_CURSOR | SF_DISABLED, 10, 8);
+ _vm->setHotspot(kHS45ExitDiscoBall, 200, 0, 600, 10, SF_DISABLED);
+ _vm->setHotspot(kHS45DiscoBall, 370, 10, 470, 125, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 7);
+ _vm->setHotspot(kHS45WalkArea1, 0, 0, 800, 472);
+ _vm->setDeviceHotspot(kHS45Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFUnk22)) {
+ _vm->_hotspots[kHS45Platypus]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS45ExitUfoParty]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS45ExitShoe]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS45ExitRight]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS45ExitDiscoBall]._flags = SF_EXIT_U_CURSOR;
+ }
+ if (_vm->isFlag(kGFUnk23) || _vm->isFlag(kGFUnk22))
+ _vm->_hotspots[kHS45DiscoBall]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 8;
+ }
+}
+
+void Scene45::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (!_vm->isSoundPlaying(0x1094A))
+ _vm->playSound(0x1094A, true);
+
+ _vm->queueInsertDeviceIcon();
+
+ gameSys.insertSequence(0x96, 1, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(0x96, 1, 3);
+ gameSys.insertSequence(0x99, 1, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(0x99, 1, 4);
+ _currDancerSequenceId = 0x8F;
+ gameSys.setAnimation(_currDancerSequenceId, 1, 2);
+ gameSys.insertSequence(_currDancerSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoId = 0;
+ _vm->_toyUfoActionStatus = -1;
+ _vm->_toyUfoSequenceId = _vm->toyUfoGetSequenceId();
+ _vm->_toyUfoNextSequenceId = _vm->_toyUfoSequenceId;
+ if (_vm->_prevSceneNum == 46)
+ _vm->_toyUfoX = 30;
+ else
+ _vm->_toyUfoX = 770;
+ gameSys.setAnimation(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 5);
+ gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->endSceneInit();
+ } else if (_vm->isFlag(kGFUnk22)) {
+ gnap._sequenceId = 0x9E;
+ gnap._sequenceDatNum = 0;
+ gnap._id = 1;
+ gameSys.setAnimation(0x9E, 1, 0);
+ gnap._actionStatus = 1;
+ gameSys.insertSequence(gnap._sequenceId, gnap._id, 0, 0, kSeqNone, 0, 0, 0);
+ plat.initPos(4, 8, kDirIdleLeft);
+ _vm->endSceneInit();
+ } else if (_vm->_prevSceneNum == 46) {
+ gnap.initPos(-1, 8, kDirUpRight);
+ plat.initPos(-1, 9, kDirUpLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(4, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(2, 7), -1, 0x107B9, 1);
+ } else if (_vm->_prevSceneNum == 41) {
+ gnap.initPos(11, 8, kDirUpRight);
+ plat.initPos(11, 9, kDirUpLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(4, 8), -1, 0x107D2, 1);
+ gnap.walkTo(Common::Point(10, 9), -1, 0x107BA, 1);
+ } else {
+ gnap.initPos(2, 11, kDirUpRight);
+ plat.initPos(6, 11, kDirUpLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(4, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(2, 7), -1, 0x107B9, 1);
+ }
+
+ if (!_vm->isFlag(kGFUnk21) && !_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->setFlag(kGFUnk21);
+ _vm->setGrabCursorSprite(-1);
+ gameSys.setAnimation(0x9D, gnap._id, 0);
+ gameSys.insertSequence(0x9D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone) {
+ _vm->gameUpdateTick();
+ if (gameSys.getAnimationStatus(2) == 2) {
+ gameSys.setAnimation(0, 0, 2);
+ int newSeqId = _vm->getRandom(7) + 0x8F;
+ gameSys.insertSequence(newSeqId, 1, _currDancerSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(newSeqId, 1, 2);
+ _currDancerSequenceId = newSeqId;
+ }
+ if (gameSys.getAnimationStatus(3) == 2 && gameSys.getAnimationStatus(4) == 2) {
+ gameSys.insertSequence(0x96, 1, 0x96, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x96, 1, 3);
+ gameSys.insertSequence(0x99, 1, 0x99, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x99, 1, 4);
+ }
+ }
+ gnap._sequenceId = 0x9D;
+ gnap._sequenceDatNum = 0;
+ _vm->hideCursor();
+ _vm->addFullScreenSprite(0x8A, 255);
+ gameSys.setAnimation(0xA0, 256, 0);
+ gameSys.insertSequence(0xA0, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ gameSys.setAnimation(0x107BD, gnap._id, 0);
+ gameSys.insertSequence(0x107BD, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ _vm->removeFullScreenSprite();
+ _vm->showCursor();
+ gnap._sequenceId = 0x7BD;
+ gnap._sequenceDatNum = 1;
+ }
+
+ plat.playSequence(0x9A);
+ gameSys.setAnimation(plat._sequenceId, plat._id, 1);
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1094A))
+ _vm->playSound(0x1094A, true);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS45UfoExitLeft:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = 2;
+ _vm->_newSceneNum = 46;
+ _vm->toyUfoFlyTo(-35, -1, -35, 799, 0, 300, 5);
+ }
+ break;
+
+ case kHS45UfoExitRight:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = 2;
+ _vm->_newSceneNum = 41;
+ _vm->toyUfoFlyTo(835, -1, 0, 835, 0, 300, 5);
+ }
+ break;
+
+ case kHS45UfoDevice:
+ _vm->runMenu();
+ updateHotspots();
+ break;
+ }
+ } else {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS45Device:
+ _vm->runMenu();
+ updateHotspots();
+ break;
+
+ case kHS45Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ plat.playSequence(0x9A);
+ gameSys.setAnimation(plat._sequenceId, plat._id, 1);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS45ExitUfoParty:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(gnap._pos.x, _vm->_hotspotsWalkPos[kHS45ExitUfoParty].y), 0, 0x107AE, 1);
+ gnap._actionStatus = 0;
+ _vm->_newSceneNum = 40;
+ }
+ break;
+
+ case kHS45ExitShoe:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS45ExitShoe].x, gnap._pos.y), 0, 0x107AF, 1);
+ gnap._actionStatus = 0;
+ plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS45ExitShoe].x, plat._pos.y), -1, 0x107CF, 1);
+ _vm->_newSceneNum = 46;
+ }
+ break;
+
+ case kHS45ExitRight:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS45ExitRight].x, gnap._pos.y), 0, 0x107AB, 1);
+ gnap._actionStatus = 0;
+ plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS45ExitRight].x, plat._pos.y), -1, 0x107CD, 1);
+ _vm->_newSceneNum = 41;
+ }
+ break;
+
+ case kHS45ExitDiscoBall:
+ _vm->clearFlag(kGFUnk22);
+ _vm->setFlag(kGFUnk23);
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 54;
+ break;
+
+ case kHS45DiscoBall:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemSpring) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS45DiscoBall], 0, 0x9F, 5);
+ gnap._actionStatus = 1;
+ _vm->setGrabCursorSprite(-1);
+ _vm->invRemove(kItemSpring);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 5, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(5, 0));
+ break;
+ case GRAB_CURSOR:
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS45WalkArea1:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+ }
+ }
+
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ _vm->_mouseClickState._left = false;
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoActionStatus = 3;
+ _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 5);
+ } else {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ }
+ }
+
+ updateAnimations();
+ _vm->toyUfoCheckTimer();
+
+ if (!_vm->_isLeavingScene && gnap._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ gnap.updateIdleSequence();
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+
+ _vm->_sceneWaiting = false;
+}
+
+void Scene45::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case 0:
+ _vm->_sceneDone = true;
+ break;
+ case 1:
+ _vm->_sceneWaiting = true;
+ _vm->setFlag(kGFUnk22);
+ updateHotspots();
+ gameSys.insertSequence(0x9E, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x9E;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0x9E, gnap._id, 0);
+ break;
+ default:
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ if (_vm->getRandom(2) != 0)
+ plat.playSequence(0x9B);
+ else
+ plat.playSequence(0x9C);
+ gameSys.setAnimation(plat._sequenceId, plat._id, 1);
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ gameSys.setAnimation(0, 0, 2);
+ int newSeqId = _vm->getRandom(7) + 0x8F;
+ gameSys.insertSequence(newSeqId, 1, _currDancerSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(newSeqId, 1, 2);
+ _currDancerSequenceId = newSeqId;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2 && gameSys.getAnimationStatus(4) == 2) {
+ gameSys.insertSequence(0x96, 1, 0x96, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x96, 1, 3);
+ gameSys.insertSequence(0x99, 1, 0x99, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x99, 1, 4);
+ }
+
+ if (gameSys.getAnimationStatus(5) == 2) {
+ switch (_vm->_toyUfoActionStatus) {
+ case 2:
+ _vm->_sceneDone = true;
+ break;
+ default:
+ _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId();
+ gameSys.insertSequence(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId + 1,
+ _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId,
+ kSeqSyncWait, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId;
+ ++_vm->_toyUfoId;
+ gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId, 5);
+ break;
+ }
+ _vm->_toyUfoActionStatus = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene46::Scene46(GnapEngine *vm) : Scene(vm) {
+ _currSackGuySequenceId = -1;
+ _nextItchyGuySequenceId = -1;
+ _nextSackGuySequenceId = -1;
+ _currItchyGuySequenceId = -1;
+}
+
+int Scene46::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ gameSys.setAnimation(0, 0, 3);
+ gameSys.setAnimation(0, 0, 4);
+ return 0x4E;
+}
+
+void Scene46::updateHotspots() {
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->setHotspot(kHS46Platypus, 0, 0, 0, 0, SF_DISABLED);
+ _vm->setHotspot(kHS46UfoExitLeft, 0, 0, 10, 599, SF_EXIT_L_CURSOR);
+ _vm->setHotspot(kHS46UfoExitRight, 790, 0, 799, 599, SF_EXIT_R_CURSOR);
+ _vm->setDeviceHotspot(kHS46UfoDevice, -1, 534, -1, 599);
+ _vm->_hotspotsCount = 4;
+ } else {
+ _vm->setHotspot(kHS46Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS46ExitUfoParty, 150, 580, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS46ExitKissinBooth, 0, 100, 10, 599, SF_EXIT_L_CURSOR, 0, 8);
+ _vm->setHotspot(kHS46ExitDisco, 790, 100, 799, 599, SF_EXIT_R_CURSOR, 10, 8);
+ _vm->setHotspot(kHS46SackGuy, 180, 370, 235, 490, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 8);
+ _vm->setHotspot(kHS46ItchyGuy, 535, 210, 650, 480, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 8);
+ _vm->setHotspot(kHS46WalkArea1, 0, 0, 800, 485);
+ _vm->setDeviceHotspot(kHS46Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 8;
+ }
+}
+
+void Scene46::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+ gameSys.insertSequence(0x4D, 0, 0, 0, kSeqLoop, 0, 0, 0);
+
+ _currSackGuySequenceId = 0x4B;
+ _nextSackGuySequenceId = -1;
+ gameSys.setAnimation(0x4B, 1, 3);
+ gameSys.insertSequence(_currSackGuySequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currItchyGuySequenceId = 0x47;
+ _nextItchyGuySequenceId = -1;
+ gameSys.setAnimation(0x47, 1, 4);
+ gameSys.insertSequence(_currItchyGuySequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoId = 0;
+ _vm->_toyUfoActionStatus = -1;
+ _vm->_toyUfoSequenceId = _vm->toyUfoGetSequenceId();
+ _vm->_toyUfoNextSequenceId = _vm->_toyUfoSequenceId;
+ if (_vm->_prevSceneNum == 44)
+ _vm->_toyUfoX = 30;
+ else
+ _vm->_toyUfoX = 770;
+ gameSys.setAnimation(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 2);
+ gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->endSceneInit();
+ } else if (_vm->_prevSceneNum == 44) {
+ gnap.initPos(-1, 8, kDirUpRight);
+ plat.initPos(-1, 8, kDirUpLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ } else if (_vm->_prevSceneNum == 45) {
+ gnap.initPos(11, 8, kDirUpRight);
+ plat.initPos(12, 8, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 8), -1, 0x107D2, 1);
+ } else {
+ gnap.initPos(5, 11, kDirUpRight);
+ plat.initPos(6, 11, kDirUpLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(5, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(6, 8), -1, 0x107BA, 1);
+ }
+
+ _vm->_timers[4] = _vm->getRandom(50) + 80;
+ _vm->_timers[5] = _vm->getRandom(50) + 80;
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1094B))
+ _vm->playSound(0x1094B, true);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS46UfoExitLeft:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = 3;
+ _vm->_newSceneNum = 44;
+ _vm->toyUfoFlyTo(-35, -1, -35, 799, 0, 300, 2);
+ }
+ break;
+
+ case kHS46UfoExitRight:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = 3;
+ _vm->_newSceneNum = 45;
+ _vm->toyUfoFlyTo(835, -1, 0, 835, 0, 300, 2);
+ }
+ break;
+
+ case kHS46UfoDevice:
+ _vm->runMenu();
+ updateHotspots();
+ break;
+ }
+ } else {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS46Device:
+ _vm->runMenu();
+ updateHotspots();
+ break;
+
+ case kHS46Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS46SackGuy:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS46SackGuy], 2, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(Common::Point(_vm->_hotspotsWalkPos[kHS46SackGuy].x + 1, 0));
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS46SackGuy], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = 2;
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS46ItchyGuy:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS46ItchyGuy], 7, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(Common::Point(_vm->_hotspotsWalkPos[kHS46ItchyGuy].x - 1, 0));
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS46ItchyGuy], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = 1;
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS46ExitUfoParty:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(gnap._pos.x, _vm->_hotspotsWalkPos[kHS46ExitUfoParty].y), 0, 0x107AE, 1);
+ gnap._actionStatus = 0;
+ _vm->_newSceneNum = 40;
+ break;
+
+ case kHS46ExitKissinBooth:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS46ExitKissinBooth].x, gnap._pos.y), 0, 0x107AF, 1);
+ gnap._actionStatus = 0;
+ plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS46ExitKissinBooth].x, plat._pos.y), -1, 0x107CF, 1);
+ _vm->_newSceneNum = 44;
+ break;
+
+ case kHS46ExitDisco:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS46ExitDisco].x, gnap._pos.y), 0, 0x107AB, 1);
+ gnap._actionStatus = 0;
+ plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS46ExitDisco].x, plat._pos.y), -1, 0x107CD, 1);
+ _vm->_newSceneNum = 45;
+ break;
+
+ case kHS46WalkArea1:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+ }
+ }
+
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ _vm->_mouseClickState._left = false;
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoActionStatus = 4;
+ _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 2);
+ } else {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ }
+ }
+
+ updateAnimations();
+ _vm->toyUfoCheckTimer();
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(50) + 80;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextItchyGuySequenceId == -1) {
+ if (_vm->getRandom(2) != 0)
+ _nextItchyGuySequenceId = 0x49;
+ else
+ _nextItchyGuySequenceId = 0x48;
+ }
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(50) + 80;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextSackGuySequenceId == -1)
+ _nextSackGuySequenceId = 0x4C;
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene46::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case 0:
+ _vm->_sceneDone = true;
+ break;
+ case 1:
+ _nextItchyGuySequenceId = 0x46;
+ break;
+ case 2:
+ _nextSackGuySequenceId = 0x4A;
+ break;
+ }
+ gnap._actionStatus = -1;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2 && _nextSackGuySequenceId != -1) {
+ gameSys.insertSequence(_nextSackGuySequenceId, 1, _currSackGuySequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextSackGuySequenceId, 1, 3);
+ _currSackGuySequenceId = _nextSackGuySequenceId;
+ _nextSackGuySequenceId = -1;
+ _vm->_timers[5] = _vm->getRandom(50) + 80;
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2 && _nextItchyGuySequenceId != -1) {
+ gameSys.insertSequence(_nextItchyGuySequenceId, 1, _currItchyGuySequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextItchyGuySequenceId, 1, 4);
+ _currItchyGuySequenceId = _nextItchyGuySequenceId;
+ _nextItchyGuySequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(50) + 80;
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ switch (_vm->_toyUfoActionStatus) {
+ case 3:
+ _vm->_sceneDone = true;
+ break;
+ default:
+ _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId();
+ gameSys.insertSequence(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId + 1,
+ _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId,
+ kSeqSyncWait, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId;
+ ++_vm->_toyUfoId;
+ gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId, 2);
+ break;
+ }
+ _vm->_toyUfoActionStatus = -1;
+ }
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/group4.h b/engines/gnap/scenes/group4.h
new file mode 100644
index 0000000000..afcd62e9e7
--- /dev/null
+++ b/engines/gnap/scenes/group4.h
@@ -0,0 +1,298 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 GNAP_GROUP4_H
+#define GNAP_GROUP4_H
+
+#include "gnap/debugger.h"
+
+namespace Gnap {
+
+enum {
+ kHS40Platypus = 0,
+ kHS40ExitCave = 1,
+ kHS40ExitToyStand = 2,
+ kHS40ExitBBQ = 3,
+ kHS40ExitUfo = 4,
+ kHS40ExitKissinBooth = 5,
+ kHS40ExitDancefloor = 6,
+ kHS40ExitShoe = 7,
+ kHS40Device = 8
+};
+
+enum {
+ kHS41Platypus = 0,
+ kHS41ExitCave = 1,
+ kHS41Exit = 2,
+ kHS41ExitBBQ = 3,
+ kHS41ToyVendor = 4,
+ kHS41Kid = 5,
+ kHS41ToyUfo = 6,
+ kHS41Device = 7,
+ kHS41WalkArea1 = 8
+};
+
+enum {
+ kHS41UfoExitLeft = 1,
+ kHS41UfoExitRight = 2,
+ kHS41UfoDevice = 3,
+ kHS41UfoWalkArea1 = 4
+};
+
+enum {
+ kHS42Platypus = 0,
+ kHS42ExitUfoParty = 1,
+ kHS42ExitToyStand = 2,
+ kHS42ExitUfo = 3,
+ kHS42BBQVendor = 4,
+ kHS42ChickenLeg = 5,
+ kHS42Device = 6,
+ kHS42WalkArea1 = 7,
+ kHS42WalkArea2 = 8
+};
+
+enum {
+ kHS42UfoExitLeft = 1,
+ kHS42UfoExitRight = 2,
+ kHS42UfoHotSauce = 3,
+ kHS42UfoDevice = 4
+};
+
+enum {
+ kHS43Platypus = 0,
+ kHS43Device = 1,
+ kHS43ExitUfoParty = 2,
+ kHS43ExitBBQ = 3,
+ kHS43ExitKissinBooth = 4,
+ kHS43TwoHeadedGuy = 5,
+ kHS43Key = 6,
+ kHS43Ufo = 7,
+ kHS43WalkArea1 = 8,
+ kHS43WalkArea2 = 9
+};
+
+enum {
+ kHS43UfoExitLeft = 1,
+ kHS43UfoExitRight = 2,
+ kHS43UfoKey = 3,
+ kHS43UfoBucket = 4,
+ kHS43UfoDevice = 5
+};
+
+enum {
+ kHS44Platypus = 0,
+ kHS44ExitUfoParty = 1,
+ kHS44ExitUfo = 2,
+ kHS44ExitShow = 3,
+ kHS44KissingLady = 4,
+ kHS44Spring = 5,
+ kHS44SpringGuy = 6,
+ kHS44Device = 7,
+ kHS44WalkArea1 = 8,
+ kHS44WalkArea2 = 9
+};
+
+enum {
+ kHS44UfoExitLeft = 1,
+ kHS44UfoExitRight = 2,
+ kHS44UfoDevice = 3
+};
+
+enum {
+ kHS45Platypus = 0,
+ kHS45ExitUfoParty = 1,
+ kHS45ExitShoe = 2,
+ kHS45ExitRight = 3,
+ kHS45ExitDiscoBall = 4,
+ kHS45DiscoBall = 5,
+ kHS45Device = 6,
+ kHS45WalkArea1 = 7
+};
+
+enum {
+ kHS45UfoExitLeft = 1,
+ kHS45UfoExitRight = 2,
+ kHS45UfoDevice = 3
+};
+
+enum {
+ kHS46Platypus = 0,
+ kHS46ExitUfoParty = 1,
+ kHS46ExitKissinBooth = 2,
+ kHS46ExitDisco = 3,
+ kHS46SackGuy = 4,
+ kHS46ItchyGuy = 5,
+ kHS46Device = 6,
+ kHS46WalkArea1 = 7
+};
+
+enum {
+ kHS46UfoExitLeft = 1,
+ kHS46UfoExitRight = 2,
+ kHS46UfoDevice = 3
+};
+
+enum {
+ kAS41LeaveScene = 0,
+ kAS41UseQuarterWithToyVendor = 1,
+ kAS41TalkToyVendor = 2,
+ kAS41UseGumWithToyUfo = 3,
+ kAS41UseChickenBucketWithKid = 4,
+ kAS41GrabKid = 5,
+ kAS41GiveBackToyUfo = 6,
+ kAS41ToyUfoLeaveScene = 7,
+ kAS41ToyUfoRefresh = 8,
+ kAS41UfoGumAttached = 9
+};
+
+enum {
+ kAS42LeaveScene = 0,
+ kAS42TalkBBQVendor = 1,
+ kAS42UseQuarterWithBBQVendor = 2,
+ kAS42UseQuarterWithBBQVendorDone = 3,
+ kAS42GrabChickenLeg = 4,
+ kAS42ToyUfoLeaveScene = 5,
+ kAS42ToyUfoRefresh = 6,
+ kAS42ToyUfoPickUpHotSauce = 7
+};
+
+/*****************************************************************************/
+
+class GnapEngine;
+class CutScene;
+
+class Scene40: public Scene {
+public:
+ Scene40(GnapEngine *vm);
+ virtual ~Scene40() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+};
+
+class Scene41: public Scene {
+public:
+ Scene41(GnapEngine *vm);
+ virtual ~Scene41() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currKidSequenceId;
+ int _nextKidSequenceId;
+ int _currToyVendorSequenceId;
+ int _nextToyVendorSequenceId;
+};
+
+class Scene42: public Scene {
+public:
+ Scene42(GnapEngine *vm);
+ virtual ~Scene42() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currBBQVendorSequenceId;
+ int _nextBBQVendorSequenceId;
+};
+
+class Scene43: public Scene {
+public:
+ Scene43(GnapEngine *vm);
+ virtual ~Scene43() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currTwoHeadedGuySequenceId;
+ int _nextTwoHeadedGuySequenceId;
+};
+
+class Scene44: public Scene {
+public:
+ Scene44(GnapEngine *vm);
+ virtual ~Scene44() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _nextSpringGuySequenceId;
+ int _nextKissingLadySequenceId;
+ int _currSpringGuySequenceId;
+ int _currKissingLadySequenceId;
+};
+
+class Scene45: public Scene {
+public:
+ Scene45(GnapEngine *vm);
+ virtual ~Scene45() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currDancerSequenceId;
+};
+
+class Scene46: public Scene {
+public:
+ Scene46(GnapEngine *vm);
+ virtual ~Scene46() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currSackGuySequenceId;
+ int _nextItchyGuySequenceId;
+ int _nextSackGuySequenceId;
+ int _currItchyGuySequenceId;
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_GROUP4_H
diff --git a/engines/gnap/scenes/group5.cpp b/engines/gnap/scenes/group5.cpp
new file mode 100644
index 0000000000..46f4c51e5d
--- /dev/null
+++ b/engines/gnap/scenes/group5.cpp
@@ -0,0 +1,381 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/group5.h"
+
+namespace Gnap {
+
+Scene53::Scene53(GnapEngine *vm) : Scene(vm) {
+ _isGnapPhoning = false;
+ _currHandSequenceId = -1;
+ _callsMadeCtr = 0;
+ _callsRndUsed = 0;
+}
+
+int Scene53::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ return 0x75;
+}
+
+void Scene53::updateHotspots() {
+ _vm->setHotspot(kHS53Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey1, 336, 238, 361, 270, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey2, 376, 243, 405, 274, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey3, 415, 248, 441, 276, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey4, 329, 276, 358, 303, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey5, 378, 282, 408, 311, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey6, 417, 286, 446, 319, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey7, 332, 311, 361, 342, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey8, 376, 318, 407, 349, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey9, 417, 320, 447, 353, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey0, 377, 352, 405, 384, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKeySharp, 419, 358, 450, 394, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKeyStar, 328, 346, 359, 379, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneExit, 150, 585, 650, 600, SF_EXIT_D_CURSOR);
+
+ _vm->setDeviceHotspot(kHS53Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 15;
+}
+
+int Scene53::pressPhoneNumberButton(int phoneNumber, int buttonNum) {
+ static const int kGnapHandSequenceIds[13] = {
+ 0x00,
+ 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B,
+ 0x4C, 0x4D, 0x4E, 0x50, 0x51, 0x4F
+ };
+
+ static const int kPlatypusHandSequenceIds[13] = {
+ 0x00,
+ 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5A, 0x5C, 0x5D, 0x5B
+ };
+
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (_isGnapPhoning) {
+ gameSys.setAnimation(kGnapHandSequenceIds[buttonNum], 40, 6);
+ gameSys.insertSequence(kGnapHandSequenceIds[buttonNum], 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currHandSequenceId = kGnapHandSequenceIds[buttonNum];
+ } else {
+ gameSys.setAnimation(kPlatypusHandSequenceIds[buttonNum], 40, 6);
+ gameSys.insertSequence(kPlatypusHandSequenceIds[buttonNum], 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currHandSequenceId = kPlatypusHandSequenceIds[buttonNum];
+ }
+
+ gnap._actionStatus = 6;
+ while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ gnap._actionStatus = -1;
+
+ if (buttonNum < 11)
+ phoneNumber = buttonNum % 10 + 10 * phoneNumber;
+
+ return phoneNumber;
+}
+
+int Scene53::getRandomCallIndex() {
+ int index, tries = 0;
+ if (_callsRndUsed == 0x7FFF)
+ _callsRndUsed = 0;
+ do {
+ index = _vm->getRandom(16);
+ if (++tries == 300)
+ _callsRndUsed = 0;
+ } while (_callsRndUsed & (1 << index));
+ _callsRndUsed |= (1 << index);
+ return index;
+}
+
+void Scene53::runRandomCall() {
+ static const int kCallSequenceIds[15] = {
+ 0x60, 0x61, 0x62, 0x63, 0x64,
+ 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6A, 0x6B, 0x6C, 0x6D, 0x71
+ };
+
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ ++_callsMadeCtr;
+ if (_callsMadeCtr <= 10) {
+ int index;
+
+ do {
+ index = getRandomCallIndex();
+ } while (!_isGnapPhoning && (index == 0 || index == 3 || index == 4 || index == 11));
+ gameSys.setAnimation(kCallSequenceIds[index], 1, 6);
+ gameSys.insertSequence(kCallSequenceIds[index], 1, 0, 0, kSeqNone, 16, 0, 0);
+ } else {
+ gameSys.setAnimation(0x74, 1, 6);
+ gameSys.insertSequence(0x74, 1, 0, 0, kSeqNone, 16, 0, 0);
+ _callsMadeCtr = 0;
+ }
+
+ gnap._actionStatus = 1;
+ while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ gnap._actionStatus = -1;
+}
+
+void Scene53::runChitChatLine() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ bool flag = false;
+ int sequenceId = -1;
+
+ gameSys.setAnimation(0x6E, 1, 6);
+ gameSys.insertSequence(0x6E, 1, 0, 0, kSeqNone, 16, 0, 0);
+
+ gnap._actionStatus = 1;
+ while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ gnap._actionStatus = -1;
+
+ if (_vm->isFlag(kGFSpringTaken)) {
+ gameSys.insertSequence(0x45, 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currHandSequenceId = 0x45;
+ } else {
+ gameSys.insertSequence(0x45, 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currHandSequenceId = 0x5E;
+ }
+
+ _vm->_hotspots[kHS53Device]._flags = SF_DISABLED;
+
+ while (!flag) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case 2:
+ sequenceId = 0x6F;
+ flag = 1;
+ break;
+ case 3:
+ sequenceId = 0x70;
+ flag = 1;
+ break;
+ case 4:
+ sequenceId = 0x71;
+ flag = 1;
+ break;
+ case 14:
+ sequenceId = -1;
+ flag = 1;
+ _vm->_isLeavingScene = true;
+ _vm->_sceneDone = true;
+ gnap._actionStatus = 0;
+ _vm->_newSceneNum = 17;
+ break;
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ pressPhoneNumberButton(0, _vm->_sceneClickedHotspot - 1);
+ break;
+ }
+
+ if (flag && sequenceId != -1) {
+ _vm->stopSound(0xA0);
+ pressPhoneNumberButton(0, _vm->_sceneClickedHotspot - 1);
+ gnap._actionStatus = 1;
+ gameSys.setAnimation(sequenceId, 1, 6);
+ gameSys.insertSequence(sequenceId, 1, 0, 0, kSeqNone, 16, 0, 0);
+ gnap._actionStatus = 1;
+ while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ gnap._actionStatus = -1;
+ gameSys.setAnimation(0x72, 1, 6);
+ gameSys.insertSequence(0x72, 1, 0, 0, kSeqNone, 16, 0, 0);
+ gnap._actionStatus = 1;
+ while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ gnap._actionStatus = -1;
+ }
+ }
+
+ updateHotspots();
+
+ gnap._actionStatus = 1;
+
+ if (_vm->isFlag(kGFSpringTaken)) {
+ gameSys.setAnimation(0x73, 40, 6);
+ gameSys.insertSequence(0x73, 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ _currHandSequenceId = 0x73;
+ gnap._actionStatus = -1;
+ }
+}
+
+void Scene53::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ int phoneNumber = 0;
+ int phoneNumberLen = 0;
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->isFlag(kGFSpringTaken)) {
+ _currHandSequenceId = 0x45;
+ _isGnapPhoning = true;
+ } else {
+ _currHandSequenceId = 0x5E;
+ _isGnapPhoning = false;
+ }
+
+ gameSys.insertSequence(_currHandSequenceId, 40, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+ _vm->setVerbCursor(GRAB_CURSOR);
+ _vm->playSound(0xA0, true);
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS53Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+ case kHS53PhoneKey1:
+ case kHS53PhoneKey2:
+ case kHS53PhoneKey3:
+ case kHS53PhoneKey4:
+ case kHS53PhoneKey5:
+ case kHS53PhoneKey6:
+ case kHS53PhoneKey7:
+ case kHS53PhoneKey8:
+ case kHS53PhoneKey9:
+ case kHS53PhoneKey0:
+ _vm->stopSound(0xA0);
+ ++phoneNumberLen;
+ phoneNumber = pressPhoneNumberButton(phoneNumber, _vm->_sceneClickedHotspot - 1);
+ debugC(kDebugBasic, "phoneNumber: %d", phoneNumber);
+ if (phoneNumberLen == 7) {
+ gnap._actionStatus = 1;
+ if (_vm->isFlag(kGFSpringTaken)) {
+ gameSys.setAnimation(0x73, 40, 6);
+ gameSys.insertSequence(0x73, 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ _currHandSequenceId = 0x73;
+ gnap._actionStatus = -1;
+ }
+ if (phoneNumber == 7284141) {
+ runChitChatLine();
+ phoneNumber = 0;
+ phoneNumberLen = 0;
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 17;
+ } else if (phoneNumber != 5556789 || _vm->isFlag(kGFPictureTaken)) {
+ runRandomCall();
+ phoneNumber = 0;
+ phoneNumberLen = 0;
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 17;
+ } else {
+ phoneNumber = 0;
+ phoneNumberLen = 0;
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 17;
+ if (_isGnapPhoning)
+ _vm->setFlag(kGFUnk25);
+ else
+ _vm->setFlag(kGFPlatypusTalkingToAssistant);
+ }
+ }
+ break;
+ case kHS53PhoneKeySharp:
+ case kHS53PhoneKeyStar:
+ pressPhoneNumberButton(0, _vm->_sceneClickedHotspot - 1);
+ break;
+ case kHS53PhoneExit:
+ if (gnap._actionStatus < 0) {
+ gnap._actionStatus = 1;
+ if (_vm->isFlag(kGFSpringTaken)) {
+ gameSys.setAnimation(0x73, 40, 6);
+ gameSys.insertSequence(0x73, 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ _currHandSequenceId = 0x73;
+ gnap._actionStatus = -1;
+ }
+ _vm->_isLeavingScene = true;
+ _vm->_sceneDone = true;
+ gnap._actionStatus = 0;
+ _vm->_newSceneNum = 17;
+ }
+ break;
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+ _vm->gameUpdateTick();
+ }
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/group5.h b/engines/gnap/scenes/group5.h
new file mode 100644
index 0000000000..dd238ec65c
--- /dev/null
+++ b/engines/gnap/scenes/group5.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.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 GNAP_GROUP5_H
+#define GNAP_GROUP5_H
+
+#include "gnap/debugger.h"
+#include "gnap/scenes/scenecore.h"
+
+namespace Gnap {
+
+enum {
+ kHS53Platypus = 0,
+ kHS53Device = 1,
+ kHS53PhoneKey1 = 2,
+ kHS53PhoneKey2 = 3,
+ kHS53PhoneKey3 = 4,
+ kHS53PhoneKey4 = 5,
+ kHS53PhoneKey5 = 6,
+ kHS53PhoneKey6 = 7,
+ kHS53PhoneKey7 = 8,
+ kHS53PhoneKey8 = 9,
+ kHS53PhoneKey9 = 10,
+ kHS53PhoneKey0 = 11,
+ kHS53PhoneKeySharp = 12,
+ kHS53PhoneKeyStar = 13,
+ kHS53PhoneExit = 14
+};
+
+/*****************************************************************************/
+
+class GnapEngine;
+
+class Scene53: public Scene {
+public:
+ Scene53(GnapEngine *vm);
+ virtual ~Scene53() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations() {};
+ virtual void updateAnimationsCb() {};
+
+private:
+ bool _isGnapPhoning;
+ int _currHandSequenceId;
+ int _callsMadeCtr;
+ uint _callsRndUsed;
+
+ int pressPhoneNumberButton(int phoneNumber, int buttonNum);
+ int getRandomCallIndex();
+ void runRandomCall();
+ void runChitChatLine();
+};
+
+} // End of namespace Gnap
+#endif // GNAP_GROUP5_H
diff --git a/engines/gnap/scenes/groupcs.cpp b/engines/gnap/scenes/groupcs.cpp
new file mode 100644
index 0000000000..c096eae27c
--- /dev/null
+++ b/engines/gnap/scenes/groupcs.cpp
@@ -0,0 +1,430 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/groupcs.h"
+
+
+namespace Gnap {
+
+Scene16::Scene16(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene16::init() {
+ _sequenceIdArr[0] = 0x1F2;
+ _sequenceIdArr[1] = 0x201;
+ _sequenceIdArr[2] = 0x1FC;
+ _sequenceIdArr[3] = 0x1F4;
+ _sequenceIdArr[4] = 0x1FB;
+ _sequenceIdArr[5] = 0x1F0;
+ _sequenceIdArr[6] = 0x1FD;
+ _sequenceIdArr[7] = 0x1FE;
+ _sequenceIdArr[8] = 0x1F7;
+ _sequenceIdArr[9] = 0x1F9;
+ _sequenceIdArr[10] = 0x1F8;
+ _sequenceIdArr[11] = 0x1F1;
+ _sequenceIdArr[12] = 0x202;
+ _sequenceIdArr[13] = 0x1F6;
+ _sequenceIdArr[14] = 0x1F3;
+ _sequenceIdArr[15] = 0x1FA;
+ _sequenceIdArr[16] = 0x1FF;
+ _sequenceIdArr[17] = 0x200;
+ _sequenceIdArr[18] = 0x203;
+ _sequenceIdArr[19] = 0x206;
+ _sequenceIdArr[20] = 0x207;
+ _sequenceIdArr[21] = 0x204;
+ _sequenceIdArr[22] = 0x205;
+ _resourceIdArr[0] = 0x1C;
+ _resourceIdArr[1] = 2;
+ _resourceIdArr[2] = 0x1B;
+ _resourceIdArr[3] = 0;
+ _resourceIdArr[4] = 0x167;
+ _resourceIdArr[5] = 1;
+ _resourceIdArr[6] = 0x15B;
+ _resourceIdArr[7] = 0x15A;
+ _resourceIdArr[8] = 0x170;
+ _resourceIdArr[9] = 0x1EB;
+ _resourceIdArr[10] = 0x1EC;
+ _resourceIdArr[11] = 0x1BE;
+ _resourceIdArr[12] = 0x1BF;
+ _sequenceCountArr[0] = 4;
+ _sequenceCountArr[1] = 1;
+ _sequenceCountArr[2] = 1;
+ _sequenceCountArr[3] = 6;
+ _sequenceCountArr[4] = 1;
+ _sequenceCountArr[5] = 3;
+ _sequenceCountArr[6] = 1;
+ _sequenceCountArr[7] = 1;
+ _sequenceCountArr[8] = 1;
+ _sequenceCountArr[9] = 1;
+ _sequenceCountArr[10] = 1;
+ _sequenceCountArr[11] = 1;
+ _sequenceCountArr[12] = 1;
+ _itemsCount = 13;
+
+ return -1;
+}
+
+/*****************************************************************************/
+
+Scene471::Scene471(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene471::init() {
+ _sequenceIdArr[0] = 0x301;
+ _sequenceIdArr[1] = 0x305;
+ _sequenceIdArr[2] = 0x302;
+ _sequenceIdArr[3] = 0x304;
+ _sequenceIdArr[4] = 0x300;
+ _resourceIdArr[0] = 3;
+ _resourceIdArr[1] = 0;
+ _resourceIdArr[2] = 1;
+ _resourceIdArr[3] = 0;
+ _resourceIdArr[4] = 2;
+ _sequenceCountArr[0] = 1;
+ _sequenceCountArr[1] = 1;
+ _sequenceCountArr[2] = 1;
+ _sequenceCountArr[3] = 1;
+ _sequenceCountArr[4] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _canSkip[2] = false;
+ _canSkip[3] = false;
+ _canSkip[4] = false;
+ _itemsCount = 5;
+
+ return -1;
+}
+
+Scene472::Scene472(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene472::init() {
+ _sequenceIdArr[0] = 0x306;
+ _sequenceIdArr[1] = 0x309;
+ _sequenceIdArr[2] = 0x307;
+ _sequenceIdArr[3] = 0x308;
+ _sequenceIdArr[4] = 0x30A;
+ _resourceIdArr[0] = 0x8E;
+ _resourceIdArr[1] = 0x90;
+ _resourceIdArr[2] = 0x8F;
+ _resourceIdArr[3] = 0x91;
+ _sequenceCountArr[0] = 2;
+ _sequenceCountArr[1] = 1;
+ _sequenceCountArr[2] = 1;
+ _sequenceCountArr[3] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _canSkip[2] = false;
+ _canSkip[3] = false;
+ _itemsCount = 4;
+
+ return -1;
+}
+
+Scene473::Scene473(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene473::init() {
+ _sequenceIdArr[0] = 0x320;
+ _sequenceIdArr[1] = 0x321;
+ _resourceIdArr[0] = 0x142;
+ _resourceIdArr[1] = 0x143;
+ _sequenceCountArr[0] = 1;
+ _sequenceCountArr[1] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _itemsCount = 2;
+
+ return -1;
+}
+
+Scene474::Scene474(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene474::init() {
+ _sequenceIdArr[0] = 0x30C;
+ _sequenceIdArr[1] = 0x30D;
+ _sequenceIdArr[2] = 0x30B;
+ _resourceIdArr[0] = 0x142;
+ _resourceIdArr[1] = 0x141;
+ _resourceIdArr[2] = 0x177;
+ _sequenceCountArr[0] = 1;
+ _sequenceCountArr[1] = 1;
+ _sequenceCountArr[2] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _canSkip[2] = false;
+ _itemsCount = 3;
+
+ return -1;
+}
+
+Scene475::Scene475(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene475::init() {
+ _sequenceIdArr[0] = 0x30E;
+ _sequenceIdArr[1] = 0x30F;
+ _sequenceIdArr[2] = 0x310;
+ _sequenceIdArr[3] = 0x311;
+ _resourceIdArr[0] = 0x206;
+ _resourceIdArr[1] = 0x207;
+ _sequenceCountArr[0] = 3;
+ _sequenceCountArr[1] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _itemsCount = 2;
+
+ return -1;
+}
+
+Scene476::Scene476(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene476::init() {
+ _sequenceIdArr[0] = 0x31E;
+ _sequenceIdArr[1] = 0x31F;
+ _resourceIdArr[0] = 0x2FA;
+ _sequenceCountArr[0] = 2;
+ _canSkip[0] = false;
+ _itemsCount = 1;
+
+ return -1;
+}
+
+Scene477::Scene477(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene477::init() {
+ int v0, v4, v2, v3;
+
+ _sequenceIdArr[0] = 0x316;
+ _sequenceIdArr[1] = 0x31A;
+ _sequenceIdArr[2] = 0x314;
+ _sequenceIdArr[3] = 0x31B;
+ int v1 = 4;
+ if (!_vm->isFlag(kGFTwigTaken)) {
+ _sequenceIdArr[4] = 0x31C;
+ v1 = 5;
+ }
+ if (!_vm->isFlag(kGFPlatypusTalkingToAssistant))
+ _sequenceIdArr[v1++] = 0x31D;
+ v4 = v1;
+ _sequenceIdArr[v1] = 0x319;
+ v0 = v1 + 1;
+ v3 = v0;
+ _sequenceIdArr[v0++] = 0x317;
+ _sequenceIdArr[v0++] = 0x312;
+ _sequenceIdArr[v0] = 0x31A;
+ v2 = v0 + 1;
+ if (!_vm->isFlag(kGFTwigTaken))
+ _sequenceIdArr[v2++] = 0x31C;
+ if (!_vm->isFlag(kGFPlatypusTalkingToAssistant))
+ _sequenceIdArr[v2++] = 0x31D;
+ _sequenceIdArr[v2] = 0x313;
+ _sequenceIdArr[v2 + 1] = 0x315;
+ _resourceIdArr[0] = 0x2B8;
+ _resourceIdArr[1] = 0x20C;
+ _resourceIdArr[2] = 0x2B8;
+ _resourceIdArr[3] = 0x20B;
+ _resourceIdArr[4] = 0x20B;
+ _sequenceCountArr[0] = v4;
+ _sequenceCountArr[1] = 1;
+ _sequenceCountArr[2] = v2 - v3;
+ _sequenceCountArr[3] = 1;
+ _sequenceCountArr[4] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _canSkip[2] = false;
+ _canSkip[3] = false;
+ _canSkip[4] = false;
+ _itemsCount = 5;
+
+ return -1;
+}
+
+/*****************************************************************************/
+
+Scene48::Scene48(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene48::init() {
+ _sequenceIdArr[0] = 390;
+ _sequenceIdArr[1] = 391;
+ _sequenceIdArr[2] = 392;
+ _sequenceIdArr[3] = 393;
+ _sequenceIdArr[4] = 394;
+ _sequenceIdArr[5] = 395;
+ _sequenceIdArr[6] = 396;
+ _sequenceIdArr[7] = 397;
+ _sequenceIdArr[8] = 398;
+ _sequenceIdArr[9] = 399;
+ _sequenceIdArr[10] = 400;
+ _sequenceIdArr[11] = 401;
+ _sequenceIdArr[12] = 402;
+ _resourceIdArr[0] = 238;
+ _resourceIdArr[1] = 42;
+ _resourceIdArr[2] = 2;
+ _resourceIdArr[3] = 37;
+ _resourceIdArr[4] = 35;
+ _resourceIdArr[5] = 38;
+ _resourceIdArr[6] = 39;
+ _resourceIdArr[7] = 40;
+ _resourceIdArr[8] = 41;
+ _resourceIdArr[9] = 36;
+ _resourceIdArr[10] = 41;
+ _resourceIdArr[11] = 388;
+ _resourceIdArr[12] = 387;
+ _sequenceCountArr[0] = 1;
+ _sequenceCountArr[1] = 1;
+ _sequenceCountArr[2] = 1;
+ _sequenceCountArr[3] = 1;
+ _sequenceCountArr[4] = 1;
+ _sequenceCountArr[5] = 1;
+ _sequenceCountArr[6] = 1;
+ _sequenceCountArr[7] = 1;
+ _sequenceCountArr[8] = 1;
+ _sequenceCountArr[9] = 1;
+ _sequenceCountArr[10] = 1;
+ _sequenceCountArr[11] = 1;
+ _sequenceCountArr[12] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _canSkip[2] = false;
+ _canSkip[3] = false;
+ _canSkip[4] = false;
+ _canSkip[5] = false;
+ _canSkip[6] = false;
+ _canSkip[7] = false;
+ _canSkip[8] = false;
+ _canSkip[9] = false;
+ _canSkip[10] = false;
+ _canSkip[11] = false;
+ _canSkip[12] = false;
+ _itemsCount = 13;
+
+ return -1;
+}
+
+/*****************************************************************************/
+
+Scene541::Scene541(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene541::init() {
+ _sequenceIdArr[0] = 0x1BE;
+ _sequenceIdArr[1] = 0x1BF;
+ _sequenceIdArr[2] = 0x1BA;
+ _sequenceIdArr[3] = 0x1BB;
+ _sequenceIdArr[4] = 0x1BD;
+ _sequenceIdArr[5] = 0x1BC;
+ _resourceIdArr[0] = 0x3C;
+ _resourceIdArr[1] = 0x43;
+ _resourceIdArr[2] = 0x44;
+ if (_vm->isFlag(kGFPictureTaken))
+ _resourceIdArr[3] = 0x47;
+ else
+ _resourceIdArr[3] = 0x46;
+ _resourceIdArr[4] = 0x45;
+ _sequenceCountArr[0] = 1;
+ _sequenceCountArr[1] = 1;
+ _sequenceCountArr[2] = 1;
+ _sequenceCountArr[3] = 2;
+ _sequenceCountArr[4] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _canSkip[2] = false;
+ _canSkip[3] = false;
+ _canSkip[4] = false;
+ _itemsCount = 5;
+
+ return -1;
+}
+
+Scene542::Scene542(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene542::init() {
+ _sequenceIdArr[0] = 0x1C9;
+ _sequenceIdArr[1] = 0x1C7;
+ _sequenceIdArr[2] = 0x1CC;
+ _sequenceIdArr[3] = 0x1C8;
+ _sequenceIdArr[4] = 0x1CB;
+ _sequenceIdArr[5] = 0x1C0;
+ _sequenceIdArr[6] = 0x1CA;
+ _sequenceIdArr[7] = 0x1CE;
+ _sequenceIdArr[8] = 0x1CD;
+ _sequenceIdArr[9] = 0x1C1;
+ _sequenceIdArr[10] = 0x1C2;
+ _sequenceIdArr[11] = 0x1C3;
+ _sequenceIdArr[12] = 0x1C4;
+ _sequenceIdArr[13] = 0x1C6;
+ _sequenceIdArr[14] = 0x1C5;
+ _sequenceIdArr[15] = 0x1D0;
+ _sequenceIdArr[16] = 0x1D0;
+ _sequenceIdArr[17] = 0x1D0;
+ _resourceIdArr[0] = 0xD5;
+ _resourceIdArr[1] = 0x14C;
+ _resourceIdArr[2] = 0xD5;
+ _resourceIdArr[3] = 0xBF;
+ _resourceIdArr[4] = 0xD6;
+ _resourceIdArr[5] = 0x154;
+ _resourceIdArr[6] = 0x155;
+ _resourceIdArr[7] = 0xB9;
+ _resourceIdArr[8] = 0xBA;
+ _resourceIdArr[9] = 0x17B;
+ _resourceIdArr[10] = 0x17A;
+ _resourceIdArr[11] = 0x17C;
+ _resourceIdArr[12] = 0x17A;
+ _resourceIdArr[13] = 0x1B7;
+ _resourceIdArr[14] = 0x1B8;
+ _resourceIdArr[15] = 0x1B9;
+ _sequenceCountArr[0] = 2;
+ _sequenceCountArr[1] = 1;
+ _sequenceCountArr[2] = 2;
+ _sequenceCountArr[3] = 1;
+ _sequenceCountArr[4] = 1;
+ _sequenceCountArr[5] = 1;
+ _sequenceCountArr[6] = 1;
+ _sequenceCountArr[7] = 1;
+ _sequenceCountArr[8] = 1;
+ _sequenceCountArr[9] = 1;
+ _sequenceCountArr[10] = 1;
+ _sequenceCountArr[11] = 1;
+ _sequenceCountArr[12] = 1;
+ _sequenceCountArr[13] = 1;
+ _sequenceCountArr[14] = 1;
+ _sequenceCountArr[15] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _canSkip[2] = false;
+ _canSkip[3] = false;
+ _canSkip[4] = false;
+ _canSkip[5] = false;
+ _canSkip[6] = false;
+ _canSkip[7] = false;
+ _canSkip[8] = false;
+ _canSkip[9] = false;
+ _canSkip[10] = false;
+ _canSkip[11] = false;
+ _canSkip[12] = false;
+ _canSkip[13] = true;
+ _canSkip[14] = true;
+ _canSkip[15] = false;
+ _itemsCount = 16;
+
+ return -1;
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/groupcs.h b/engines/gnap/scenes/groupcs.h
new file mode 100644
index 0000000000..58033564ce
--- /dev/null
+++ b/engines/gnap/scenes/groupcs.h
@@ -0,0 +1,122 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 GNAP_GROUPCS_H
+#define GNAP_GROUPCS_H
+
+#include "gnap/debugger.h"
+
+namespace Gnap {
+
+class GnapEngine;
+class CutScene;
+
+class Scene16: public CutScene {
+public:
+ Scene16(GnapEngine *vm);
+ virtual ~Scene16() {}
+
+ virtual int init();
+};
+
+class Scene471: public CutScene {
+public:
+ Scene471(GnapEngine *vm);
+ virtual ~Scene471() {}
+
+ virtual int init();
+};
+
+class Scene472: public CutScene {
+public:
+ Scene472(GnapEngine *vm);
+ virtual ~Scene472() {}
+
+ virtual int init();
+};
+
+class Scene473: public CutScene {
+public:
+ Scene473(GnapEngine *vm);
+ virtual ~Scene473() {}
+
+ virtual int init();
+};
+
+class Scene474: public CutScene {
+public:
+ Scene474(GnapEngine *vm);
+ virtual ~Scene474() {}
+
+ virtual int init();
+};
+
+class Scene475: public CutScene {
+public:
+ Scene475(GnapEngine *vm);
+ virtual ~Scene475() {}
+
+ virtual int init();
+};
+
+class Scene476: public CutScene {
+public:
+ Scene476(GnapEngine *vm);
+ virtual ~Scene476() {}
+
+ virtual int init();
+};
+
+class Scene477: public CutScene {
+public:
+ Scene477(GnapEngine *vm);
+ virtual ~Scene477() {}
+
+ virtual int init();
+};
+
+class Scene48: public CutScene {
+public:
+ Scene48(GnapEngine *vm);
+ virtual ~Scene48() {}
+
+ virtual int init();
+};
+
+class Scene541: public CutScene {
+public:
+ Scene541(GnapEngine *vm);
+ virtual ~Scene541() {}
+
+ virtual int init();
+};
+
+class Scene542: public CutScene {
+public:
+ Scene542(GnapEngine *vm);
+ virtual ~Scene542() {}
+
+ virtual int init();
+};
+} // End of namespace Gnap
+
+#endif // GNAP_GROUPCS_H
diff --git a/engines/gnap/scenes/intro.cpp b/engines/gnap/scenes/intro.cpp
new file mode 100644
index 0000000000..b4ba2f5201
--- /dev/null
+++ b/engines/gnap/scenes/intro.cpp
@@ -0,0 +1,182 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "video/avi_decoder.h"
+
+#include "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/intro.h"
+
+namespace Gnap {
+
+SceneIntro::SceneIntro(GnapEngine *vm) : Scene(vm) {
+}
+
+int SceneIntro::init() {
+ return 0x37C;
+}
+
+void SceneIntro::run() {
+ const int animIdArr[] = {
+ 0x356, 0x357, 0x358, 0x35A, 0x35F,
+ 0x360, 0x361, 0x362, 0x363, 0x364,
+ 0x365, 0x368, 0x369, 0x36B, 0x378,
+ 0x36C, 0x36D, 0x36E, 0x36F, 0x370,
+ 0x371, 0x372, 0x373, 0x374, 0x375,
+ 0x376, 0x377, 0x378, 0x379, 0x37A,
+ 0x37B, 0};
+
+ const int backgroundIdArr[] = {
+ 0x354, 0x355, 0, 1, 3,
+ 4, 5, 6, 7, 8,
+ 7, 9, 0xA, 0xB, 0xC,
+ 0xD, 0xE, 0xF, 0x10, 0x11,
+ 0x12, 0x13, 0x17, 0x14, 0x19,
+ 0x1A, 0x14, 0x15, 0x16, 0x14,
+ 0x19, 0};
+
+ GameSys& gameSys = *_vm->_gameSys;
+ int index = 0;
+ bool skip = false;
+
+ _vm->hideCursor();
+ _vm->_dat->open(1, "musop_n.dat");
+
+ Video::VideoDecoder *videoDecoder = new Video::AVIDecoder();
+ if (!videoDecoder->loadFile("hoffman.avi")) {
+ delete videoDecoder;
+ warning("Unable to open video 'hoffman.avi' - Skipping intro");
+ return;
+ }
+ videoDecoder->start();
+
+ int vidPosX = (800 - videoDecoder->getWidth()) / 2;
+ int vidPosY = (600 - videoDecoder->getHeight()) / 2;
+ bool skipVideo = false;
+
+ _vm->screenEffect(1, 255, 255, 255);
+
+ while (!_vm->shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) {
+ if (videoDecoder->needsUpdate()) {
+ const Graphics::Surface *frame = videoDecoder->decodeNextFrame();
+ if (frame) {
+ if (frame->format.bytesPerPixel == 1) {
+ _vm->_system->copyRectToScreen(frame->getPixels(), frame->pitch, vidPosX, vidPosY, frame->w, frame->h);
+ } else if (frame->format.bytesPerPixel != 4) {
+ Graphics::Surface *frame1 = frame->convertTo(_vm->_system->getScreenFormat());
+ _vm->_system->copyRectToScreen(frame1->getPixels(), frame1->pitch, vidPosX, vidPosY, frame1->w, frame1->h);
+ frame1->free();
+ delete frame1;
+ } else {
+ // The intro AVI is played upside down, it's the only video played in the English version
+ for (uint16 y = 0; y < frame->h / 2; y++) {
+ uint32 *ptrFrom = (uint32 *)frame->getBasePtr(0, y);
+ uint32 *ptrTo = (uint32 *)frame->getBasePtr(0, frame->h - y - 1);
+ for (uint16 x = 0; x < frame->w; x++) {
+ uint32 t = *ptrFrom;
+ *ptrFrom = *ptrTo;
+ *ptrTo = t;
+ ptrFrom++;
+ ptrTo++;
+ }
+ }
+
+ Graphics::Surface *frame1 = frame->convertTo(_vm->_system->getScreenFormat());
+ _vm->_system->copyRectToScreen(frame1->getPixels(), frame1->pitch, vidPosX, vidPosY, frame1->w, frame1->h);
+ frame1->free();
+ delete frame1;
+ }
+ _vm->_system->updateScreen();
+ }
+ }
+
+ Common::Event event;
+ while (g_system->getEventManager()->pollEvent(event)) {
+ if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) ||
+ event.type == Common::EVENT_LBUTTONUP)
+ skipVideo = true;
+ }
+
+ _vm->_system->delayMillis(10);
+ }
+
+ delete videoDecoder;
+
+ gameSys.drawSpriteToBackground(0, 0, backgroundIdArr[index]);
+ gameSys.insertSequence(0x356, 2, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(0x356, 2, 0);
+
+ while (!_vm->_sceneDone) {
+ _vm->gameUpdateTick();
+
+ if (gameSys.getAnimationStatus(0) == 2 || skip ) {
+ skip = false;
+ gameSys.requestClear2(false);
+ gameSys.requestClear1();
+ if ( index == 11 || index == 1 )
+ _vm->screenEffect(0, 0, 0, 0);
+
+ gameSys.setAnimation(0, 0, 0);
+ if (++index >= 31)
+ _vm->_sceneDone = true;
+ else {
+ gameSys.insertSequence(animIdArr[index], 2, 0, 0, kSeqNone, 0, 0, 0);
+ if (index == 2) {
+ _vm->playSound(0x10000, false);
+ gameSys.insertSequence(0x359, 2, 0, 0, 0, 0, 0, 0);
+ } else if (index == 3)
+ gameSys.insertSequence(0x35B, 2, 0, 0, kSeqNone, 0, 0, 0);
+ else if (index == 12)
+ gameSys.insertSequence(0x36A, 2, 0, 0, kSeqNone, 0, 0, 0);
+
+ gameSys.drawSpriteToBackground(0, 0, backgroundIdArr[index]);
+ gameSys.setAnimation(animIdArr[index], 2, 0);
+
+ if (index == 11)
+ _vm->stopSound(0x10000);
+ }
+ }
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_ESCAPE) || _vm->isKeyStatus1(Common::KEYCODE_SPACE) || _vm->isKeyStatus1(Common::KEYCODE_RETURN)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ _vm->clearKeyStatus1(Common::KEYCODE_RETURN);
+ if (index == 0) {
+ skip = true;
+ _vm->stopSound(0x3CF);
+ } else if (index == 1)
+ skip = true;
+ else
+ _vm->_sceneDone = true;
+ }
+ }
+
+ _vm->stopSound(0x10000);
+
+ _vm->_newSceneNum = 1;
+ _vm->_newCursorValue = 1;
+
+ _vm->_dat->open(1, "stock_n.dat");
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/intro.h b/engines/gnap/scenes/intro.h
new file mode 100644
index 0000000000..15aedfc4fc
--- /dev/null
+++ b/engines/gnap/scenes/intro.h
@@ -0,0 +1,47 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GNAP_INTRO_H
+#define GNAP_INTRO_H
+
+#include "gnap/debugger.h"
+#include "gnap/scenes/scenecore.h"
+
+namespace Gnap {
+
+class GnapEngine;
+
+class SceneIntro: public Scene {
+public:
+ SceneIntro(GnapEngine *vm);
+ virtual ~SceneIntro() {}
+
+ virtual int init();
+ virtual void updateHotspots() {}
+ virtual void run();
+ virtual void updateAnimations() {}
+ virtual void updateAnimationsCb() {}
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_INTRO_H
diff --git a/engines/gnap/scenes/scenecore.cpp b/engines/gnap/scenes/scenecore.cpp
new file mode 100644
index 0000000000..fb6f91c954
--- /dev/null
+++ b/engines/gnap/scenes/scenecore.cpp
@@ -0,0 +1,740 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public 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 "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+
+#include "gnap/scenes/scenecore.h"
+
+#include "gnap/scenes/arcade.h"
+#include "gnap/scenes/groupcs.h"
+#include "gnap/scenes/group0.h"
+#include "gnap/scenes/group1.h"
+#include "gnap/scenes/group2.h"
+#include "gnap/scenes/group3.h"
+#include "gnap/scenes/group4.h"
+#include "gnap/scenes/group5.h"
+#include "gnap/scenes/intro.h"
+
+namespace Gnap {
+
+int GnapEngine::initSceneLogic() {
+ int backgroundId = -1;
+
+ switch (_currentSceneNum) {
+ case 0:
+ _scene = new SceneIntro(this);
+ backgroundId = _scene->init();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ break;
+ case 1:
+ _scene = new Scene01(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 2:
+ _scene = new Scene02(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 3:
+ _scene = new Scene03(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 4:
+ _scene = new Scene04(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 5:
+ _scene = new Scene05(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 6:
+ _scene = new Scene06(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 7:
+ _scene = new Scene07(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 8:
+ _scene = new Scene08(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 9:
+ _scene = new Scene09(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 10:
+ _scene = new Scene10(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 11:
+ _scene = new Scene11(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 12:
+ _scene = new Scene12(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 13:
+ _scene = new Scene13(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 14:
+ _scene = new Scene14(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ break;
+ case 15:
+ _scene = new Scene15(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ break;
+ case 16:
+ case 47:
+ case 48:
+ case 54:
+ backgroundId = -1;
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ break;
+ case 17:
+ _scene = new Scene17(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 18:
+ _scene = new Scene18(this);
+ backgroundId = _scene->init();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ _scene->updateHotspots();
+ break;
+ case 19:
+ _scene = new Scene19(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 20:
+ _scene = new Scene20(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 21:
+ _scene = new Scene21(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 22:
+ _scene = new Scene22(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 23:
+ _scene = new Scene23(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 24:
+ _scene = new Scene24(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 136, 11, 10);
+ break;
+ case 25:
+ _scene = new Scene25(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 26:
+ _scene = new Scene26(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 27:
+ _scene = new Scene27(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 28:
+ _scene = new Scene28(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 29:
+ _scene = new Scene29(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 30:
+ _scene = new Scene30(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 31:
+ _scene = new Scene31(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 32:
+ _scene = new Scene32(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 33:
+ _scene = new Scene33(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 34:
+ _scene = new Scene03(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 35:
+ _scene = new Scene05(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 36:
+ _scene = new Scene06(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 37:
+ _scene = new Scene04(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 38:
+ _scene = new Scene38(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 39:
+ _scene = new Scene39(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 40:
+ _scene = new Scene40(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 41:
+ _scene = new Scene41(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 42:
+ _scene = new Scene42(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 43:
+ _scene = new Scene43(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 44:
+ _scene = new Scene44(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 45:
+ _scene = new Scene45(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 46:
+ _scene = new Scene46(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 49:
+ _scene = new Scene49(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 50:
+ _scene = new Scene50(this);
+ backgroundId = _scene->init();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 51:
+ _scene = new Scene51(this);
+ backgroundId = _scene->init();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 52:
+ _scene = new Scene52(this);
+ backgroundId = _scene->init();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 53:
+ _scene = new Scene53(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ }
+
+ return backgroundId;
+}
+
+void GnapEngine::runSceneLogic() {
+ switch (_currentSceneNum) {
+ case 0:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 8;
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 4;
+ break;
+ case 7:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 8;
+ break;
+ case 8:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 9;
+ break;
+ case 9:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 10;
+ break;
+ case 10:
+ case 12:
+ case 13:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 11;
+ break;
+ case 11:
+ case 15:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 12;
+ break;
+ case 14:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 13;
+ break;
+ case 16:
+ _scene = new Scene16(this);
+ _scene->init();
+ _newSceneNum = 17;
+ _newCursorValue = 3;
+ _scene->run();
+ delete _scene;
+ break;
+ case 17:
+ case 18:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 20;
+ break;
+ case 19:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 19;
+ break;
+ case 20:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 22;
+ break;
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ case 38:
+ case 39:
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 37;
+ break;
+ case 47:
+ if (_prevSceneNum == 49) {
+ _scene = new Scene471(this);
+ _scene->init();
+ _newSceneNum = 7;
+ _newCursorValue = 2;
+ } else if (_prevSceneNum == 13) {
+ _scene = new Scene472(this);
+ _scene->init();
+ _newSceneNum = 11;
+ } else if (!isFlag(kGFPlatypusDisguised) && _prevSceneNum == 2) {//CHECKME
+ if (isFlag(kGFUnk25)) {
+ _scene = new Scene473(this);
+ _scene->init();
+ _newSceneNum = 2;
+ } else {
+ _scene = new Scene474(this);
+ _scene->init();
+ _newSceneNum = 49;
+ }
+ } else if (_prevSceneNum == 21) {
+ _scene = new Scene475(this);
+ _scene->init();
+ _newSceneNum = 21;
+ setFlag(kGFTwigTaken);
+ setFlag(kGFKeysTaken);
+ } else if (_prevSceneNum == 30) {
+ _scene = new Scene476(this);
+ _scene->init();
+ _newSceneNum = 26;
+ } else if (isFlag(kGFPlatypusDisguised) && _cursorValue == 1) {
+ _scene = new Scene477(this);
+ _scene->init();
+ _newSceneNum = 4;
+ }
+ _scene->run();
+ delete _scene;
+ break;
+ case 48:
+ _scene = new Scene48(this);
+ _scene->init();
+ _newSceneNum = 33;
+ _newCursorValue = 4;
+ _scene->run();
+ delete _scene;
+ break;
+ case 49:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 47;
+ break;
+ case 50:
+ _scene->run();
+ delete _scene;
+ _newSceneNum = _prevSceneNum;
+ break;
+ case 51:
+ _scene->run();
+ delete _scene;
+ break;
+ case 52:
+ _scene->run();
+ delete _scene;
+ _newSceneNum = _prevSceneNum;
+ break;
+ case 53:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 53;
+ break;
+ case 54:
+ if (_prevSceneNum == 45) {
+ _scene = new Scene541(this);
+ _scene->init();
+ _newSceneNum = 43;
+ _scene->run();
+ delete _scene;
+ } else {
+ _scene = new Scene542(this);
+ _scene->init();
+ _scene->run();
+ delete _scene;
+ _gameDone = true;
+ }
+ break;
+ }
+}
+
+void Scene::playRandomSound(int timerIndex) {
+ if (!_vm->_timers[timerIndex]) {
+ _vm->_timers[timerIndex] = _vm->getRandom(40) + 50;
+ switch (_vm->getRandom(4)) {
+ case 0:
+ _vm->playSound(0x1091B, false);
+ break;
+ case 1:
+ _vm->playSound(0x10921, false);
+ break;
+ case 2:
+ _vm->playSound(0x10927, false);
+ break;
+ case 3:
+ _vm->playSound(0x1091D, false);
+ break;
+ }
+ }
+}
+
+bool Scene::clearKeyStatus() {
+ if (_vm->isKeyStatus1(Common::KEYCODE_ESCAPE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _vm->clearKeyStatus1(Common::KEYCODE_UP);
+ _vm->clearKeyStatus1(Common::KEYCODE_RIGHT);
+ _vm->clearKeyStatus1(Common::KEYCODE_LEFT);
+ _vm->clearKeyStatus1(Common::KEYCODE_p);
+ return true;
+ }
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_p)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_p);
+ _vm->pauseGame();
+ _vm->updatePause();
+ }
+
+ return false;
+}
+
+/****************************************************************************/
+
+CutScene::CutScene(GnapEngine *vm) : Scene(vm) {
+ _itemsCount = -1;
+
+ for (int i = 0; i < 16; i++) {
+ _resourceIdArr[i] = -1;
+ _sequenceCountArr[i] = -1;
+ _canSkip[i] = false;
+ }
+
+ for (int i = 0; i < 50; i++)
+ _sequenceIdArr[i] = -1;
+}
+
+void CutScene::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ int itemIndex = 0;
+ int soundId = -1;
+ int volume = 100;
+ int duration = 0;
+ bool skip = false;
+
+ if (_vm->_prevSceneNum == 2) {
+ soundId = 0x36B;
+ duration = MAX(1, 300 / _vm->getSequenceTotalDuration(_sequenceIdArr[_itemsCount - 1]));
+ _vm->_timers[0] = 0;
+ }
+
+ if (soundId != -1)
+ _vm->playSound(soundId, false);
+
+ _vm->hideCursor();
+
+ gameSys.drawSpriteToBackground(0, 0, _resourceIdArr[0]);
+
+ for (int j = 0; j < _sequenceCountArr[0]; ++j)
+ gameSys.insertSequence(_sequenceIdArr[j], j + 2, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(_sequenceIdArr[0], 2, 0);
+
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ _vm->clearKeyStatus1(Common::KEYCODE_RETURN);
+
+ _vm->_mouseClickState._left = false;
+
+ int firstSequenceIndex = 0;
+ while (!_vm->_sceneDone) {
+ _vm->gameUpdateTick();
+
+ if (gameSys.getAnimationStatus(0) == 2 || skip) {
+ skip = false;
+ gameSys.requestClear2(false);
+ gameSys.requestClear1();
+ gameSys.setAnimation(0, 0, 0);
+ firstSequenceIndex += _sequenceCountArr[itemIndex++];
+ if (itemIndex >= _itemsCount) {
+ _vm->_sceneDone = true;
+ } else {
+ for (int m = 0; m < _sequenceCountArr[itemIndex]; ++m)
+ gameSys.insertSequence(_sequenceIdArr[firstSequenceIndex + m], m + 2, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.drawSpriteToBackground(0, 0, _resourceIdArr[itemIndex]);
+ gameSys.setAnimation(_sequenceIdArr[firstSequenceIndex], 2, 0);
+ }
+ }
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_ESCAPE) || _vm->isKeyStatus1(Common::KEYCODE_SPACE) || _vm->isKeyStatus1(Common::KEYCODE_RETURN)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ _vm->clearKeyStatus1(Common::KEYCODE_RETURN);
+ if (_canSkip[itemIndex])
+ skip = true;
+ else
+ _vm->_sceneDone = true;
+ }
+
+ if (!_vm->_timers[0] && itemIndex == _itemsCount - 1) {
+ _vm->_timers[0] = 2;
+ volume = MAX(1, volume - duration);
+ _vm->setSoundVolume(soundId, volume);
+ }
+ }
+
+ if (soundId != -1)
+ _vm->stopSound(soundId);
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/scenecore.h b/engines/gnap/scenes/scenecore.h
new file mode 100644
index 0000000000..c54b5a7bc5
--- /dev/null
+++ b/engines/gnap/scenes/scenecore.h
@@ -0,0 +1,70 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GNAP_SCENECORE_H
+#define GNAP_SCENECORE_H
+
+#include "gnap/debugger.h"
+
+namespace Gnap {
+
+class GnapEngine;
+
+class Scene {
+public:
+ Scene(GnapEngine *vm) : _vm(vm) {};
+ virtual ~Scene() {};
+
+ void playRandomSound(int timerIndex);
+ bool clearKeyStatus();
+
+ virtual int init() = 0;
+ virtual void updateHotspots() = 0;
+ virtual void run() = 0;
+ virtual void updateAnimations() = 0;
+ virtual void updateAnimationsCb() = 0;
+
+protected:
+ GnapEngine *_vm;
+};
+
+class CutScene : public Scene {
+public:
+ CutScene(GnapEngine *vm);
+ virtual ~CutScene() {};
+
+ virtual int init() = 0;
+ void updateHotspots() {}
+ void run();
+ void updateAnimations() {}
+ void updateAnimationsCb() {}
+
+protected:
+ int _itemsCount;
+ int _resourceIdArr[16];
+ int _sequenceCountArr[16];
+ int _sequenceIdArr[50];
+ bool _canSkip[16];
+};
+} // End of namespace Gnap
+
+#endif // GNAP_SCENECORE_H
diff --git a/engines/gnap/sound.cpp b/engines/gnap/sound.cpp
new file mode 100644
index 0000000000..75cfb5555c
--- /dev/null
+++ b/engines/gnap/sound.cpp
@@ -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.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "gnap/sound.h"
+#include "audio/audiostream.h"
+#include "audio/decoders/wave.h"
+
+namespace Gnap {
+
+SoundMan::SoundMan(GnapEngine *vm)
+ : _vm(vm) {
+}
+
+SoundMan::~SoundMan() {
+}
+
+void SoundMan::playSound(int resourceId, bool looping) {
+ SoundItem soundItem;
+ soundItem._resourceId = resourceId;
+
+ SoundResource *soundResource = _vm->_soundCache->get(resourceId);
+ Common::MemoryReadStream *stream = new Common::MemoryReadStream(soundResource->_data, soundResource->_size, DisposeAfterUse::NO);
+ Audio::AudioStream *audioStream = Audio::makeLoopingAudioStream(Audio::makeWAVStream(stream, DisposeAfterUse::YES), looping ? 0 : 1);
+
+ _vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &soundItem._handle, audioStream);
+
+ _items.push_back(soundItem);
+
+}
+
+void SoundMan::stopSound(int resourceId) {
+ const int index = find(resourceId);
+ if (index >= 0) {
+ _vm->_soundCache->release(_items[index]._resourceId);
+ _vm->_mixer->stopHandle(_items[index]._handle);
+ _items.remove_at(index);
+ }
+}
+
+void SoundMan::setSoundVolume(int resourceId, int volume) {
+ if (resourceId == -1 || volume < 0 || volume > 100)
+ return;
+
+ const int index = find(resourceId);
+ int realVol = volume * 2.55;
+ _vm->_mixer->setChannelVolume(_items[index]._handle, realVol);
+}
+
+bool SoundMan::isSoundPlaying(int resourceId) {
+ const int index = find(resourceId);
+ return index >= 0 && _vm->_mixer->isSoundHandleActive(_items[index]._handle);
+}
+
+void SoundMan::stopAll() {
+ for (int index = 0; index < (int)_items.size(); ++index) {
+ _vm->_soundCache->release(_items[index]._resourceId);
+ _vm->_mixer->stopHandle(_items[index]._handle);
+ }
+}
+
+void SoundMan::update() {
+ for (int index = 0; index < (int)_items.size(); ++index)
+ if (!_vm->_mixer->isSoundHandleActive(_items[index]._handle)) {
+ _vm->_soundCache->release(_items[index]._resourceId);
+ _items.remove_at(index);
+ --index;
+ }
+}
+
+int SoundMan::find(int resourceId) {
+ for (int index = 0; index < (int)_items.size(); ++index)
+ if (_items[index]._resourceId == resourceId)
+ return index;
+ return -1;
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/sound.h b/engines/gnap/sound.h
new file mode 100644
index 0000000000..de3981245d
--- /dev/null
+++ b/engines/gnap/sound.h
@@ -0,0 +1,57 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GNAP_SOUND_H
+#define GNAP_SOUND_H
+
+#include "gnap/gnap.h"
+#include "gnap/resource.h"
+#include "audio/mixer.h"
+#include "common/array.h"
+
+namespace Gnap {
+
+struct SoundItem {
+ int _resourceId;
+ Audio::SoundHandle _handle;
+};
+
+class SoundMan {
+public:
+ SoundMan(GnapEngine *vm);
+ ~SoundMan();
+ void playSound(int resourceId, bool looping);
+ void stopSound(int resourceId);
+ void setSoundVolume(int resourceId, int volume);
+ bool isSoundPlaying(int resourceId);
+ void stopAll();
+ void update();
+protected:
+ GnapEngine *_vm;
+ Common::Array<SoundItem> _items;
+
+ int find(int resourceId);
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_SOUND_H
diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp
index d995f26d9f..b51a6382e6 100644
--- a/engines/gob/gob.cpp
+++ b/engines/gob/gob.cpp
@@ -26,6 +26,7 @@
#include "base/plugins.h"
#include "common/config-manager.h"
#include "audio/mididrv.h"
+#include "audio/mixer.h"
#include "gui/gui-manager.h"
#include "gui/dialog.h"
diff --git a/engines/gob/inter_playtoons.cpp b/engines/gob/inter_playtoons.cpp
index 45f573efcd..13d24dc05d 100644
--- a/engines/gob/inter_playtoons.cpp
+++ b/engines/gob/inter_playtoons.cpp
@@ -41,7 +41,6 @@
#include "gob/video.h"
#include "gob/videoplayer.h"
#include "gob/save/saveload.h"
-#include "gob/sound/sound.h"
namespace Gob {
diff --git a/engines/gob/inter_v4.cpp b/engines/gob/inter_v4.cpp
index 656ca6f5c3..d379d5ab11 100644
--- a/engines/gob/inter_v4.cpp
+++ b/engines/gob/inter_v4.cpp
@@ -205,7 +205,7 @@ void Inter_v4::o4_playVmdOrMusic() {
return;
} else if (props.lastFrame == -9) {
_vm->_sound->bgStop();
- _vm->_sound->bgSetPlayMode(BackgroundAtmosphere::kPlayModeRandom);
+ _vm->_sound->bgSetPlayMode(Sound::kPlayModeRandom);
_vm->_sound->bgPlay(file.c_str(), "SND", SOUND_SND, props.palStart);
return;
} else if (props.lastFrame < 0) {
diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index a6e4da75e7..50910e77bd 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -30,8 +30,6 @@
#include "gob/anifile.h"
#include "gob/aniobject.h"
-#include "gob/sound/sound.h"
-
#include "gob/pregob/txtfile.h"
#include "gob/pregob/gctfile.h"
diff --git a/engines/gob/pregob/pregob.h b/engines/gob/pregob/pregob.h
index 021cf2b3d6..108771a63a 100644
--- a/engines/gob/pregob/pregob.h
+++ b/engines/gob/pregob/pregob.h
@@ -29,14 +29,14 @@
#include "gob/util.h"
#include "gob/aniobject.h"
-#include "gob/sound/sounddesc.h"
-
#include "gob/pregob/txtfile.h"
namespace Gob {
class GobEngine;
+class ANIFile;
class Surface;
+class SoundDesc;
class GCTFile;
diff --git a/engines/gob/sound/bgatmosphere.cpp b/engines/gob/sound/bgatmosphere.cpp
index 21fb70278a..c7be1be96a 100644
--- a/engines/gob/sound/bgatmosphere.cpp
+++ b/engines/gob/sound/bgatmosphere.cpp
@@ -23,6 +23,7 @@
#include "common/array.h"
#include "gob/sound/bgatmosphere.h"
+#include "gob/sound/sound.h"
#include "gob/sound/sounddesc.h"
namespace Gob {
@@ -30,7 +31,7 @@ namespace Gob {
BackgroundAtmosphere::BackgroundAtmosphere(Audio::Mixer &mixer) :
SoundMixer(mixer, Audio::Mixer::kMusicSoundType), _rnd("gobBA") {
- _playMode = kPlayModeLinear;
+ _playMode = Sound::kPlayModeLinear;
_queuePos = -1;
_shaded = false;
_shadable = true;
@@ -56,7 +57,7 @@ void BackgroundAtmosphere::stopBA() {
SoundMixer::stop(0);
}
-void BackgroundAtmosphere::setPlayMode(PlayMode mode) {
+void BackgroundAtmosphere::setPlayMode(Sound::BackgroundPlayMode mode) {
_playMode = mode;
}
@@ -100,11 +101,11 @@ void BackgroundAtmosphere::getNextQueuePos() {
switch (_playMode) {
- case kPlayModeLinear:
+ case Sound::kPlayModeLinear:
_queuePos = (_queuePos + 1) % _queue.size();
break;
- case kPlayModeRandom:
+ case Sound::kPlayModeRandom:
_queuePos = _rnd.getRandomNumber(_queue.size() - 1);
break;
diff --git a/engines/gob/sound/bgatmosphere.h b/engines/gob/sound/bgatmosphere.h
index c838a2c2bb..138b65a1c1 100644
--- a/engines/gob/sound/bgatmosphere.h
+++ b/engines/gob/sound/bgatmosphere.h
@@ -27,6 +27,7 @@
#include "common/mutex.h"
#include "common/random.h"
+#include "gob/sound/sound.h"
#include "gob/sound/soundmixer.h"
namespace Audio {
@@ -39,18 +40,13 @@ class SoundDesc;
class BackgroundAtmosphere : private SoundMixer {
public:
- enum PlayMode {
- kPlayModeLinear,
- kPlayModeRandom
- };
-
BackgroundAtmosphere(Audio::Mixer &mixer);
~BackgroundAtmosphere();
void playBA();
void stopBA();
- void setPlayMode(PlayMode mode);
+ void setPlayMode(Sound::BackgroundPlayMode mode);
void queueSample(SoundDesc &sndDesc);
void queueClear();
@@ -60,7 +56,7 @@ public:
void unshade();
private:
- PlayMode _playMode;
+ Sound::BackgroundPlayMode _playMode;
Common::Array<SoundDesc *> _queue;
int _queuePos;
diff --git a/engines/gob/sound/sound.cpp b/engines/gob/sound/sound.cpp
index 22dfe9d3c3..000eafa031 100644
--- a/engines/gob/sound/sound.cpp
+++ b/engines/gob/sound/sound.cpp
@@ -28,6 +28,7 @@
#include "gob/game.h"
#include "gob/inter.h"
+#include "gob/sound/bgatmosphere.h"
#include "gob/sound/pcspeaker.h"
#include "gob/sound/soundblaster.h"
#include "gob/sound/adlplayer.h"
@@ -717,7 +718,7 @@ void Sound::bgStop() {
_bgatmos->queueClear();
}
-void Sound::bgSetPlayMode(BackgroundAtmosphere::PlayMode mode) {
+void Sound::bgSetPlayMode(Sound::BackgroundPlayMode mode) {
if (!_bgatmos)
return;
diff --git a/engines/gob/sound/sound.h b/engines/gob/sound/sound.h
index 6ebc323b18..f1fd46d24b 100644
--- a/engines/gob/sound/sound.h
+++ b/engines/gob/sound/sound.h
@@ -23,12 +23,13 @@
#ifndef GOB_SOUND_SOUND_H
#define GOB_SOUND_SOUND_H
+#include "common/str.h"
#include "gob/sound/sounddesc.h"
-#include "gob/sound/bgatmosphere.h"
namespace Gob {
class GobEngine;
+class BackgroundAtmosphere;
class PCSpeaker;
class SoundBlaster;
class ADLPlayer;
@@ -39,6 +40,11 @@ class CDROM;
class Sound {
public:
+ enum BackgroundPlayMode {
+ kPlayModeLinear,
+ kPlayModeRandom
+ };
+
static const int kSoundsCount = 60;
Sound(GobEngine *vm);
@@ -135,7 +141,7 @@ public:
void bgPlay(const char *base, const char *ext, SoundType type, int count);
void bgStop();
- void bgSetPlayMode(BackgroundAtmosphere::PlayMode mode);
+ void bgSetPlayMode(BackgroundPlayMode mode);
void bgShade();
void bgUnshade();
diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp
index e97848d27e..bbf4ef4162 100644
--- a/engines/gob/videoplayer.cpp
+++ b/engines/gob/videoplayer.cpp
@@ -21,6 +21,8 @@
*/
+#include "video/coktel_decoder.h"
+
#include "gob/videoplayer.h"
#include "gob/global.h"
#include "gob/dataio.h"
diff --git a/engines/gob/videoplayer.h b/engines/gob/videoplayer.h
index 02ed510ec5..1c39ecf2fa 100644
--- a/engines/gob/videoplayer.h
+++ b/engines/gob/videoplayer.h
@@ -29,11 +29,14 @@
#include "common/str.h"
#include "graphics/surface.h"
-#include "video/coktel_decoder.h"
#include "gob/util.h"
#include "gob/draw.h"
+namespace Video {
+class CoktelDecoder;
+}
+
namespace Gob {
class GobEngine;
diff --git a/engines/groovie/cell.cpp b/engines/groovie/cell.cpp
index 24fac17e44..5fceb8f74e 100644
--- a/engines/groovie/cell.cpp
+++ b/engines/groovie/cell.cpp
@@ -30,6 +30,7 @@ CellGame::CellGame() {
_stack_index = _boardStackPtr = 0;
_flag4 = false;
_flag2 = false;
+ _flag1 = false;
_coeff3 = 0;
_moveCount = 0;
diff --git a/engines/groovie/cursor.cpp b/engines/groovie/cursor.cpp
index 442f0bfada..d56698095f 100644
--- a/engines/groovie/cursor.cpp
+++ b/engines/groovie/cursor.cpp
@@ -35,7 +35,7 @@ namespace Groovie {
// Cursor Manager
GrvCursorMan::GrvCursorMan(OSystem *system) :
- _syst(system), _lastTime(0), _current(255), _cursor(NULL) {
+ _syst(system), _lastTime(0), _current(255), _cursor(NULL), _lastFrame(0) {
}
GrvCursorMan::~GrvCursorMan() {
diff --git a/engines/groovie/font.h b/engines/groovie/font.h
index 23e060faf3..5c479b6919 100644
--- a/engines/groovie/font.h
+++ b/engines/groovie/font.h
@@ -44,7 +44,7 @@ private:
int _maxHeight, _maxWidth;
struct Glyph {
- Glyph() : pixels(0) {}
+ Glyph() : pixels(0), width(0), height(0), julia(0) {}
~Glyph() { delete[] pixels; }
byte width;
diff --git a/engines/groovie/graphics.cpp b/engines/groovie/graphics.cpp
index e0c198f377..45956416cd 100644
--- a/engines/groovie/graphics.cpp
+++ b/engines/groovie/graphics.cpp
@@ -31,7 +31,7 @@
namespace Groovie {
GraphicsMan::GraphicsMan(GroovieEngine *vm) :
- _vm(vm), _changed(false), _fading(0) {
+ _vm(vm), _changed(false), _fading(0), _fadeStartTime(0) {
// Create the game surfaces
_foreground.create(640, 320, _vm->_pixelFormat);
_background.create(640, 320, _vm->_pixelFormat);
diff --git a/engines/groovie/groovie.h b/engines/groovie/groovie.h
index d442d39cb2..c2994d20cc 100644
--- a/engines/groovie/groovie.h
+++ b/engines/groovie/groovie.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef GROOVIE_H
-#define GROOVIE_H
+#ifndef GROOVIE_GROOVIE_H
+#define GROOVIE_GROOVIE_H
#include "groovie/debug.h"
#include "groovie/font.h"
@@ -132,4 +132,4 @@ private:
} // End of namespace Groovie
-#endif // GROOVIE_H
+#endif // GROOVIE_GROOVIE_H
diff --git a/engines/groovie/music.cpp b/engines/groovie/music.cpp
index cf65e012c8..9244dd7c31 100644
--- a/engines/groovie/music.cpp
+++ b/engines/groovie/music.cpp
@@ -44,7 +44,8 @@ namespace Groovie {
MusicPlayer::MusicPlayer(GroovieEngine *vm) :
_vm(vm), _isPlaying(false), _backgroundFileRef(0), _gameVolume(100),
- _prevCDtrack(0), _backgroundDelay(0) {
+ _prevCDtrack(0), _backgroundDelay(0), _fadingStartTime(0), _fadingStartVolume(0),
+ _fadingEndVolume(0), _fadingDuration(0), _userVolume(0) {
}
MusicPlayer::~MusicPlayer() {
@@ -391,6 +392,8 @@ MusicPlayerXMI::MusicPlayerXMI(GroovieEngine *vm, const Common::String &gtlName)
bool milesAudioEnabled = true;
MidiParser::XMidiNewTimbreListProc newTimbreListProc = NULL;
+ _musicType = 0;
+
if (milesAudioEnabled) {
// 7th Guest uses FAT.AD/FAT.OPL/FAT.MT
// 11th Hour uses SAMPLE.AD/SAMPLE.OPL/SAMPLE.MT
diff --git a/engines/groovie/music.h b/engines/groovie/music.h
index c549527c77..8b46cddc1f 100644
--- a/engines/groovie/music.h
+++ b/engines/groovie/music.h
@@ -141,7 +141,7 @@ private:
// Timbres
class Timbre {
public:
- Timbre() : data(NULL) {}
+ Timbre() : data(NULL), patch(0), bank(0), size(0) {}
byte patch;
byte bank;
uint32 size;
diff --git a/engines/groovie/player.cpp b/engines/groovie/player.cpp
index dea32386f2..bbc8918902 100644
--- a/engines/groovie/player.cpp
+++ b/engines/groovie/player.cpp
@@ -29,7 +29,8 @@
namespace Groovie {
VideoPlayer::VideoPlayer(GroovieEngine *vm) :
- _vm(vm), _syst(vm->_system), _file(NULL), _audioStream(NULL), _fps(0), _overrideSpeed(false) {
+ _vm(vm), _syst(vm->_system), _file(NULL), _audioStream(NULL), _fps(0), _overrideSpeed(false), _flags(0),
+ _begunPlaying(false), _millisBetweenFrames(0), _lastFrameTime(0) {
}
bool VideoPlayer::load(Common::SeekableReadStream *file, uint16 flags) {
diff --git a/engines/hopkins/detection.cpp b/engines/hopkins/detection.cpp
index cc1e84f5f8..cfdbf8030c 100644
--- a/engines/hopkins/detection.cpp
+++ b/engines/hopkins/detection.cpp
@@ -111,7 +111,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "Hopkins FBI (c)1997-2003 MP Entertainment";
+ return "Hopkins FBI (C)1997-2003 MP Entertainment";
}
virtual bool hasFeature(MetaEngineFeature f) const;
diff --git a/engines/hugo/hugo.h b/engines/hugo/hugo.h
index 27dfea8725..85209afe06 100644
--- a/engines/hugo/hugo.h
+++ b/engines/hugo/hugo.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef HUGO_H
-#define HUGO_H
+#ifndef HUGO_HUGO_H
+#define HUGO_HUGO_H
#include "engines/engine.h"
@@ -341,4 +341,4 @@ private:
} // End of namespace Hugo
-#endif // Hugo_H
+#endif // HUGO_HUGO_H
diff --git a/engines/kyra/items_lok.cpp b/engines/kyra/items_lok.cpp
index 55a23b2a1a..3a2e631744 100644
--- a/engines/kyra/items_lok.cpp
+++ b/engines/kyra/items_lok.cpp
@@ -844,8 +844,6 @@ void KyraEngine_LoK::updatePlayerItemsForScene() {
uint8 item = _currentCharacter->inventoryItems[i];
if (item >= 29 && item < 33) {
++item;
- if (item > 33)
- item = 33;
_currentCharacter->inventoryItems[i] = item;
redraw = true;
}
diff --git a/engines/kyra/resource.h b/engines/kyra/resource.h
index 3ab08a4c7c..c3ebf6e5fe 100644
--- a/engines/kyra/resource.h
+++ b/engines/kyra/resource.h
@@ -203,7 +203,6 @@ enum KyraResources {
k1ConfigStrings,
k1AudioTracks,
- k1AudioTracks2,
k1AudioTracksIntro,
k1CreditsStrings,
diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp
index 1a2e2c093c..e99321ddcb 100644
--- a/engines/kyra/staticres.cpp
+++ b/engines/kyra/staticres.cpp
@@ -39,7 +39,7 @@
namespace Kyra {
-#define RESFILE_VERSION 87
+#define RESFILE_VERSION 88
namespace {
bool checkKyraDat(Common::SeekableReadStream *file) {
@@ -805,19 +805,11 @@ void KyraEngine_LoK::initStaticResource() {
}
// audio resource assignment
- int size1, size2;
- const char *const *soundfiles1 = _staticres->loadStrings(k1AudioTracks, size1);
- const char *const *soundfiles2 = _staticres->loadStrings(k1AudioTracks2, size2);
- int soundFilesSize = size1 + size2;
+ int soundFilesSize;
+ const char *const *soundFiles = _staticres->loadStrings(k1AudioTracks, soundFilesSize);
int soundFilesIntroSize = 0;
int cdaTableSize = 0;
- const char **soundFiles = 0;
- if (soundFilesSize) {
- soundFiles = new const char*[soundFilesSize];
- for (int i = 0; i < soundFilesSize; i++)
- soundFiles[i] = (i < size1) ? soundfiles1[i] : soundfiles2[i - size1];
- }
const char *const *soundFilesIntro = _staticres->loadStrings(k1AudioTracksIntro, soundFilesIntroSize);
const int32 *cdaTable = (const int32 *)_staticres->loadRawData(k1TownsCDATable, cdaTableSize);
diff --git a/engines/lab/anim.cpp b/engines/lab/anim.cpp
index 1190f0323b..2dc580735e 100644
--- a/engines/lab/anim.cpp
+++ b/engines/lab/anim.cpp
@@ -208,6 +208,8 @@ void Anim::diffNextFrame(bool onlyDiffData) {
_vm->updateEvents();
_vm->waitTOF();
}
+
+ _waitForEffect = false;
}
_size -= 8;
@@ -217,7 +219,9 @@ void Anim::diffNextFrame(bool onlyDiffData) {
_diffFile->skip(2);
// Sound effects embedded in animations are started here. These are
- // usually animation-specific, like door opening sounds, and are not looped
+ // usually animation-specific, like door opening sounds, and are not looped.
+ // The engine should wait for all such sounds to end.
+ _waitForEffect = true;
_vm->_music->playSoundEffect(_sampleSpeed, _size, false, _diffFile);
break;
@@ -233,6 +237,8 @@ void Anim::diffNextFrame(bool onlyDiffData) {
if (drawOnScreen)
didTOF = true;
}
+
+ _waitForEffect = false;
}
_isPlaying = false;
diff --git a/engines/lab/detection.cpp b/engines/lab/detection.cpp
index 1fd3ca8944..30890b5acf 100644
--- a/engines/lab/detection.cpp
+++ b/engines/lab/detection.cpp
@@ -127,7 +127,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "Labyrinth of Time (c) 2004 The Wyrmkeep Entertainment Co. and Terra Nova Development";
+ return "Labyrinth of Time (C) 2004 The Wyrmkeep Entertainment Co. and Terra Nova Development";
}
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
diff --git a/engines/lab/processroom.cpp b/engines/lab/processroom.cpp
index 5093e8ef85..68e6e63c1d 100644
--- a/engines/lab/processroom.cpp
+++ b/engines/lab/processroom.cpp
@@ -254,16 +254,9 @@ void LabEngine::doActions(const ActionList &actionList) {
_music->loadSoundEffect(action->_messages[0], true, false);
break;
- case kActionShowDiff: {
- bool curWait = _anim->_waitForEffect;
- // Pause the engine until the sound is finished
- _anim->_waitForEffect = true;
+ case kActionShowDiff:
_graphics->readPict(action->_messages[0], true);
-
- // Restore the previous value of _waitForEffect
- _anim->_waitForEffect = curWait;
break;
- }
case kActionShowDiffLooping: // used in scene 44 (heart of the labyrinth, minotaur)
_graphics->readPict(action->_messages[0], false);
diff --git a/engines/lastexpress/entities/gendarmes.cpp b/engines/lastexpress/entities/gendarmes.cpp
index b628b8dfe7..1b51dd2006 100644
--- a/engines/lastexpress/entities/gendarmes.cpp
+++ b/engines/lastexpress/entities/gendarmes.cpp
@@ -174,7 +174,7 @@ IMPLEMENT_FUNCTION_IISS(9, Gendarmes, doCompartment, CarIndex, EntityPosition)
strcat((char *)&parameters1->seq1, (char *)&params->seq1);
strcat((char *)&parameters1->seq2, (char *)&params->seq1);
- strcat((char *)&parameters1->seq3, (char *)&params->seq1);
+ Common::strlcat((char *)&parameters1->seq3, (char *)&params->seq1, 9); // Beware, seq3 is smaller than seq1
if ((getEntities()->isInsideCompartment(kEntityPlayer, (CarIndex)params->param1, (EntityPosition)params->param2)
|| getEntities()->isInsideCompartment(kEntityPlayer, (CarIndex)params->param1, (EntityPosition)parameters2->param7)
diff --git a/engines/lastexpress/lastexpress.h b/engines/lastexpress/lastexpress.h
index b4098f3860..b33784b1e8 100644
--- a/engines/lastexpress/lastexpress.h
+++ b/engines/lastexpress/lastexpress.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef LASTEXPRESS_H
-#define LASTEXPRESS_H
+#ifndef LASTEXPRESS_LASTEXPRESS_H
+#define LASTEXPRESS_LASTEXPRESS_H
#include "lastexpress/debug.h"
#include "lastexpress/eventhandler.h"
@@ -146,4 +146,4 @@ private:
} // End of namespace LastExpress
-#endif // LASTEXPRESS_H
+#endif // LASTEXPRESS_LASTEXPRESS_H
diff --git a/engines/lastexpress/sound/entry.cpp b/engines/lastexpress/sound/entry.cpp
index 697e6e1269..7308214551 100644
--- a/engines/lastexpress/sound/entry.cpp
+++ b/engines/lastexpress/sound/entry.cpp
@@ -366,7 +366,7 @@ void SoundEntry::saveLoadWithSerializer(Common::Serializer &s) {
assert(_name1.size() <= 16);
assert(_name2.size() <= 16);
- if (_name2.matchString("NISSND?") && (_status.status & kFlagType9) != kFlag3) {
+ if (_name2.matchString("NISSND?") && ((_status.status & kFlagType9) != kFlag3)) {
s.syncAsUint32LE(_status.status);
s.syncAsUint32LE(_type);
s.syncAsUint32LE(_blockCount); // field_8;
diff --git a/engines/lure/game.cpp b/engines/lure/game.cpp
index 38ca0ba54f..84cc91ec9a 100644
--- a/engines/lure/game.cpp
+++ b/engines/lure/game.cpp
@@ -538,7 +538,7 @@ void Game::handleRightClickMenu() {
hotspot = res.getHotspot(room.hotspotId());
assert(hotspot);
strings.getString(hotspot->nameId, statusLine);
- strcat(statusLine, stringList.getString(S_FOR));
+ Common::strlcat(statusLine, stringList.getString(S_FOR), MAX_DESC_SIZE);
statusLine += strlen(statusLine);
itemId = PopupMenu::ShowItems(GET, player->roomNumber());
@@ -549,7 +549,7 @@ void Game::handleRightClickMenu() {
hotspot = res.getHotspot(room.hotspotId());
assert(hotspot);
strings.getString(hotspot->nameId, statusLine);
- strcat(statusLine, stringList.getString(S_TO));
+ Common::strlcat(statusLine, stringList.getString(S_TO), MAX_DESC_SIZE);
breakFlag = GetTellActions();
break;
@@ -559,7 +559,7 @@ void Game::handleRightClickMenu() {
case DRINK:
hasItems = (res.numInventoryItems() != 0);
if (!hasItems)
- strcat(statusLine, stringList.getString(S_ACTION_NOTHING));
+ Common::strlcat(statusLine, stringList.getString(S_ACTION_NOTHING), MAX_DESC_SIZE);
statusLine += strlen(statusLine);
room.update();
@@ -579,9 +579,9 @@ void Game::handleRightClickMenu() {
assert(useHotspot);
strings.getString(useHotspot->nameId, statusLine);
if (action == GIVE)
- strcat(statusLine, stringList.getString(S_TO));
+ Common::strlcat(statusLine, stringList.getString(S_TO), MAX_DESC_SIZE);
else
- strcat(statusLine, stringList.getString(S_ON));
+ Common::strlcat(statusLine, stringList.getString(S_ON), MAX_DESC_SIZE);
statusLine += strlen(statusLine);
}
else if ((action == DRINK) || (action == EXAMINE))
@@ -762,11 +762,11 @@ bool Game::GetTellActions() {
// Second parameter
action = (Action) commands[_numTellCommands * 3];
if (action == ASK)
- strcat(statusLine, stringList.getString(S_FOR));
+ Common::strlcat(statusLine, stringList.getString(S_FOR), MAX_DESC_SIZE);
else if (action == GIVE)
- strcat(statusLine, stringList.getString(S_TO));
+ Common::strlcat(statusLine, stringList.getString(S_TO), MAX_DESC_SIZE);
else if (action == USE)
- strcat(statusLine, stringList.getString(S_ON));
+ Common::strlcat(statusLine, stringList.getString(S_ON), MAX_DESC_SIZE);
else {
// All other commads don't need a second parameter
++paramIndex;
diff --git a/engines/lure/hotspots.cpp b/engines/lure/hotspots.cpp
index fbf93e1e14..29e5d2832e 100644
--- a/engines/lure/hotspots.cpp
+++ b/engines/lure/hotspots.cpp
@@ -1898,8 +1898,8 @@ void Hotspot::doStatus(HotspotData *hotspot) {
endAction();
strings.getString(room.roomNumber(), buffer);
- strcat(buffer, "\n\n");
- strcat(buffer, stringList.getString(S_YOU_ARE_CARRYING));
+ Common::strlcat(buffer, "\n\n", MAX_DESC_SIZE);
+ Common::strlcat(buffer, stringList.getString(S_YOU_ARE_CARRYING), MAX_DESC_SIZE);
// Scan through the list and add in any items assigned to the player
HotspotDataList &list = res.hotspotData();
@@ -1909,25 +1909,25 @@ void Hotspot::doStatus(HotspotData *hotspot) {
if (rec.roomNumber == PLAYER_ID) {
if (numItems++ == 0)
- strcat(buffer, ": ");
+ Common::strlcat(buffer, ": ", MAX_DESC_SIZE);
else
- strcat(buffer, ", ");
+ Common::strlcat(buffer, ", ", MAX_DESC_SIZE);
strings.getString(rec.nameId, buffer + strlen(buffer));
}
}
// If there were no items, add in the word 'nothing'
if (numItems == 0)
- strcat(buffer, stringList.getString(S_INV_NOTHING));
+ Common::strlcat(buffer, stringList.getString(S_INV_NOTHING), MAX_DESC_SIZE);
// If the player has money, add it in
uint16 numGroats = res.fieldList().numGroats();
if (numGroats > 0) {
- strcat(buffer, "\n\n");
- strcat(buffer, stringList.getString(S_YOU_HAVE));
- sprintf(buffer + strlen(buffer), "%d", numGroats);
- strcat(buffer, " ");
- strcat(buffer, stringList.getString((numGroats == 1) ? S_GROAT : S_GROATS));
+ Common::strlcat(buffer, "\n\n", MAX_DESC_SIZE);
+ Common::strlcat(buffer, stringList.getString(S_YOU_HAVE), MAX_DESC_SIZE);
+ snprintf(buffer + strlen(buffer), MAX_DESC_SIZE - strlen(buffer), "%d", numGroats);
+ Common::strlcat(buffer, " ", MAX_DESC_SIZE);
+ Common::strlcat(buffer, stringList.getString((numGroats == 1) ? S_GROAT : S_GROATS), MAX_DESC_SIZE); // Make sure we're not overrunning
}
// Display the dialog
diff --git a/engines/lure/lure.h b/engines/lure/lure.h
index af00197c3f..71ce2d3cff 100644
--- a/engines/lure/lure.h
+++ b/engines/lure/lure.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef LURE_H
-#define LURE_H
+#ifndef LURE_LURE_H
+#define LURE_LURE_H
#include "engines/engine.h"
#include "common/rect.h"
diff --git a/engines/lure/scripts.cpp b/engines/lure/scripts.cpp
index 3df119a9da..f7dc06033a 100644
--- a/engines/lure/scripts.cpp
+++ b/engines/lure/scripts.cpp
@@ -926,8 +926,8 @@ uint16 Script::execute(uint16 startOffset) {
opcode >>= 1;
if (gDebugLevel >= ERROR_DETAILED)
- strcat(debugInfo, (opcode > S_OPCODE_RANDOM) ? "INVALID" :
- scriptOpcodes[opcode]);
+ Common::strlcat(debugInfo, (opcode > S_OPCODE_RANDOM) ? "INVALID" :
+ scriptOpcodes[opcode], MAX_DESC_SIZE);
if (hasParam) {
// Flag to read next two bytes as active parameter
@@ -1087,7 +1087,7 @@ uint16 Script::execute(uint16 startOffset) {
else if (scriptMethodNames[param] == NULL) strcat(debugInfo, " UNKNOWN METHOD");
else {
strcat(debugInfo, " ");
- strcat(debugInfo, scriptMethodNames[param]);
+ Common::strlcat(debugInfo, scriptMethodNames[param], MAX_DESC_SIZE);
}
// Any params
diff --git a/engines/made/database.cpp b/engines/made/database.cpp
index 3eab31acc2..0020cb398c 100644
--- a/engines/made/database.cpp
+++ b/engines/made/database.cpp
@@ -40,6 +40,7 @@ namespace Made {
*/
Object::Object() : _objData(NULL), _freeData(false) {
+ _objSize = 0;
}
Object::~Object() {
diff --git a/engines/made/made.cpp b/engines/made/made.cpp
index f1539297ee..a29aa2512f 100644
--- a/engines/made/made.cpp
+++ b/engines/made/made.cpp
@@ -58,11 +58,24 @@ MadeEngine::MadeEngine(OSystem *syst, const MadeGameDescription *gameDesc) : Eng
const GameSettings *g;
+ _eventNum = 0;
+ _eventMouseX = _eventMouseY = 0;
+ _eventKey = 0;
+ _autoStopSound = false;
+ _soundEnergyIndex = 0;
+ _soundEnergyArray = 0;
+ _musicBeatStart = 0;
+ _cdTimeStart = 0;
+
+ _gameId = -1;
+
const char *gameid = ConfMan.get("gameid").c_str();
for (g = madeSettings; g->gameid; ++g)
if (!scumm_stricmp(g->gameid, gameid))
_gameId = g->id;
+ assert(_gameId != -1);
+
_rnd = new Common::RandomSource("made");
_console = new MadeConsole(this);
@@ -85,6 +98,8 @@ MadeEngine::MadeEngine(OSystem *syst, const MadeGameDescription *gameDesc) : Eng
_music = nullptr;
+ _soundRate = 0;
+
// Set default sound frequency
switch (getGameID()) {
case GID_RODNEY:
diff --git a/engines/made/pmvplayer.cpp b/engines/made/pmvplayer.cpp
index 453e2a4872..0beb132b93 100644
--- a/engines/made/pmvplayer.cpp
+++ b/engines/made/pmvplayer.cpp
@@ -223,7 +223,10 @@ bool PmvPlayer::play(const char *filename) {
//delete _audioStream;
delete _fd;
- _surface->free();
+
+ if(_surface)
+ _surface->free();
+
delete _surface;
return !_aborted;
diff --git a/engines/made/redreader.cpp b/engines/made/redreader.cpp
index f92ffd8dd8..a0aaf7be43 100644
--- a/engines/made/redreader.cpp
+++ b/engines/made/redreader.cpp
@@ -102,7 +102,7 @@ int LzhDecompressor::decompress(Common::SeekableReadStream &source, byte *dest,
int bufsize;
byte* buffer;
- buffer = (byte *) malloc(DICSIZ);
+ buffer = (byte *)calloc(DICSIZ, 1);
_source = &source;
_compSize = sourceLen;
diff --git a/engines/made/resource.cpp b/engines/made/resource.cpp
index f8e763e74e..a9734ed47d 100644
--- a/engines/made/resource.cpp
+++ b/engines/made/resource.cpp
@@ -43,6 +43,7 @@ Resource::~Resource() {
PictureResource::PictureResource() : _picture(NULL), _picturePalette(NULL) {
_hasPalette = false;
+ _paletteColorCount = 0;
}
PictureResource::~PictureResource() {
@@ -182,6 +183,9 @@ void PictureResource::loadChunked(byte *source, int size) {
/* AnimationResource */
AnimationResource::AnimationResource() {
+ _flags = 0;
+ _width = 0;
+ _height = 0;
}
AnimationResource::~AnimationResource() {
diff --git a/engines/made/screen.cpp b/engines/made/screen.cpp
index edccb68953..33edb3834c 100644
--- a/engines/made/screen.cpp
+++ b/engines/made/screen.cpp
@@ -91,6 +91,8 @@ Screen::Screen(MadeEngine *vm) : _vm(vm) {
_currentFontNum = 0;
_fontDrawCtx.clipRect = Common::Rect(320, 200);
_fontDrawCtx.destSurface = _backgroundScreen;
+ _outlineColor = 0;
+ _dropShadowColor = 0;
clearChannels();
}
diff --git a/engines/made/sound.cpp b/engines/made/sound.cpp
index ad49031e7b..62559efa84 100644
--- a/engines/made/sound.cpp
+++ b/engines/made/sound.cpp
@@ -155,6 +155,7 @@ void decompressSound(byte *source, byte *dest, uint16 chunkSize, uint16 chunkCou
};
soundEnergyItem.position = 0;
+ memset(deltaSoundBuffer, 0, 1024);
if (soundEnergyArray)
soundEnergyArray->clear();
@@ -237,6 +238,7 @@ void decompressSound(byte *source, byte *dest, uint16 chunkSize, uint16 chunkCou
break;
default:
+ delete[] soundBuffer;
return;
}
@@ -247,6 +249,9 @@ void decompressSound(byte *source, byte *dest, uint16 chunkSize, uint16 chunkCou
// soundBuffer.
soundBuffer[workChunkSize] = soundBuffer[workChunkSize - 1];
+ for (i = 0; i < chunkSize; i++)
+ soundBuffer[i] = 0;
+
if (deltaType == 1) {
for (i = 0; i < chunkSize - 1; i += 2) {
l = i / 2;
diff --git a/engines/mads/detection.cpp b/engines/mads/detection.cpp
index b3ba60b6d0..4736503a38 100644
--- a/engines/mads/detection.cpp
+++ b/engines/mads/detection.cpp
@@ -149,7 +149,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "MADS (c)";
+ return "MADS (C)";
}
virtual bool hasFeature(MetaEngineFeature f) const;
diff --git a/engines/mads/dragonsphere/dragonsphere_scenes.cpp b/engines/mads/dragonsphere/dragonsphere_scenes.cpp
index a18d03d143..c20eeb72fa 100644
--- a/engines/mads/dragonsphere/dragonsphere_scenes.cpp
+++ b/engines/mads/dragonsphere/dragonsphere_scenes.cpp
@@ -201,7 +201,7 @@ Common::String DragonsphereScene::formAnimName(char sepChar, int suffixNum) {
/*------------------------------------------------------------------------*/
-void SceneInfoDragonsphere::loadCodes(MSurface &depthSurface, int variant) {
+void SceneInfoDragonsphere::loadCodes(BaseSurface &depthSurface, int variant) {
Common::String ext = Common::String::format(".WW%d", variant);
Common::String fileName = Resources::formatName(RESPREFIX_RM, _sceneId, ext);
if (!Common::File::exists(fileName))
@@ -217,7 +217,7 @@ void SceneInfoDragonsphere::loadCodes(MSurface &depthSurface, int variant) {
f.close();
}
-void SceneInfoDragonsphere::loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream) {
+void SceneInfoDragonsphere::loadCodes(BaseSurface &depthSurface, Common::SeekableReadStream *stream) {
byte *destP = (byte *)depthSurface.getPixels();
byte *walkMap = new byte[stream->size()];
stream->read(walkMap, stream->size());
diff --git a/engines/mads/dragonsphere/dragonsphere_scenes.h b/engines/mads/dragonsphere/dragonsphere_scenes.h
index e9b48715db..22d894b9d9 100644
--- a/engines/mads/dragonsphere/dragonsphere_scenes.h
+++ b/engines/mads/dragonsphere/dragonsphere_scenes.h
@@ -647,9 +647,9 @@ public:
class SceneInfoDragonsphere : public SceneInfo {
friend class SceneInfo;
protected:
- virtual void loadCodes(MSurface &depthSurface, int variant);
+ virtual void loadCodes(BaseSurface &depthSurface, int variant);
- virtual void loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream);
+ virtual void loadCodes(BaseSurface &depthSurface, Common::SeekableReadStream *stream);
/**
* Constructor
diff --git a/engines/mads/font.cpp b/engines/mads/font.cpp
index 3828c3df8e..684418da91 100644
--- a/engines/mads/font.cpp
+++ b/engines/mads/font.cpp
@@ -145,7 +145,7 @@ void Font::setColorMode(SelectionMode mode) {
}
}
-int Font::writeString(MSurface *surface, const Common::String &msg, const Common::Point &pt,
+int Font::writeString(BaseSurface *surface, const Common::String &msg, const Common::Point &pt,
int spaceWidth, int width) {
int xEnd;
if (width > 0)
diff --git a/engines/mads/font.h b/engines/mads/font.h
index 486cadcfff..a27de6e283 100644
--- a/engines/mads/font.h
+++ b/engines/mads/font.h
@@ -86,7 +86,7 @@ public:
int maxWidth() const { return _maxWidth; }
int getWidth(const Common::String &msg, int spaceWidth = -1);
int getHeight() const { return _maxHeight; }
- int writeString(MSurface *surface, const Common::String &msg, const Common::Point &pt,
+ int writeString(BaseSurface *surface, const Common::String &msg, const Common::Point &pt,
int spaceWidth = 0, int width = 0);
};
diff --git a/engines/mads/mads.cpp b/engines/mads/mads.cpp
index 29bcd10094..5776d813cf 100644
--- a/engines/mads/mads.cpp
+++ b/engines/mads/mads.cpp
@@ -58,6 +58,7 @@ MADSEngine::MADSEngine(OSystem *syst, const MADSGameDescription *gameDesc) :
_resources = nullptr;
_sound = nullptr;
_audio = nullptr;
+ _screen = nullptr;
}
MADSEngine::~MADSEngine() {
diff --git a/engines/mads/menu_views.h b/engines/mads/menu_views.h
index c203248ad9..e22b6223a7 100644
--- a/engines/mads/menu_views.h
+++ b/engines/mads/menu_views.h
@@ -8,20 +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.
-<<<<<<< HEAD
-
-=======
*
->>>>>>> master
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-<<<<<<< HEAD
-
-=======
*
->>>>>>> master
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
diff --git a/engines/mads/messages.cpp b/engines/mads/messages.cpp
index 2bee77dae7..773ebd309c 100644
--- a/engines/mads/messages.cpp
+++ b/engines/mads/messages.cpp
@@ -558,7 +558,7 @@ void TextDisplayList::setDirtyAreas2() {
}
}
-void TextDisplayList::draw(MSurface *s) {
+void TextDisplayList::draw(BaseSurface *s) {
for (uint idx = 0; idx < size(); ++idx) {
TextDisplay &td = (*this)[idx];
if (td._active && (td._expire >= 0)) {
diff --git a/engines/mads/messages.h b/engines/mads/messages.h
index 2b673a8a4d..ced8c5bb6d 100644
--- a/engines/mads/messages.h
+++ b/engines/mads/messages.h
@@ -170,7 +170,7 @@ public:
* Draw any text in the list to the specified surface
* @param surface Surface
*/
- void draw(MSurface *s);
+ void draw(BaseSurface *s);
/**
* Determine dirty areas for active text areas
diff --git a/engines/mads/msurface.cpp b/engines/mads/msurface.cpp
index 40c69c0f08..8ea9c39bf5 100644
--- a/engines/mads/msurface.cpp
+++ b/engines/mads/msurface.cpp
@@ -30,9 +30,9 @@
namespace MADS {
-MADSEngine *MSurface::_vm = nullptr;
+MADSEngine *BaseSurface::_vm = nullptr;
-int MSurface::scaleValue(int value, int scale, int err) {
+int BaseSurface::scaleValue(int value, int scale, int err) {
int scaled = 0;
while (value--) {
err -= scale;
@@ -44,7 +44,7 @@ int MSurface::scaleValue(int value, int scale, int err) {
return scaled;
}
-void MSurface::drawSprite(const Common::Point &pt, SpriteInfo &info, const Common::Rect &clipRect) {
+void BaseSurface::drawSprite(const Common::Point &pt, SpriteInfo &info, const Common::Rect &clipRect) {
enum {
kStatusSkip,
kStatusScale,
@@ -171,7 +171,7 @@ void MSurface::drawSprite(const Common::Point &pt, SpriteInfo &info, const Commo
delete[] scaledLineBuf;
}
-void MSurface::scrollX(int xAmount) {
+void BaseSurface::scrollX(int xAmount) {
if (xAmount == 0)
return;
@@ -203,7 +203,7 @@ void MSurface::scrollX(int xAmount) {
markAllDirty();
}
-void MSurface::scrollY(int yAmount) {
+void BaseSurface::scrollY(int yAmount) {
if (yAmount == 0)
return;
@@ -238,7 +238,7 @@ void MSurface::scrollY(int yAmount) {
delete[] tempData;
}
-void MSurface::translate(Common::Array<RGB6> &palette) {
+void BaseSurface::translate(Common::Array<RGB6> &palette) {
for (int y = 0; y < this->h; ++y) {
byte *pDest = (byte *)getBasePtr(0, y);
@@ -251,7 +251,7 @@ void MSurface::translate(Common::Array<RGB6> &palette) {
markAllDirty();
}
-void MSurface::translate(byte map[PALETTE_COUNT]) {
+void BaseSurface::translate(byte map[PALETTE_COUNT]) {
for (int y = 0; y < this->h; ++y) {
byte *pDest = (byte *)getBasePtr(0, y);
@@ -263,7 +263,7 @@ void MSurface::translate(byte map[PALETTE_COUNT]) {
markAllDirty();
}
-MSurface *MSurface::flipHorizontal() const {
+BaseSurface *BaseSurface::flipHorizontal() const {
MSurface *dest = new MSurface(this->w, this->h);
for (int y = 0; y < this->h; ++y) {
@@ -277,7 +277,7 @@ MSurface *MSurface::flipHorizontal() const {
return dest;
}
-void MSurface::copyRectTranslate(MSurface &srcSurface, const byte *paletteMap,
+void BaseSurface::copyRectTranslate(BaseSurface &srcSurface, const byte *paletteMap,
const Common::Point &destPos, const Common::Rect &srcRect) {
// Loop through the lines
for (int yCtr = 0; yCtr < srcRect.height(); ++yCtr) {
@@ -294,7 +294,7 @@ void MSurface::copyRectTranslate(MSurface &srcSurface, const byte *paletteMap,
destPos.y + srcRect.height()));
}
-void MSurface::copyFrom(MSurface &src, const Common::Point &destPos, int depth,
+void BaseSurface::copyFrom(BaseSurface &src, const Common::Point &destPos, int depth,
DepthSurface *depthSurface, int scale, bool flipped, int transparentColor) {
int destX = destPos.x, destY = destPos.y;
int frameWidth = src.w;
@@ -337,15 +337,13 @@ void MSurface::copyFrom(MSurface &src, const Common::Point &destPos, int depth,
if (destX < 0) {
copyRect.left += -destX;
destX = 0;
- }
- else if (destX + copyRect.width() > w) {
+ } else if (destX + copyRect.width() > w) {
copyRect.right -= destX + copyRect.width() - w;
}
if (destY < 0) {
copyRect.top += -destY;
destY = 0;
- }
- else if (destY + copyRect.height() > h) {
+ } else if (destY + copyRect.height() > h) {
copyRect.bottom -= destY + copyRect.height() - h;
}
diff --git a/engines/mads/msurface.h b/engines/mads/msurface.h
index e92770900d..5b5a1d62c1 100644
--- a/engines/mads/msurface.h
+++ b/engines/mads/msurface.h
@@ -25,7 +25,7 @@
#include "common/scummsys.h"
#include "common/rect.h"
-#include "graphics/managed_surface.h"
+#include "graphics/screen.h"
#include "mads/palette.h"
namespace MADS {
@@ -48,9 +48,11 @@ struct SpriteInfo {
};
/*
- * MADS graphics surface
+ * Base MADS surface class. This derivces from Graphics::Screen
+ * because it has logic we'll need for our own Screen class that
+ * derives from this one
*/
-class MSurface : virtual public Graphics::ManagedSurface {
+class BaseSurface : public Graphics::Screen {
private:
/**
* Helper method for calculating new dimensions when scaling a sprite
@@ -72,17 +74,19 @@ public:
/**
* Basic constructor
*/
- MSurface() : Graphics::ManagedSurface() {}
+ BaseSurface() : Graphics::Screen(0, 0) {
+ free(); // Free the 0x0 surface allocated by Graphics::Screen
+ }
/**
* Constructor for a surface with fixed dimensions
*/
- MSurface(int width, int height) : Graphics::ManagedSurface(width, height) {}
+ BaseSurface(int width, int height) : Graphics::Screen(width, height) {}
/**
* Destructor
*/
- virtual ~MSurface() {}
+ virtual ~BaseSurface() {}
/**
* Return a rect containing the bounds of the surface
@@ -142,13 +146,13 @@ public:
/**
* Create a new surface which is a flipped horizontal copy of the current one
*/
- MSurface *flipHorizontal() const;
+ BaseSurface *flipHorizontal() const;
/**
* Copy an area from one surface to another, translating it using a palette
* map as it's done
*/
- void copyRectTranslate(MSurface &srcSurface, const byte *paletteMap,
+ void copyRectTranslate(BaseSurface &srcSurface, const byte *paletteMap,
const Common::Point &destPos, const Common::Rect &srcRect);
/**
@@ -161,10 +165,22 @@ public:
* @param flipped Flag for whether image is to be flipped
* @param transparentColor Transparency palette index
*/
- void copyFrom(MSurface &src, const Common::Point &destPos, int depth, DepthSurface *depthSurface,
+ void copyFrom(BaseSurface &src, const Common::Point &destPos, int depth, DepthSurface *depthSurface,
int scale, bool flipped, int transparentColor = -1);
};
+class MSurface : public BaseSurface {
+protected:
+ /**
+ * Override the addDirtyRect from Graphics::Screen, since for standard
+ * surfaces we don't need dirty rects to be tracked
+ */
+ virtual void addDirtyRect(const Common::Rect &r) {}
+public:
+ MSurface() : BaseSurface() {}
+ MSurface(int width, int height) : BaseSurface(width, height) {}
+};
+
class DepthSurface : public MSurface {
public:
/**
diff --git a/engines/mads/nebular/nebular_scenes.cpp b/engines/mads/nebular/nebular_scenes.cpp
index 40228b4b7d..9502d273ea 100644
--- a/engines/mads/nebular/nebular_scenes.cpp
+++ b/engines/mads/nebular/nebular_scenes.cpp
@@ -311,7 +311,7 @@ Common::String NebularScene::formAnimName(char sepChar, int suffixNum) {
/*------------------------------------------------------------------------*/
-void SceneInfoNebular::loadCodes(MSurface &depthSurface, int variant) {
+void SceneInfoNebular::loadCodes(BaseSurface &depthSurface, int variant) {
File f(Resources::formatName(RESPREFIX_RM, _sceneId, ".DAT"));
MadsPack codesPack(&f);
Common::SeekableReadStream *stream = codesPack.getItemStream(variant + 1);
@@ -322,7 +322,7 @@ void SceneInfoNebular::loadCodes(MSurface &depthSurface, int variant) {
f.close();
}
-void SceneInfoNebular::loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream) {
+void SceneInfoNebular::loadCodes(BaseSurface &depthSurface, Common::SeekableReadStream *stream) {
byte *destP = (byte *)depthSurface.getPixels();
byte *endP = (byte *)depthSurface.getBasePtr(0, depthSurface.h);
diff --git a/engines/mads/nebular/nebular_scenes.h b/engines/mads/nebular/nebular_scenes.h
index 58a6d1c98f..b600c6dbe1 100644
--- a/engines/mads/nebular/nebular_scenes.h
+++ b/engines/mads/nebular/nebular_scenes.h
@@ -1373,9 +1373,9 @@ public:
class SceneInfoNebular : public SceneInfo {
friend class SceneInfo;
protected:
- virtual void loadCodes(MSurface &depthSurface, int variant);
+ virtual void loadCodes(BaseSurface &depthSurface, int variant);
- virtual void loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream);
+ virtual void loadCodes(BaseSurface &depthSurface, Common::SeekableReadStream *stream);
/**
* Constructor
diff --git a/engines/mads/phantom/phantom_scenes.cpp b/engines/mads/phantom/phantom_scenes.cpp
index 7ef627ceeb..bfb521e369 100644
--- a/engines/mads/phantom/phantom_scenes.cpp
+++ b/engines/mads/phantom/phantom_scenes.cpp
@@ -174,7 +174,7 @@ Common::String PhantomScene::formAnimName(char sepChar, int suffixNum) {
/*------------------------------------------------------------------------*/
-void SceneInfoPhantom::loadCodes(MSurface &depthSurface, int variant) {
+void SceneInfoPhantom::loadCodes(BaseSurface &depthSurface, int variant) {
Common::String ext = Common::String::format(".WW%d", variant);
Common::String fileName = Resources::formatName(RESPREFIX_RM, _sceneId, ext);
if (!Common::File::exists(fileName))
@@ -190,7 +190,7 @@ void SceneInfoPhantom::loadCodes(MSurface &depthSurface, int variant) {
f.close();
}
-void SceneInfoPhantom::loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream) {
+void SceneInfoPhantom::loadCodes(BaseSurface &depthSurface, Common::SeekableReadStream *stream) {
byte *destP = (byte *)depthSurface.getPixels();
byte *walkMap = new byte[stream->size()];
stream->read(walkMap, stream->size());
diff --git a/engines/mads/phantom/phantom_scenes.h b/engines/mads/phantom/phantom_scenes.h
index a6a8395a2c..6b7ab697f3 100644
--- a/engines/mads/phantom/phantom_scenes.h
+++ b/engines/mads/phantom/phantom_scenes.h
@@ -474,9 +474,9 @@ public:
class SceneInfoPhantom : public SceneInfo {
friend class SceneInfo;
protected:
- virtual void loadCodes(MSurface &depthSurface, int variant);
+ virtual void loadCodes(BaseSurface &depthSurface, int variant);
- virtual void loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream);
+ virtual void loadCodes(BaseSurface &depthSurface, Common::SeekableReadStream *stream);
/**
* Constructor
diff --git a/engines/mads/scene_data.cpp b/engines/mads/scene_data.cpp
index 5323178ec7..21fd4f9026 100644
--- a/engines/mads/scene_data.cpp
+++ b/engines/mads/scene_data.cpp
@@ -128,7 +128,7 @@ SceneInfo *SceneInfo::init(MADSEngine *vm) {
}
void SceneInfo::load(int sceneId, int variant, const Common::String &resName,
- int flags, DepthSurface &depthSurface, MSurface &bgSurface) {
+ int flags, DepthSurface &depthSurface, BaseSurface &bgSurface) {
bool sceneFlag = sceneId >= 0;
// Figure out the resource to use
@@ -299,7 +299,7 @@ void SceneInfo::load(int sceneId, int variant, const Common::String &resName,
}
}
-void SceneInfo::loadPalette(int sceneId, int artFileNum, const Common::String &resName, int flags, MSurface &bgSurface) {
+void SceneInfo::loadPalette(int sceneId, int artFileNum, const Common::String &resName, int flags, BaseSurface &bgSurface) {
bool sceneFlag = sceneId >= 0;
Common::String resourceName;
bool isV2 = (_vm->getGameID() != GType_RexNebular);
@@ -351,7 +351,7 @@ void SceneInfo::loadPalette(int sceneId, int artFileNum, const Common::String &r
}
}
-void SceneInfo::loadMadsV1Background(int sceneId, const Common::String &resName, int flags, MSurface &bgSurface) {
+void SceneInfo::loadMadsV1Background(int sceneId, const Common::String &resName, int flags, BaseSurface &bgSurface) {
bool sceneFlag = sceneId >= 0;
Common::String resourceName;
Common::SeekableReadStream *stream;
@@ -397,7 +397,7 @@ void SceneInfo::loadMadsV1Background(int sceneId, const Common::String &resName,
artFile.close();
}
-void SceneInfo::loadMadsV2Background(int sceneId, const Common::String &resName, int flags, MSurface &bgSurface) {
+void SceneInfo::loadMadsV2Background(int sceneId, const Common::String &resName, int flags, BaseSurface &bgSurface) {
Common::String tileMapResourceName = Resources::formatName(RESPREFIX_RM, sceneId, ".MM");
File tileMapFile(tileMapResourceName);
MadsPack tileMapPack(&tileMapFile);
diff --git a/engines/mads/scene_data.h b/engines/mads/scene_data.h
index 41a08f74eb..a28c42c5ab 100644
--- a/engines/mads/scene_data.h
+++ b/engines/mads/scene_data.h
@@ -189,36 +189,36 @@ public:
* loads the data
*/
void load(int sceneId, int variant, const Common::String &resName, int flags,
- DepthSurface &depthSurface, MSurface &bgSurface);
+ DepthSurface &depthSurface, BaseSurface &bgSurface);
/**
* Loads the palette for a scene
*/
- void loadPalette(int sceneId, int artFileNum, const Common::String &resName, int flags, MSurface &bgSurface);
+ void loadPalette(int sceneId, int artFileNum, const Common::String &resName, int flags, BaseSurface &bgSurface);
/**
* Loads a V1 game background
*/
- void loadMadsV1Background(int sceneId, const Common::String &resName, int flags, MSurface &bgSurface);
+ void loadMadsV1Background(int sceneId, const Common::String &resName, int flags, BaseSurface &bgSurface);
/**
* Loads a V2 game background
*/
- void loadMadsV2Background(int sceneId, const Common::String &resName, int flags, MSurface &bgSurface);
+ void loadMadsV2Background(int sceneId, const Common::String &resName, int flags, BaseSurface &bgSurface);
/**
* Loads the given surface with depth information of a given scene
* @param depthSurface Depth/walk surface
* @param variant Variant number to load
*/
- virtual void loadCodes(MSurface &depthSurface, int variant) = 0;
+ virtual void loadCodes(BaseSurface &depthSurface, int variant) = 0;
/**
* Loads the given surface with depth information of a given scene
* @param depthSurface Depth/walk surface
* @param stream Stream to load the data from
*/
- virtual void loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream) = 0;
+ virtual void loadCodes(BaseSurface &depthSurface, Common::SeekableReadStream *stream) = 0;
};
} // End of namespace MADS
diff --git a/engines/mads/screen.cpp b/engines/mads/screen.cpp
index 05f9de61e2..b17b6e93b8 100644
--- a/engines/mads/screen.cpp
+++ b/engines/mads/screen.cpp
@@ -201,7 +201,7 @@ void DirtyAreas::mergeAreas(int idx1, int idx2) {
da1._textActive = true;
}
-void DirtyAreas::copy(MSurface *srcSurface, MSurface *destSurface, const Common::Point &posAdjust) {
+void DirtyAreas::copy(BaseSurface *srcSurface, BaseSurface *destSurface, const Common::Point &posAdjust) {
for (uint i = 0; i < size(); ++i) {
const Common::Rect &srcBounds = (*this)[i]._bounds;
@@ -555,7 +555,7 @@ void ScreenObjects::synchronize(Common::Serializer &s) {
/*------------------------------------------------------------------------*/
-Screen::Screen(): Graphics::Screen(), MSurface() {
+Screen::Screen(): BaseSurface() {
// Create the screen surface separately on another surface, since the screen
// surface will be subject to change as the clipping area is altered
_rawSurface.create(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT);
diff --git a/engines/mads/screen.h b/engines/mads/screen.h
index 626080580e..eeb15453f8 100644
--- a/engines/mads/screen.h
+++ b/engines/mads/screen.h
@@ -25,7 +25,6 @@
#include "common/scummsys.h"
#include "common/array.h"
-#include "graphics/screen.h"
#include "mads/msurface.h"
#include "mads/action.h"
@@ -118,7 +117,7 @@ public:
* @param destSurface Dest surface
* @param posAdjust Position adjustment
*/
- void copy(MSurface *srcSurface, MSurface *destSurface, const Common::Point &posAdjust);
+ void copy(BaseSurface *srcSurface, BaseSurface *destSurface, const Common::Point &posAdjust);
/**
* Use the lsit of dirty areas to copy areas of the screen surface to
@@ -129,7 +128,6 @@ public:
void reset();
};
-
class ScreenObject {
public:
bool _active;
@@ -208,7 +206,7 @@ public:
void synchronize(Common::Serializer &s);
};
-class Screen : virtual public Graphics::Screen, virtual public MSurface {
+class Screen : public BaseSurface {
private:
uint16 _random;
MSurface _rawSurface;
diff --git a/engines/mads/sprites.cpp b/engines/mads/sprites.cpp
index fc8ddf22d2..84060ccdfe 100644
--- a/engines/mads/sprites.cpp
+++ b/engines/mads/sprites.cpp
@@ -337,7 +337,7 @@ void SpriteSlots::drawSprites(MSurface *s) {
s->copyFrom(*sprite, Common::Point(xp, yp), slot._depth, &scene._depthSurface,
-1, flipped, sprite->getTransparencyIndex());
} else {
- MSurface *spr = sprite;
+ BaseSurface *spr = sprite;
if (flipped) {
// Create a flipped copy of the sprite temporarily
spr = sprite->flipHorizontal();
diff --git a/engines/mads/user_interface.cpp b/engines/mads/user_interface.cpp
index 8f7cb0a24b..204f71fe43 100644
--- a/engines/mads/user_interface.cpp
+++ b/engines/mads/user_interface.cpp
@@ -161,7 +161,7 @@ void UISlots::draw(bool updateFlag, bool delFlag) {
MSprite *sprite = asset->getFrame(frameNumber - 1);
if (flipped) {
- MSurface *spr = sprite->flipHorizontal();
+ BaseSurface *spr = sprite->flipHorizontal();
userInterface.mergeFrom(spr, spr->getBounds(), slot._position,
sprite->getTransparencyIndex());
spr->free();
@@ -429,7 +429,7 @@ void UserInterface::drawTextElements() {
}
}
-void UserInterface::mergeFrom(MSurface *src, const Common::Rect &srcBounds,
+void UserInterface::mergeFrom(BaseSurface *src, const Common::Rect &srcBounds,
const Common::Point &destPos, int transparencyIndex) {
// Validation of the rectangle and position
int destX = destPos.x, destY = destPos.y;
diff --git a/engines/mads/user_interface.h b/engines/mads/user_interface.h
index 9232dc1bb1..6c9485998a 100644
--- a/engines/mads/user_interface.h
+++ b/engines/mads/user_interface.h
@@ -238,7 +238,7 @@ public:
* @param destPos Destination position to draw in current surface
* @param transparencyIndex Transparency color
*/
- void mergeFrom(MSurface *src, const Common::Rect &srcBounds, const Common::Point &destPos,
+ void mergeFrom(BaseSurface *src, const Common::Rect &srcBounds, const Common::Point &destPos,
int transparencyIndex = -1);
/**
diff --git a/engines/mohawk/mohawk.h b/engines/mohawk/mohawk.h
index 6fa733e38e..ac91dca971 100644
--- a/engines/mohawk/mohawk.h
+++ b/engines/mohawk/mohawk.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef MOHAWK_H
-#define MOHAWK_H
+#ifndef MOHAWK_MOHAWK_H
+#define MOHAWK_MOHAWK_H
#include "common/scummsys.h"
#include "common/array.h"
diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp
index e2bc88ebf6..633b67f7e9 100644
--- a/engines/mohawk/myst.cpp
+++ b/engines/mohawk/myst.cpp
@@ -604,7 +604,8 @@ void MohawkEngine_Myst::changeToCard(uint16 card, TransitionType transition) {
_gfx->runTransition(transition, Common::Rect(544, 333), 10, 0);
} else {
_gfx->copyBackBufferToScreen(Common::Rect(544, 333));
- _needsUpdate = true;
+ _system->updateScreen();
+ _needsUpdate = false;
}
}
diff --git a/engines/mortevielle/mortevielle.cpp b/engines/mortevielle/mortevielle.cpp
index 90d366ed7e..81b2edb57d 100644
--- a/engines/mortevielle/mortevielle.cpp
+++ b/engines/mortevielle/mortevielle.cpp
@@ -145,6 +145,7 @@ MortevielleEngine::MortevielleEngine(OSystem *system, const MortevielleGameDescr
_endGame = false;
_loseGame = false;
_txxFileFl = false;
+ _is = 0;
}
MortevielleEngine::~MortevielleEngine() {
diff --git a/engines/neverhood/diskplayerscene.cpp b/engines/neverhood/diskplayerscene.cpp
index 96a935851c..e79f4c9d77 100644
--- a/engines/neverhood/diskplayerscene.cpp
+++ b/engines/neverhood/diskplayerscene.cpp
@@ -22,6 +22,7 @@
#include "neverhood/diskplayerscene.h"
#include "neverhood/mouse.h"
+#include "neverhood/smackerplayer.h"
namespace Neverhood {
diff --git a/engines/neverhood/diskplayerscene.h b/engines/neverhood/diskplayerscene.h
index 2ae85b9a0b..dba10f3a46 100644
--- a/engines/neverhood/diskplayerscene.h
+++ b/engines/neverhood/diskplayerscene.h
@@ -26,11 +26,11 @@
#include "neverhood/neverhood.h"
#include "neverhood/resourceman.h"
#include "neverhood/scene.h"
-#include "neverhood/smackerplayer.h"
namespace Neverhood {
class DiskplayerScene;
+class SmackerPlayer;
class AsDiskplayerSceneKey : public AnimatedSprite {
public:
diff --git a/engines/neverhood/menumodule.cpp b/engines/neverhood/menumodule.cpp
index 0f2a421d83..e58dd31f03 100644
--- a/engines/neverhood/menumodule.cpp
+++ b/engines/neverhood/menumodule.cpp
@@ -23,6 +23,8 @@
#include "common/config-manager.h"
#include "common/translation.h"
+#include "audio/mixer.h"
+
#include "gui/saveload.h"
#include "neverhood/menumodule.h"
diff --git a/engines/neverhood/modules/module1300.cpp b/engines/neverhood/modules/module1300.cpp
index 60ff0411a6..65bd353576 100644
--- a/engines/neverhood/modules/module1300.cpp
+++ b/engines/neverhood/modules/module1300.cpp
@@ -23,6 +23,7 @@
#include "neverhood/diskplayerscene.h"
#include "neverhood/gamemodule.h"
#include "neverhood/menumodule.h"
+#include "neverhood/smackerplayer.h"
#include "neverhood/modules/module1000_sprites.h"
#include "neverhood/modules/module1200_sprites.h"
#include "neverhood/modules/module1300.h"
diff --git a/engines/neverhood/modules/module1300.h b/engines/neverhood/modules/module1300.h
index 4a0ca6c062..8164a51d0d 100644
--- a/engines/neverhood/modules/module1300.h
+++ b/engines/neverhood/modules/module1300.h
@@ -26,10 +26,11 @@
#include "neverhood/neverhood.h"
#include "neverhood/module.h"
#include "neverhood/scene.h"
-#include "neverhood/smackerplayer.h"
namespace Neverhood {
+class SmackerPlayer;
+
class Module1300 : public Module {
public:
Module1300(NeverhoodEngine *vm, Module *parentModule, int which);
diff --git a/engines/neverhood/modules/module1300_sprites.h b/engines/neverhood/modules/module1300_sprites.h
index 6f4faaa234..bf9f72a5a7 100644
--- a/engines/neverhood/modules/module1300_sprites.h
+++ b/engines/neverhood/modules/module1300_sprites.h
@@ -26,7 +26,6 @@
#include "neverhood/neverhood.h"
#include "neverhood/module.h"
#include "neverhood/scene.h"
-#include "neverhood/smackerplayer.h"
namespace Neverhood {
diff --git a/engines/neverhood/modules/module2800.cpp b/engines/neverhood/modules/module2800.cpp
index ab22390c7d..63d507d8fd 100644
--- a/engines/neverhood/modules/module2800.cpp
+++ b/engines/neverhood/modules/module2800.cpp
@@ -23,6 +23,7 @@
#include "neverhood/diskplayerscene.h"
#include "neverhood/gamemodule.h"
#include "neverhood/scene.h"
+#include "neverhood/smackerplayer.h"
#include "neverhood/modules/module1000_sprites.h"
#include "neverhood/modules/module1200_sprites.h"
#include "neverhood/modules/module1700_sprites.h"
diff --git a/engines/neverhood/navigationscene.h b/engines/neverhood/navigationscene.h
index 8e286effb9..e1dabfea3d 100644
--- a/engines/neverhood/navigationscene.h
+++ b/engines/neverhood/navigationscene.h
@@ -26,6 +26,7 @@
#include "neverhood/neverhood.h"
#include "neverhood/resourceman.h"
#include "neverhood/scene.h"
+#include "neverhood/smackerplayer.h"
namespace Neverhood {
diff --git a/engines/neverhood/neverhood.cpp b/engines/neverhood/neverhood.cpp
index c6cff86c72..0dc271997b 100644
--- a/engines/neverhood/neverhood.cpp
+++ b/engines/neverhood/neverhood.cpp
@@ -24,6 +24,8 @@
#include "common/config-manager.h"
#include "common/textconsole.h"
+#include "audio/mixer.h"
+
#include "base/plugins.h"
#include "base/version.h"
diff --git a/engines/neverhood/neverhood.h b/engines/neverhood/neverhood.h
index 9eac4ffc44..4c5f9c3303 100644
--- a/engines/neverhood/neverhood.h
+++ b/engines/neverhood/neverhood.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef NEVERHOOD_H
-#define NEVERHOOD_H
+#ifndef NEVERHOOD_NEVERHOOD_H
+#define NEVERHOOD_NEVERHOOD_H
#include "common/scummsys.h"
#include "common/events.h"
@@ -149,4 +149,4 @@ private:
} // End of namespace Neverhood
-#endif /* NEVERHOOD_H */
+#endif /* NEVERHOOD_NEVERHOOD_H */
diff --git a/engines/neverhood/scene.cpp b/engines/neverhood/scene.cpp
index 1a8e74da38..8ed988c0fc 100644
--- a/engines/neverhood/scene.cpp
+++ b/engines/neverhood/scene.cpp
@@ -22,6 +22,7 @@
#include "neverhood/console.h"
#include "neverhood/scene.h"
+#include "neverhood/smackerplayer.h"
namespace Neverhood {
diff --git a/engines/neverhood/scene.h b/engines/neverhood/scene.h
index 98a7fa5090..1d1faf28bc 100644
--- a/engines/neverhood/scene.h
+++ b/engines/neverhood/scene.h
@@ -31,13 +31,13 @@
#include "neverhood/klaymen.h"
#include "neverhood/module.h"
#include "neverhood/palette.h"
-#include "neverhood/smackerplayer.h"
#include "neverhood/sprite.h"
#include "neverhood/staticdata.h"
namespace Neverhood {
class Console;
+class SmackerPlayer;
class Scene : public Entity {
public:
diff --git a/engines/neverhood/screen.cpp b/engines/neverhood/screen.cpp
index cc735c4c16..5cc7998210 100644
--- a/engines/neverhood/screen.cpp
+++ b/engines/neverhood/screen.cpp
@@ -21,6 +21,7 @@
*/
#include "graphics/palette.h"
+#include "video/smk_decoder.h"
#include "neverhood/screen.h"
namespace Neverhood {
diff --git a/engines/neverhood/screen.h b/engines/neverhood/screen.h
index 82ce90b245..91bbe12c66 100644
--- a/engines/neverhood/screen.h
+++ b/engines/neverhood/screen.h
@@ -25,11 +25,14 @@
#include "common/array.h"
#include "graphics/surface.h"
-#include "video/smk_decoder.h"
#include "neverhood/neverhood.h"
#include "neverhood/microtiles.h"
#include "neverhood/graphics.h"
+namespace Video {
+ class SmackerDecoder;
+}
+
namespace Neverhood {
struct RenderItem {
diff --git a/engines/neverhood/smackerscene.cpp b/engines/neverhood/smackerscene.cpp
index 2b43579130..50677d7d5c 100644
--- a/engines/neverhood/smackerscene.cpp
+++ b/engines/neverhood/smackerscene.cpp
@@ -21,6 +21,7 @@
*/
#include "neverhood/smackerscene.h"
+#include "neverhood/smackerplayer.h"
namespace Neverhood {
diff --git a/engines/neverhood/sound.cpp b/engines/neverhood/sound.cpp
index b15bea4a64..db22b72289 100644
--- a/engines/neverhood/sound.cpp
+++ b/engines/neverhood/sound.cpp
@@ -21,10 +21,17 @@
*/
#include "common/memstream.h"
-#include "graphics/palette.h"
+#include "audio/mixer.h"
#include "neverhood/sound.h"
+#include "neverhood/resource.h"
#include "neverhood/resourceman.h"
+// Convert volume from percent to 0..255
+#define VOLUME(volume) (Audio::Mixer::kMaxChannelVolume / 100 * (volume))
+
+// Convert panning from percent (50% equals center) to -127..0..+127
+#define PANNING(panning) (254 / 100 * (panning) - 127)
+
namespace Neverhood {
SoundResource::SoundResource(NeverhoodEngine *vm)
@@ -583,6 +590,11 @@ AudioResourceManSoundItem::AudioResourceManSoundItem(NeverhoodEngine *vm, uint32
_volume(100), _panning(50) {
_vm->_res->queryResource(_fileHash, _resourceHandle);
+ _soundHandle = new Audio::SoundHandle();
+}
+
+AudioResourceManSoundItem::~AudioResourceManSoundItem() {
+ delete _soundHandle;
}
void AudioResourceManSoundItem::loadSound() {
@@ -594,22 +606,22 @@ void AudioResourceManSoundItem::loadSound() {
}
void AudioResourceManSoundItem::unloadSound() {
- if (_vm->_mixer->isSoundHandleActive(_soundHandle))
- _vm->_mixer->stopHandle(_soundHandle);
+ if (_vm->_mixer->isSoundHandleActive(*_soundHandle))
+ _vm->_mixer->stopHandle(*_soundHandle);
_vm->_res->unloadResource(_resourceHandle);
_data = NULL;
}
void AudioResourceManSoundItem::setVolume(int16 volume) {
_volume = MIN<int16>(volume, 100);
- if (_isPlaying && _vm->_mixer->isSoundHandleActive(_soundHandle))
- _vm->_mixer->setChannelVolume(_soundHandle, VOLUME(_volume));
+ if (_isPlaying && _vm->_mixer->isSoundHandleActive(*_soundHandle))
+ _vm->_mixer->setChannelVolume(*_soundHandle, VOLUME(_volume));
}
void AudioResourceManSoundItem::setPan(int16 pan) {
_panning = MIN<int16>(pan, 100);
- if (_isPlaying && _vm->_mixer->isSoundHandleActive(_soundHandle))
- _vm->_mixer->setChannelVolume(_soundHandle, PANNING(_panning));
+ if (_isPlaying && _vm->_mixer->isSoundHandleActive(*_soundHandle))
+ _vm->_mixer->setChannelVolume(*_soundHandle, PANNING(_panning));
}
void AudioResourceManSoundItem::playSound(bool looping) {
@@ -619,7 +631,7 @@ void AudioResourceManSoundItem::playSound(bool looping) {
const byte *shiftValue = _resourceHandle.extData();
Common::MemoryReadStream *stream = new Common::MemoryReadStream(_data, _resourceHandle.size(), DisposeAfterUse::NO);
NeverhoodAudioStream *audioStream = new NeverhoodAudioStream(22050, *shiftValue, looping, DisposeAfterUse::YES, stream);
- _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle,
+ _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, _soundHandle,
audioStream, -1, VOLUME(_volume), PANNING(_panning));
debug(1, "playing sound %08X", _fileHash);
_isPlaying = true;
@@ -627,13 +639,13 @@ void AudioResourceManSoundItem::playSound(bool looping) {
}
void AudioResourceManSoundItem::stopSound() {
- if (_vm->_mixer->isSoundHandleActive(_soundHandle))
- _vm->_mixer->stopHandle(_soundHandle);
+ if (_vm->_mixer->isSoundHandleActive(*_soundHandle))
+ _vm->_mixer->stopHandle(*_soundHandle);
_isPlaying = false;
}
bool AudioResourceManSoundItem::isPlaying() {
- return _vm->_mixer->isSoundHandleActive(_soundHandle);
+ return _vm->_mixer->isSoundHandleActive(*_soundHandle);
}
AudioResourceManMusicItem::AudioResourceManMusicItem(NeverhoodEngine *vm, uint32 fileHash)
@@ -641,6 +653,11 @@ AudioResourceManMusicItem::AudioResourceManMusicItem(NeverhoodEngine *vm, uint32
_volume(100), _panning(50), _start(false), _isFadingIn(false), _isFadingOut(false), _isPlaying(false),
_fadeVolume(0), _fadeVolumeStep(0) {
+ _soundHandle = new Audio::SoundHandle();
+}
+
+AudioResourceManMusicItem::~AudioResourceManMusicItem() {
+ delete _soundHandle;
}
void AudioResourceManMusicItem::playMusic(int16 fadeVolumeStep) {
@@ -658,7 +675,7 @@ void AudioResourceManMusicItem::playMusic(int16 fadeVolumeStep) {
}
void AudioResourceManMusicItem::stopMusic(int16 fadeVolumeStep) {
- if (_vm->_mixer->isSoundHandleActive(_soundHandle)) {
+ if (_vm->_mixer->isSoundHandleActive(*_soundHandle)) {
if (fadeVolumeStep != 0) {
if (_isFadingIn)
_isFadingIn = false;
@@ -667,7 +684,7 @@ void AudioResourceManMusicItem::stopMusic(int16 fadeVolumeStep) {
_isFadingOut = true;
_fadeVolumeStep = fadeVolumeStep;
} else {
- _vm->_mixer->stopHandle(_soundHandle);
+ _vm->_mixer->stopHandle(*_soundHandle);
}
_isPlaying = false;
}
@@ -677,8 +694,8 @@ void AudioResourceManMusicItem::unloadMusic() {
if (_isFadingOut) {
_canRestart = true;
} else {
- if (_vm->_mixer->isSoundHandleActive(_soundHandle))
- _vm->_mixer->stopHandle(_soundHandle);
+ if (_vm->_mixer->isSoundHandleActive(*_soundHandle))
+ _vm->_mixer->stopHandle(*_soundHandle);
_isPlaying = false;
_terminate = true;
}
@@ -686,8 +703,8 @@ void AudioResourceManMusicItem::unloadMusic() {
void AudioResourceManMusicItem::setVolume(int16 volume) {
_volume = MIN<int16>(volume, 100);
- if (_isPlaying && _vm->_mixer->isSoundHandleActive(_soundHandle))
- _vm->_mixer->setChannelVolume(_soundHandle, VOLUME(_volume));
+ if (_isPlaying && _vm->_mixer->isSoundHandleActive(*_soundHandle))
+ _vm->_mixer->setChannelVolume(*_soundHandle, VOLUME(_volume));
}
void AudioResourceManMusicItem::restart() {
@@ -698,33 +715,33 @@ void AudioResourceManMusicItem::restart() {
void AudioResourceManMusicItem::update() {
- if (_start && !_vm->_mixer->isSoundHandleActive(_soundHandle)) {
+ if (_start && !_vm->_mixer->isSoundHandleActive(*_soundHandle)) {
ResourceHandle resourceHandle;
_vm->_res->queryResource(_fileHash, resourceHandle);
Common::SeekableReadStream *stream = _vm->_res->createStream(_fileHash);
const byte *shiftValue = resourceHandle.extData();
NeverhoodAudioStream *audioStream = new NeverhoodAudioStream(22050, *shiftValue, true, DisposeAfterUse::YES, stream);
- _vm->_mixer->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle,
+ _vm->_mixer->playStream(Audio::Mixer::kMusicSoundType, _soundHandle,
audioStream, -1, VOLUME(_isFadingIn ? _fadeVolume : _volume),
PANNING(_panning));
_start = false;
_isPlaying = true;
}
- if (_vm->_mixer->isSoundHandleActive(_soundHandle)) {
+ if (_vm->_mixer->isSoundHandleActive(*_soundHandle)) {
if (_isFadingIn) {
_fadeVolume += _fadeVolumeStep;
if (_fadeVolume >= _volume) {
_fadeVolume = _volume;
_isFadingIn = false;
}
- _vm->_mixer->setChannelVolume(_soundHandle, VOLUME(_fadeVolume));
+ _vm->_mixer->setChannelVolume(*_soundHandle, VOLUME(_fadeVolume));
}
if (_isFadingOut) {
_fadeVolume -= _fadeVolumeStep;
if (_fadeVolume < 0)
_fadeVolume = 0;
- _vm->_mixer->setChannelVolume(_soundHandle, VOLUME(_fadeVolume));
+ _vm->_mixer->setChannelVolume(*_soundHandle, VOLUME(_fadeVolume));
if (_fadeVolume == 0) {
_isFadingOut = false;
stopMusic(0);
diff --git a/engines/neverhood/sound.h b/engines/neverhood/sound.h
index 24947f0191..e5e4ec9216 100644
--- a/engines/neverhood/sound.h
+++ b/engines/neverhood/sound.h
@@ -24,23 +24,22 @@
#define NEVERHOOD_SOUND_H
#include "audio/audiostream.h"
-#include "audio/mixer.h"
#include "common/array.h"
-#include "graphics/surface.h"
-#include "neverhood/neverhood.h"
-#include "neverhood/resource.h"
+#include "neverhood/resourceman.h"
-namespace Neverhood {
+namespace Common {
+class SeekableReadStream;
+}
-// Convert volume from percent to 0..255
-#define VOLUME(volume) (Audio::Mixer::kMaxChannelVolume / 100 * (volume))
+namespace Audio {
+class SoundHandle;
+}
-// Convert panning from percent (50% equals center) to -127..0..+127
-#define PANNING(panning) (254 / 100 * (panning) - 127)
+namespace Neverhood {
+class NeverhoodEngine;
class AudioResourceManSoundItem;
class AudioResourceManMusicItem;
-class AudioResourceMan;
class SoundResource {
public:
@@ -214,6 +213,7 @@ private:
class AudioResourceManSoundItem {
public:
AudioResourceManSoundItem(NeverhoodEngine *vm, uint32 fileHash);
+ ~AudioResourceManSoundItem();
void loadSound();
void unloadSound();
void setVolume(int16 volume);
@@ -230,12 +230,13 @@ protected:
bool _isPlaying;
int16 _volume;
int16 _panning;
- Audio::SoundHandle _soundHandle;
+ Audio::SoundHandle *_soundHandle;
};
class AudioResourceManMusicItem {
public:
AudioResourceManMusicItem(NeverhoodEngine *vm, uint32 fileHash);
+ ~AudioResourceManMusicItem();
void playMusic(int16 fadeVolumeStep);
void stopMusic(int16 fadeVolumeStep);
void unloadMusic();
@@ -259,7 +260,7 @@ protected:
bool _isFadingOut;
int16 _fadeVolume;
int16 _fadeVolumeStep;
- Audio::SoundHandle _soundHandle;
+ Audio::SoundHandle *_soundHandle;
};
class AudioResourceMan {
diff --git a/engines/parallaction/adlib.cpp b/engines/parallaction/adlib.cpp
index 568ad190aa..a981a5553b 100644
--- a/engines/parallaction/adlib.cpp
+++ b/engines/parallaction/adlib.cpp
@@ -277,6 +277,15 @@ public:
_channels[i].init(this, i);
_isOpen = false;
+
+ _opl = NULL;
+ memset(_voices, 0, sizeof(_voices));
+
+ _lastVoice = 0;
+ _percussionMask = 0;
+
+ _adlibTimerProc = NULL;
+ _adlibTimerParam = NULL;
}
int open();
diff --git a/engines/parallaction/balloons.cpp b/engines/parallaction/balloons.cpp
index 234abff59a..c0a516eb0f 100644
--- a/engines/parallaction/balloons.cpp
+++ b/engines/parallaction/balloons.cpp
@@ -55,7 +55,7 @@ protected:
}
public:
- WrappedLineFormatter(Font *font) : _font(font) { }
+ WrappedLineFormatter(Font *font) : _font(font), _lines(0), _lineWidth(0) { }
virtual ~WrappedLineFormatter() { }
virtual void calc(const Common::String &text, uint16 maxwidth) {
@@ -136,7 +136,7 @@ protected:
}
public:
- StringExtent_NS(Font *font) : WrappedLineFormatter(font) { }
+ StringExtent_NS(Font *font) : WrappedLineFormatter(font), _width(0), _height(0) { }
uint width() const { return _width; }
uint height() const { return _height; }
@@ -189,7 +189,8 @@ protected:
}
public:
- StringWriter_NS(Parallaction_ns *vm, Font *font) : WrappedLineFormatter(font), _vm(vm) { }
+ StringWriter_NS(Parallaction_ns *vm, Font *font) : WrappedLineFormatter(font), _vm(vm),
+ _width(0), _height(0), _color(0), _surf(NULL) { }
void write(const Common::String &text, uint maxWidth, byte color, Graphics::Surface *surf) {
StringExtent_NS se(_font);
@@ -464,7 +465,7 @@ protected:
}
public:
- StringExtent_BR(Font *font) : WrappedLineFormatter(font) { }
+ StringExtent_BR(Font *font) : WrappedLineFormatter(font), _width(0), _height(0) { }
uint width() const { return _width; }
uint height() const { return _height; }
@@ -480,7 +481,8 @@ class StringWriter_BR : public WrappedLineFormatter {
Graphics::Surface *_surf;
protected:
- StringWriter_BR(Font *font, byte color) : WrappedLineFormatter(font) {
+ StringWriter_BR(Font *font, byte color) : WrappedLineFormatter(font), _width(0), _height(0),
+ _color(color), _x(0), _y(0), _surf(NULL) {
}
@@ -504,7 +506,8 @@ protected:
}
public:
- StringWriter_BR(Font *font) : WrappedLineFormatter(font) { }
+ StringWriter_BR(Font *font) : WrappedLineFormatter(font), _width(0), _height(0),
+ _color(0), _x(0), _y(0), _surf(NULL) { }
void write(const Common::String &text, uint maxWidth, byte color, Graphics::Surface *surf) {
StringExtent_BR se(_font);
diff --git a/engines/parallaction/debug.cpp b/engines/parallaction/debug.cpp
index a7087c64d7..0bf2babb5b 100644
--- a/engines/parallaction/debug.cpp
+++ b/engines/parallaction/debug.cpp
@@ -32,6 +32,7 @@ namespace Parallaction {
Debugger::Debugger(Parallaction *vm)
: GUI::Debugger() {
_vm = vm;
+ _mouseState = MOUSE_ENABLED_SHOW;
registerCmd("continue", WRAP_METHOD(Debugger, cmdExit));
registerCmd("location", WRAP_METHOD(Debugger, Cmd_Location));
diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp
index 62e2152816..771715b95e 100644
--- a/engines/parallaction/dialogue.cpp
+++ b/engines/parallaction/dialogue.cpp
@@ -140,6 +140,19 @@ DialogueManager::DialogueManager(Parallaction *vm, ZonePtr z) : _vm(vm), _z(z) {
_cmdList = 0;
_answerId = 0;
+
+ _faceId = 0;
+
+ _q = NULL;
+ memset(_visAnswers, 0, sizeof(_visAnswers));
+ _numVisAnswers = 0;
+
+ _selection = _oldSelection = 0;
+
+ _isKeyDown = false;
+ _downKey = 0;
+
+ _mouseButtons = 0;
}
void DialogueManager::start() {
@@ -412,7 +425,8 @@ protected:
}
public:
- DialogueManager_ns(Parallaction_ns *vm, ZonePtr z) : DialogueManager(vm, z), _vm(vm) {
+ DialogueManager_ns(Parallaction_ns *vm, ZonePtr z) : DialogueManager(vm, z), _vm(vm),
+ _passwordChanged(false), _askPassword(false) {
_ballonPos._questionBalloon = Common::Point(140, 10);
_ballonPos._questionChar = Common::Point(190, 80);
_ballonPos._answerChar = Common::Point(10, 80);
diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp
index 7458065b8c..af2d2b82e0 100644
--- a/engines/parallaction/disk_br.cpp
+++ b/engines/parallaction/disk_br.cpp
@@ -762,14 +762,11 @@ Common::String AmigaDisk_br::selectArchive(const Common::String& name) {
}
-Disk_br::Disk_br(Parallaction *vm) : _vm(vm), _baseDir(0) {
-
+Disk_br::Disk_br(Parallaction *vm) : _vm(vm), _baseDir(0), _language(0) {
}
Disk_br::~Disk_br() {
_sset.clear();
}
-
-
} // namespace Parallaction
diff --git a/engines/parallaction/disk_ns.cpp b/engines/parallaction/disk_ns.cpp
index 28e61b04f9..c25236acbd 100644
--- a/engines/parallaction/disk_ns.cpp
+++ b/engines/parallaction/disk_ns.cpp
@@ -238,7 +238,7 @@ void Disk_ns::setLanguage(uint16 language) {
#pragma mark -
-DosDisk_ns::DosDisk_ns(Parallaction* vm) : Disk_ns(vm) {
+DosDisk_ns::DosDisk_ns(Parallaction* vm) : Disk_ns(vm), _gfx(NULL) {
}
diff --git a/engines/parallaction/exec.cpp b/engines/parallaction/exec.cpp
index ceba072173..3d4e9bd803 100644
--- a/engines/parallaction/exec.cpp
+++ b/engines/parallaction/exec.cpp
@@ -81,7 +81,7 @@ void ProgramExec::runScripts(ProgramList::iterator first, ProgramList::iterator
return;
}
-ProgramExec::ProgramExec() : _modCounter(0) {
+ProgramExec::ProgramExec() : _modCounter(0), _instructionNames(NULL) {
}
diff --git a/engines/parallaction/font.cpp b/engines/parallaction/font.cpp
index 57b04deb12..f1c3b89ae8 100644
--- a/engines/parallaction/font.cpp
+++ b/engines/parallaction/font.cpp
@@ -302,7 +302,7 @@ protected:
}
public:
- DosFont(Cnv *cnv) : _data(cnv), _pitch(cnv->_width) {
+ DosFont(Cnv *cnv) : _data(cnv), _pitch(cnv->_width), _cp(NULL), _bufPitch(0) {
}
~DosFont() {
diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp
index f1499f7782..819804bfe7 100644
--- a/engines/parallaction/gfxbase.cpp
+++ b/engines/parallaction/gfxbase.cpp
@@ -32,7 +32,8 @@ namespace Parallaction {
GfxObj::GfxObj(uint objType, Frames *frames, const char* name) :
_frames(frames), x(0), y(0), z(0), _prog(0), _flags(0),
- type(objType), frame(0), layer(3), scale(100), _hasMask(false), _hasPath(false) {
+ type(objType), frame(0), layer(3), scale(100), _hasMask(false), _hasPath(false),
+ transparentKey(0), _maskId(0), _pathId(0) {
if (name) {
_name = strdup(name);
diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp
index 06b315016a..162671b68a 100644
--- a/engines/parallaction/graphics.cpp
+++ b/engines/parallaction/graphics.cpp
@@ -743,6 +743,8 @@ Gfx::Gfx(Parallaction* vm) :
_nextProjectorPos = 0;
_hbCircleRadius = 0;
+ _overlayMode = false;
+
_unpackedBitmap = new byte[MAXIMUM_UNPACKED_BITMAP_SIZE];
assert(_unpackedBitmap);
diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h
index 55e2bbca84..03b4dd97ef 100644
--- a/engines/parallaction/graphics.h
+++ b/engines/parallaction/graphics.h
@@ -57,7 +57,7 @@ protected:
public:
- Font() {}
+ Font() : _color(0) {}
virtual ~Font() {}
virtual void setColor(byte color) {
diff --git a/engines/parallaction/gui_br.cpp b/engines/parallaction/gui_br.cpp
index ae3d136b0e..17d759d26f 100644
--- a/engines/parallaction/gui_br.cpp
+++ b/engines/parallaction/gui_br.cpp
@@ -43,7 +43,8 @@ protected:
int _fadeSteps;
public:
- SplashInputState_BR(Parallaction *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm) {
+ SplashInputState_BR(Parallaction *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm),
+ _timeOut(0), _startTime(0), _fadeSteps(0) {
}
virtual MenuInputState* run() {
@@ -382,6 +383,9 @@ public:
_menuObj->getRect(0, _menuRect);
_cellW = _menuRect.width() / 3;
_cellH = _menuRect.height() / 2;
+
+ _menuObjId = _mscMenuObjId = _sfxMenuObjId = 0;
+ _sfxStatus = _mscStatus = 0;
}
~IngameMenuInputState_BR() {
diff --git a/engines/parallaction/gui_ns.cpp b/engines/parallaction/gui_ns.cpp
index 3d977c9e51..3c312c4f2d 100644
--- a/engines/parallaction/gui_ns.cpp
+++ b/engines/parallaction/gui_ns.cpp
@@ -43,7 +43,8 @@ protected:
Parallaction *_vm;
public:
- SplashInputState_NS(Parallaction *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm) {
+ SplashInputState_NS(Parallaction *vm, const Common::String &name, MenuInputHelper *helper) : MenuInputState(name, helper), _vm(vm),
+ _timeOut(0), _startTime(0) {
}
virtual MenuInputState* run() {
@@ -298,7 +299,7 @@ class LoadGameInputState_NS : public MenuInputState {
Parallaction *_vm;
public:
- LoadGameInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("loadgame", helper), _vm(vm) { }
+ LoadGameInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("loadgame", helper), _vm(vm), _result(false) { }
virtual MenuInputState* run() {
if (!_result) {
@@ -477,6 +478,11 @@ public:
_labels[0] = 0;
_labels[1] = 0;
+ _fail = false;
+ _len = 0;
+ _startTime = 0;
+ _state = 0;
+
_codeSelectBlocks[0] = Common::Rect( 111, 129, 127, 153 ); // na
_codeSelectBlocks[1] = Common::Rect( 128, 120, 144, 144 ); // wa
_codeSelectBlocks[2] = Common::Rect( 145, 111, 161, 135 ); // ra
@@ -689,6 +695,9 @@ public:
ShowCreditsInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("showcredits", helper), _vm(vm) {
_labels[0] = 0;
_labels[1] = 0;
+
+ _current = 0;
+ _startTime = 0;
}
~ShowCreditsInputState_NS() {
@@ -827,6 +836,8 @@ public:
_labels[1] = 0;
_labels[2] = 0;
_labels[3] = 0;
+
+ _allPartsComplete = false;
}
void destroyLabels() {
diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp
index 290af339bb..2cd85d7f1c 100644
--- a/engines/parallaction/input.cpp
+++ b/engines/parallaction/input.cpp
@@ -70,6 +70,9 @@ Input::Input(Parallaction *vm) : _vm(vm) {
_mouseButtons = 0;
_delayedActionZone.reset();
+ _inputMode = 0;
+ _hasKeyPressEvent = false;
+
_dinoCursor = 0;
_dougCursor = 0;
_donnaCursor = 0;
diff --git a/engines/parallaction/objects.cpp b/engines/parallaction/objects.cpp
index 50a5b38d8d..950d62a841 100644
--- a/engines/parallaction/objects.cpp
+++ b/engines/parallaction/objects.cpp
@@ -145,6 +145,8 @@ Program::Program() {
_locals = new LocalVariable[NUM_LOCALS];
_numLocals = 0;
_status = kProgramIdle;
+ _ip = 0;
+ _loopStart = 0;
}
Program::~Program() {
@@ -163,7 +165,7 @@ int16 Program::findLocal(const char* name) {
int16 Program::addLocal(const char *name, int16 value, int16 min, int16 max) {
assert(_numLocals < NUM_LOCALS);
- strcpy(_localNames[_numLocals], name);
+ Common::strlcpy(_localNames[_numLocals], name, 10);
_locals[_numLocals].setRange(min, max);
_locals[_numLocals].setValue(value);
@@ -259,6 +261,8 @@ Answer::Answer() {
_noFlags = 0;
_yesFlags = 0;
_hasCounterCondition = false;
+ _counterValue = 0;
+ _counterOp = 0;
}
bool Answer::textIsNull() {
@@ -298,6 +302,7 @@ Instruction::Instruction() {
// common
_immediate = 0;
+ _endif = 0;
// BRA specific
_text = 0;
diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp
index 2b75e78582..bbe759dffe 100644
--- a/engines/parallaction/parallaction.cpp
+++ b/engines/parallaction/parallaction.cpp
@@ -60,6 +60,7 @@ Parallaction::Parallaction(OSystem *syst, const PARALLACTIONGameDescription *gam
DebugMan.addDebugChannel(kDebugMenu, "menu", "Menu debug level");
DebugMan.addDebugChannel(kDebugInventory, "inventory", "Inventory debug level");
+ _screenWidth = 0;
_screenHeight = 0;
_screenSize = 0;
_gameType = 0;
@@ -86,6 +87,7 @@ Parallaction::Parallaction(OSystem *syst, const PARALLACTIONGameDescription *gam
_inventory = 0;
_currentLocationIndex = 0;
_numLocations = 0;
+ _language = 0;
}
Parallaction::~Parallaction() {
@@ -208,7 +210,7 @@ void Parallaction::allocateLocationSlot(const char *name) {
error("No more location slots available. Please report this immediately to ScummVM team");
if (_currentLocationIndex == -1) {
- strcpy(_locationNames[_numLocations], name);
+ Common::strlcpy(_locationNames[_numLocations], name, 10);
_currentLocationIndex = _numLocations;
_numLocations++;
diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h
index 6ea50584f8..c4839897ef 100644
--- a/engines/parallaction/parallaction.h
+++ b/engines/parallaction/parallaction.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef PARALLACTION_H
-#define PARALLACTION_H
+#ifndef PARALLACTION_PARALLACTION_H
+#define PARALLACTION_PARALLACTION_H
#include "common/str.h"
#include "common/stack.h"
diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp
index 1e1c0b0a3d..9f045cb397 100644
--- a/engines/parallaction/parallaction_br.cpp
+++ b/engines/parallaction/parallaction_br.cpp
@@ -320,7 +320,7 @@ void Parallaction_br::changeLocation() {
freeLocation(false);
// load new location
- strcpy(_location._name, _newLocationName.c_str());
+ Common::strlcpy(_location._name, _newLocationName.c_str(), 100);
parseLocation(_location._name);
if (_location._startPosition.x != -1000) {
diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp
index 144c2b3a98..5fd6d87985 100644
--- a/engines/parallaction/parallaction_ns.cpp
+++ b/engines/parallaction/parallaction_ns.cpp
@@ -395,7 +395,7 @@ void Parallaction_ns::changeLocation() {
changeCharacter(locname.character());
}
- strcpy(g_saveData1, locname.location());
+ Common::strlcpy(g_saveData1, locname.location(), 30);
parseLocation(g_saveData1);
if (_location._startPosition.x != -1000) {
diff --git a/engines/parallaction/parser.cpp b/engines/parallaction/parser.cpp
index c37cee692e..725a8b5996 100644
--- a/engines/parallaction/parser.cpp
+++ b/engines/parallaction/parser.cpp
@@ -226,6 +226,7 @@ uint16 Script::readLineToken(bool errorOnEOF) {
void Parser::reset() {
_currentOpcodes = 0;
_currentStatements = 0;
+ _lookup = 0;
_statements.clear();
_opcodes.clear();
diff --git a/engines/parallaction/parser.h b/engines/parallaction/parser.h
index 7b77f58eb0..e7ae7dcc36 100644
--- a/engines/parallaction/parser.h
+++ b/engines/parallaction/parser.h
@@ -405,7 +405,7 @@ protected:
virtual void parseRValue(ScriptVar &var, const char *str);
public:
- ProgramParser_br(Parallaction_br *vm) : ProgramParser_ns((Parallaction_ns*)vm), _vm(vm) {
+ ProgramParser_br(Parallaction_br *vm) : ProgramParser_ns((Parallaction_ns*)vm), _vm(vm), _openIfStatement(0) {
}
virtual void init();
diff --git a/engines/parallaction/saveload.cpp b/engines/parallaction/saveload.cpp
index eff088d5ee..0f4ceae7a5 100644
--- a/engines/parallaction/saveload.cpp
+++ b/engines/parallaction/saveload.cpp
@@ -93,7 +93,7 @@ void SaveLoad_ns::doLoadGame(uint16 slot) {
uint16 _si;
for (_si = 0; _si < _vm->_numLocations; _si++) {
s = f->readLine();
- strcpy(_vm->_locationNames[_si], s.c_str());
+ Common::strlcpy(_vm->_locationNames[_si], s.c_str(), 32);
s = f->readLine();
_vm->_localFlags[_si] = atoi(s.c_str());
diff --git a/engines/parallaction/sound_br.cpp b/engines/parallaction/sound_br.cpp
index d13b318ace..0147d3cd90 100644
--- a/engines/parallaction/sound_br.cpp
+++ b/engines/parallaction/sound_br.cpp
@@ -86,7 +86,7 @@ protected:
byte *_trackEnd;
public:
- MidiParser_MSC() : byte_11C5A(false) {
+ MidiParser_MSC() : byte_11C5A(false), _beats(0), _lastEvent(0), _trackEnd(NULL) {
}
};
@@ -467,6 +467,11 @@ SoundMan_br::SoundMan_br(Parallaction_br *vm) : _vm(vm) {
_musicEnabled = true;
_sfxEnabled = true;
+
+ _sfxLooping = false;
+ _sfxVolume = 0;
+ _sfxRate = 0;
+ _sfxChannel = 0;
}
SoundMan_br::~SoundMan_br() {
diff --git a/engines/parallaction/sound_ns.cpp b/engines/parallaction/sound_ns.cpp
index 692389b490..6073f82b82 100644
--- a/engines/parallaction/sound_ns.cpp
+++ b/engines/parallaction/sound_ns.cpp
@@ -323,6 +323,11 @@ void AmigaSoundMan_ns::playLocationMusic(const char *location) {
SoundMan_ns::SoundMan_ns(Parallaction_ns *vm) : _vm(vm) {
_mixer = _vm->_mixer;
+ _sfxLooping = false;
+ _sfxVolume = 0;
+ _sfxRate = 0;
+ _sfxChannel = 0;
+ _musicType = 0;
}
void SoundMan_ns::setMusicVolume(int value) {
@@ -330,7 +335,7 @@ void SoundMan_ns::setMusicVolume(int value) {
}
void SoundMan_ns::setMusicFile(const char *filename) {
- strcpy(_musicFile, filename);
+ Common::strlcpy(_musicFile, filename, PATH_LEN);
}
void SoundMan_ns::execute(int command, const char *parm = 0) {
diff --git a/engines/pegasus/neighborhood/mars/mars.cpp b/engines/pegasus/neighborhood/mars/mars.cpp
index df5a75541c..7c4a8a98ba 100644
--- a/engines/pegasus/neighborhood/mars/mars.cpp
+++ b/engines/pegasus/neighborhood/mars/mars.cpp
@@ -1950,7 +1950,7 @@ void Mars::pickedUpItem(Item *item) {
}
void Mars::dropItemIntoRoom(Item *item, Hotspot *dropSpot) {
- if (dropSpot->getObjectID() == kAttackRobotHotSpotID) {
+ if (dropSpot && dropSpot->getObjectID() == kAttackRobotHotSpotID) {
_attackingItem = (InventoryItem *)item;
startExtraSequence(kMars48RobotDefends, kExtraCompletedFlag, kFilterNoInput);
loadLoopSound2("");
diff --git a/engines/pegasus/pegasus.h b/engines/pegasus/pegasus.h
index d88545a4d1..57ae910def 100644
--- a/engines/pegasus/pegasus.h
+++ b/engines/pegasus/pegasus.h
@@ -23,8 +23,8 @@
*
*/
-#ifndef PEGASUS_H
-#define PEGASUS_H
+#ifndef PEGASUS_PEGASUS_H
+#define PEGASUS_PEGASUS_H
#include "common/list.h"
#include "common/macresman.h"
diff --git a/engines/prince/prince.cpp b/engines/prince/prince.cpp
index b39d26e056..f1fd5a25d3 100644
--- a/engines/prince/prince.cpp
+++ b/engines/prince/prince.cpp
@@ -1543,20 +1543,18 @@ void PrinceEngine::showAnim(Anim &anim) {
// make_special_shadow
if ((anim._flags & 0x80)) {
- if (animSurface) {
- DrawNode newDrawNode;
- newDrawNode.posX = x;
- newDrawNode.posY = y + animSurface->h - anim._shadowBack;
- newDrawNode.posZ = Hero::kHeroShadowZ;
- newDrawNode.width = 0;
- newDrawNode.height = 0;
- newDrawNode.scaleValue = _scaleValue;
- newDrawNode.originalRoomSurface = nullptr;
- newDrawNode.data = this;
- newDrawNode.drawFunction = &Hero::showHeroShadow;
- newDrawNode.s = animSurface;
- _drawNodeList.push_back(newDrawNode);
- }
+ DrawNode newDrawNode;
+ newDrawNode.posX = x;
+ newDrawNode.posY = y + animSurface->h - anim._shadowBack;
+ newDrawNode.posZ = Hero::kHeroShadowZ;
+ newDrawNode.width = 0;
+ newDrawNode.height = 0;
+ newDrawNode.scaleValue = _scaleValue;
+ newDrawNode.originalRoomSurface = nullptr;
+ newDrawNode.data = this;
+ newDrawNode.drawFunction = &Hero::showHeroShadow;
+ newDrawNode.s = animSurface;
+ _drawNodeList.push_back(newDrawNode);
}
//ShowFrameCodeShadow
diff --git a/engines/prince/prince.h b/engines/prince/prince.h
index 6dce044a41..82fcb152fa 100644
--- a/engines/prince/prince.h
+++ b/engines/prince/prince.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef PRINCE_H
-#define PRINCE_H
+#ifndef PRINCE_PRINCE_H
+#define PRINCE_PRINCE_H
#include "common/random.h"
#include "common/system.h"
diff --git a/engines/queen/queen.h b/engines/queen/queen.h
index c00e1b3a70..789025c264 100644
--- a/engines/queen/queen.h
+++ b/engines/queen/queen.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef QUEEN_H
-#define QUEEN_H
+#ifndef QUEEN_QUEEN_H
+#define QUEEN_QUEEN_H
#include "engines/engine.h"
#include "common/random.h"
diff --git a/engines/saga/interface.cpp b/engines/saga/interface.cpp
index cb09d53762..b08534c7fa 100644
--- a/engines/saga/interface.cpp
+++ b/engines/saga/interface.cpp
@@ -1170,7 +1170,7 @@ void Interface::processStatusTextInput(Common::KeyState keystate) {
_statusTextInputPos--;
_statusTextInputString[_statusTextInputPos] = 0;
default:
- if (_statusTextInputPos >= STATUS_TEXT_INPUT_MAX) {
+ if (_statusTextInputPos > STATUS_TEXT_INPUT_MAX) {
break;
}
if (Common::isAlnum(keystate.ascii) || (keystate.ascii == ' ')) {
@@ -2299,6 +2299,9 @@ void Interface::drawPanelButtonText(InterfacePanel *panel, PanelButton *panelBut
break;
}
if (_vm->getGameId() == GID_ITE) {
+ if (textId > kTextEnterProtectAnswer)
+ error("This should not happen. Please report to ScummVM Team how you achieved this error.");
+
text = _vm->getTextString(textId);
textFont = kKnownFontMedium;
textShadowKnownColor = kKnownColorVerbTextShadow;
diff --git a/engines/saga/isomap.cpp b/engines/saga/isomap.cpp
index 77680178c1..e50378b9c0 100644
--- a/engines/saga/isomap.cpp
+++ b/engines/saga/isomap.cpp
@@ -97,6 +97,23 @@ IsoMap::IsoMap(SagaEngine *vm) : _vm(vm) {
_viewScroll.x = (128 - 8) * 16;
_viewScroll.y = (128 - 8) * 16 - 64;
_viewDiff = 1;
+ _platformHeight = 0;
+ _queueCount = _readCount = 0;
+
+ for (int i = 0; i < SAGA_DRAGON_SEARCH_DIAMETER; i++)
+ for (int j = 0; j < SAGA_DRAGON_SEARCH_DIAMETER; j++)
+ _dragonSearchArray.cell[i][j].visited = _dragonSearchArray.cell[i][j].direction = 0;
+
+ for (int i = 0; i < SAGA_SEARCH_DIAMETER; i++)
+ for (int j = 0; j < SAGA_SEARCH_DIAMETER; j++)
+ _searchArray.cell[i][j].visited = _searchArray.cell[i][j].direction = 0;
+
+ for (int i = 0; i < SAGA_SEARCH_QUEUE_SIZE; i++) {
+ memset(&_dragonSearchArray.queue[i], 0, sizeof(DragonTilePoint));
+ memset(&_searchArray.queue[i], 0, sizeof(TilePoint));
+ }
+
+ memset(&_tileMap, 0, sizeof(TileMapData));
}
void IsoMap::loadImages(const ByteArray &resourceData) {
diff --git a/engines/saga/puzzle.cpp b/engines/saga/puzzle.cpp
index 099bf79e6b..2c9a02beec 100644
--- a/engines/saga/puzzle.cpp
+++ b/engines/saga/puzzle.cpp
@@ -86,6 +86,11 @@ Puzzle::Puzzle(SagaEngine *vm) : _vm(vm), _solved(false), _active(false) {
_hintBox.setWidth(240);
_hintBox.setHeight(30);
+ _hintNextRqState = kRQNoHint;
+ _hintGiver = 0;
+ _hintSpeaker = 0;
+ _slidePointX = _slidePointY = 0;
+
initPieceInfo( 0, 268, 18, 0, 0, 0 + PUZZLE_X_OFFSET, 0 + PUZZLE_Y_OFFSET, 0, 3,
Point(0, 1), Point(0, 62), Point(15, 31), Point(0, 0), Point(0, 0), Point(0,0));
initPieceInfo( 1, 270, 52, 0, 0, 0 + PUZZLE_X_OFFSET, 32 + PUZZLE_Y_OFFSET, 0, 4,
diff --git a/engines/saga/saga.h b/engines/saga/saga.h
index 06cb411e5a..422eaa530d 100644
--- a/engines/saga/saga.h
+++ b/engines/saga/saga.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef SAGA_H
-#define SAGA_H
+#ifndef SAGA_SAGA_H
+#define SAGA_SAGA_H
#include "engines/engine.h"
diff --git a/engines/saga/saveload.cpp b/engines/saga/saveload.cpp
index e659e09ce8..2d798bb0d6 100644
--- a/engines/saga/saveload.cpp
+++ b/engines/saga/saveload.cpp
@@ -56,7 +56,7 @@ SaveFileData *SagaEngine::getSaveFile(uint idx) {
return &_saveFiles[_saveFilesCount - idx - 1];
} else {
if (!emptySlot.name[0])
- strcpy(emptySlot.name, getTextString(kTextNewSave));
+ Common::strlcpy(emptySlot.name, getTextString(kTextNewSave), SAVE_TITLE_SIZE);
return (idx == 0) ? &emptySlot : &_saveFiles[_saveFilesCount - idx];
}
diff --git a/engines/saga/scene.cpp b/engines/saga/scene.cpp
index efd4c371b1..5cb4b55899 100644
--- a/engines/saga/scene.cpp
+++ b/engines/saga/scene.cpp
@@ -969,9 +969,8 @@ void Scene::processSceneResources(SceneResourceDataArray &resourceList) {
case SAGA_OBJECT:
break;
case SAGA_BG_IMAGE: // Scene background resource
- if (_bg.loaded) {
+ if (_bg.loaded)
error("Scene::processSceneResources() Multiple background resources encountered");
- }
debug(3, "Loading background resource.");
@@ -987,9 +986,9 @@ void Scene::processSceneResources(SceneResourceDataArray &resourceList) {
memcpy(_bg.pal, palPointer, sizeof(_bg.pal));
break;
case SAGA_BG_MASK: // Scene background mask resource
- if (_bgMask.loaded) {
+ if (_bgMask.loaded)
error("Scene::ProcessSceneResources(): Duplicate background mask resource encountered");
- }
+
debug(3, "Loading BACKGROUND MASK resource.");
_vm->decodeBGImage(resourceData, _bgMask.buffer, &_bgMask.w, &_bgMask.h, true);
_bgMask.loaded = true;
@@ -1014,47 +1013,38 @@ void Scene::processSceneResources(SceneResourceDataArray &resourceList) {
_actionMap->load(resourceData);
break;
case SAGA_ISO_IMAGES:
- if (!(_sceneDescription.flags & kSceneFlagISO)) {
+ if (!(_sceneDescription.flags & kSceneFlagISO))
error("Scene::ProcessSceneResources(): not Iso mode");
- }
debug(3, "Loading isometric images resource.");
_vm->_isoMap->loadImages(resourceData);
break;
case SAGA_ISO_MAP:
- if (!(_sceneDescription.flags & kSceneFlagISO)) {
+ if (!(_sceneDescription.flags & kSceneFlagISO))
error("Scene::ProcessSceneResources(): not Iso mode");
- }
debug(3, "Loading isometric map resource.");
-
_vm->_isoMap->loadMap(resourceData);
break;
case SAGA_ISO_PLATFORMS:
- if (!(_sceneDescription.flags & kSceneFlagISO)) {
+ if (!(_sceneDescription.flags & kSceneFlagISO))
error("Scene::ProcessSceneResources(): not Iso mode");
- }
debug(3, "Loading isometric platforms resource.");
-
_vm->_isoMap->loadPlatforms(resourceData);
break;
case SAGA_ISO_METATILES:
- if (!(_sceneDescription.flags & kSceneFlagISO)) {
+ if (!(_sceneDescription.flags & kSceneFlagISO))
error("Scene::ProcessSceneResources(): not Iso mode");
- }
debug(3, "Loading isometric metatiles resource.");
-
_vm->_isoMap->loadMetaTiles(resourceData);
break;
case SAGA_ANIM:
{
uint16 animId = resource->resourceType - 14;
-
debug(3, "Loading animation resource animId=%i", animId);
-
_vm->_anim->load(animId, resourceData);
}
break;
@@ -1063,9 +1053,8 @@ void Scene::processSceneResources(SceneResourceDataArray &resourceList) {
loadSceneEntryList(resourceData);
break;
case SAGA_ISO_MULTI:
- if (!(_sceneDescription.flags & kSceneFlagISO)) {
+ if (!(_sceneDescription.flags & kSceneFlagISO))
error("Scene::ProcessSceneResources(): not Iso mode");
- }
debug(3, "Loading isometric multi resource.");
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 1661f92cfe..51fb52bb21 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -2565,9 +2565,14 @@ bool Console::cmdVMVars(int argc, const char **argv) {
case 1:
case 2:
case 3: {
- // for global, local, temp and param, we need an index
if (argc < 3) {
- debugPrintf("Variable number must be specified for requested type\n");
+ for (int i = 0; i < s->variablesMax[varType]; ++i) {
+ curValue = &s->variables[varType][i];
+ debugPrintf("%s var %d == %04x:%04x", varNames[varType], i, PRINT_REG(*curValue));
+ printBasicVarInfo(*curValue);
+ debugPrintf("\n");
+ }
+
return true;
}
if (argc > 4) {
diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h
index 2ae9802d35..c01613268a 100644
--- a/engines/sci/detection_tables.h
+++ b/engines/sci/detection_tables.h
@@ -349,6 +349,19 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformDOS, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Conquests of Camelot - English Atari ST
+ // Game version 1.019.000
+ // Floppy: INT#10.12.90
+ // Executable reports "1.002.038"
+ {"camelot", "", {
+ {"resource.map", 0, "0f80a11867be91a158823887a49cf443", 7290},
+ {"resource.001", 0, "162f66c42e4146ee63f78fba6f1a6757", 596773},
+ {"resource.002", 0, "162f66c42e4146ee63f78fba6f1a6757", 724615},
+ {"resource.003", 0, "162f66c42e4146ee63f78fba6f1a6757", 713351},
+ {"resource.004", 0, "162f66c42e4146ee63f78fba6f1a6757", 718766},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Conquests of Camelot - English DOS
// SCI interpreter version 0.000.685
{"camelot", "", {
@@ -939,6 +952,22 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Hoyle 1 - English Atari ST
+ // Game version 1.000.104, SCI interpreter version 1.002.024
+ {"hoyle1", "", {
+ {"resource.001", 0, "e0dd44069a62a463fd124974b915f10d", 518127},
+ {"resource.map", 0, "0af9a3dcd72a091960de070432e1f524", 4386},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
+ // Hoyle 1 - English Atari ST
+ // Game version 1.000.108, SCI interpreter version 1.002.026
+ {"hoyle1", "", {
+ {"resource.map", 0, "ed8355f84752e49ffa1f0cf9eca4b28e", 4140},
+ {"resource.001", 0, "e0dd44069a62a463fd124974b915f10d", 517454},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Hoyle 2 - English DOS
// SCI interpreter version 0.000.572
{"hoyle2", "", {
@@ -982,6 +1011,15 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Hoyle 2 - English Atari ST
+ // Game version 1.001.017
+ // Executable scanning reports "1.002.034"
+ {"hoyle2", "", {
+ {"resource.map", 0, "13c8cc977598b6ad61d24c6296a090fd", 1356},
+ {"resource.001", 0, "8f2dd70abe01112eca464cda818b5eb6", 216280},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Hoyle 2 - English Macintosh
// Executable scanning reports "x.yyy.zzz"
{"hoyle2", "", {
@@ -1977,6 +2015,17 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Larry 2 - English Atari ST
+ // Game version 1.001.006
+ // Executable reports "1.000.159" 1988-12-02 12:22 p.m.
+ {"lsl2", "", {
+ {"resource.map", 0, "2fc3ce7da1346e4dadfee18606d814fc", 4758},
+ {"resource.001", 0, "4a24443a25e2b1492462a52809605dc2", 477342},
+ {"resource.002", 0, "4a24443a25e2b1492462a52809605dc2", 406698},
+ {"resource.003", 0, "4a24443a25e2b1492462a52809605dc2", 592433},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Larry 2 - English DOS Non-Interactive Demo
// Executable scanning reports "x.yyy.zzz"
// SCI interpreter version 0.000.409
@@ -2034,6 +2083,17 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformDOS, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Larry 2 - English Atari ST (Kixx)
+ // Game version 1.002.000
+ // Executable reports "1.001.008" 1989-01-12 16:30
+ {"lsl2", "", {
+ {"resource.map", 0, "2c9c3b0923e3764f5ab999bcb71c2d47", 4758},
+ {"resource.001", 0, "4a24443a25e2b1492462a52809605dc2", 477625},
+ {"resource.002", 0, "4a24443a25e2b1492462a52809605dc2", 406935},
+ {"resource.003", 0, "4a24443a25e2b1492462a52809605dc2", 592533},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Larry 3 - English Amiga (from www.back2roots.org)
// Executable scanning reports "1.002.032"
// SCI interpreter version 0.000.685
@@ -2048,6 +2108,19 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Larry 3 - English Atari ST
+ // Game version 1.021, 1990-01-27
+ // Int#6.26.90
+ // Executable scanning reports "1.002.026"
+ {"lsl3", "", {
+ {"resource.map", 0, "0b6bd3e039682830a51c5755c06591db", 5916},
+ {"resource.001", 0, "f18441027154292836b973c655fa3175", 456722},
+ {"resource.002", 0, "f18441027154292836b973c655fa3175", 578024},
+ {"resource.003", 0, "f18441027154292836b973c655fa3175", 506807},
+ {"resource.004", 0, "f18441027154292836b973c655fa3175", 513651},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Larry 3 - English DOS (supplied by ssburnout in bug report #3049193)
// 1.021 8x5.25" (label: Int#5.15.90)
{"lsl3", "", {
@@ -2916,6 +2989,17 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformDOS, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Police Quest 2 - English Atari ST
+ // Game version 1.002.011 DS 1989-07-21
+ // Executable reports "1.002.003"
+ {"pq2", "", {
+ {"resource.map", 0, "28a6f471c7900c2c92da40eecb615d9d", 4584},
+ {"resource.001", 0, "77f02def3094af804fd2371db25b7100", 509525},
+ {"resource.002", 0, "77f02def3094af804fd2371db25b7100", 546000},
+ {"resource.003", 0, "77f02def3094af804fd2371db25b7100", 591851},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Police Quest 2 - English DOS (from FRG)
// SCI interpreter version 0.000.395
{"pq2", "", {
@@ -2935,6 +3019,17 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformDOS, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Police Quest 2 - English Atari ST
+ // Game version 1.001.006 1989-01-16 13:30
+ // Executable reports "1.001.009"
+ {"pq2", "", {
+ {"resource.map", 0, "8e1161c684b342742d30f938a4839a4b", 4518},
+ {"resource.001", 0, "77f02def3094af804fd2371db25b7100", 506563},
+ {"resource.002", 0, "77f02def3094af804fd2371db25b7100", 541261},
+ {"resource.003", 0, "77f02def3094af804fd2371db25b7100", 587511},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Police Quest 2 - Japanese PC-98 (also includes english language)
// Executable scanning reports "x.yyy.zzz"
// SCI interpreter version unknown
@@ -3204,6 +3299,19 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformDOS, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Quest for Glory 1 / Hero's Quest - English Atari ST
+ // Game version 1.137
+ // Executable reports "1.002.028"
+ {"qfg1", "", {
+ {"resource.map", 0, "2a794066ad161acbedac8fa14e46905d", 6438},
+ {"resource.000", 0, "40332d3ebfc70a4b6a6a0443c2763287", 79204},
+ {"resource.001", 0, "f7fc269d3db146830d6427d3e02d4187", 473547},
+ {"resource.002", 0, "e64004e020fdf1813be52b639b08be89", 635687},
+ {"resource.003", 0, "f0af87c60ec869946da442833aa5afa8", 640438},
+ {"resource.004", 0, "f0af87c60ec869946da442833aa5afa8", 644452},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Quest for Glory 1 / Hero's Quest - English DOS Demo
// Executable scanning reports "0.000.685"
{"qfg1", "Demo", {
@@ -3283,6 +3391,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
// Quest for Glory 2 - English Amiga
+ // Game version 1.109
// Executable scanning reports "1.003.004"
// SCI interpreter version 0.001.010
{"qfg2", "", {
@@ -3705,6 +3814,18 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Space Quest 3 - English Atari ST
+ // Game version 1.0Q 1989-27-03 17:00
+ // Int#1.002.002
+ // Executable reports "1.002.001"
+ {"sq3", "", {
+ {"resource.map", 0, "c36e322805949affd882a75803a6a54e", 5484},
+ {"resource.001", 0, "ceeda7202b96e5c85ecaa88a40a540fc", 485146},
+ {"resource.002", 0, "ceeda7202b96e5c85ecaa88a40a540fc", 720227},
+ {"resource.003", 0, "ceeda7202b96e5c85ecaa88a40a540fc", 688524},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Space Quest 3 - German Amiga (also includes english language)
// Executable scanning reports "1.004.006"
// SCI interpreter version 0.000.453 (just a guess)
@@ -4235,6 +4356,16 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Torin's Passage - Russian Windows CD (SoftClub official translate)
+ // SCI interpreter version 2.100.002
+ // VERSION file "1.0"
+ { "torin", "",{
+ { "resource.aud", 0, "f66df699be5ed011b16b3f816cee8a04", 210583510 },
+ { "ressci.000", 0, "e672da099fb1663b87c78abc6c8ba2a4", 130622695 },
+ { "resmap.000", 0, "643859f8f2be8e7701611e29b3b65208", 9799 },
+ AD_LISTEND },
+ Common::RU_RUS, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Torin's Passage - English Macintosh
{"torin", "", {
{"Data1", 0, "63887e33cc282c92dc1f916f54aea8eb", 700786},
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index 3463d05e77..0ede307e6b 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -465,7 +465,7 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(CelWide), SIG_SCI16, SIGFOR_ALL, "ii(i)", NULL, kCelWide_workarounds },
#ifdef ENABLE_SCI32
{ "CelHigh", kCelHigh32, SIG_SCI32, SIGFOR_ALL, "iii", NULL, NULL },
- { "CelWide", kCelWide32, SIG_SCI32, SIGFOR_ALL, "iii", NULL, NULL },
+ { "CelWide", kCelWide32, SIG_SCI32, SIGFOR_ALL, "iii", NULL, kCelWide_workarounds },
#endif
{ MAP_CALL(CheckFreeSpace), SIG_SCI32, SIGFOR_ALL, "r.*", NULL, NULL },
{ MAP_CALL(CheckFreeSpace), SIG_SCI11, SIGFOR_ALL, "r(i)", NULL, NULL },
diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp
index d5540f72b1..6c51ec4284 100644
--- a/engines/sci/engine/kgraphics32.cpp
+++ b/engines/sci/engine/kgraphics32.cpp
@@ -216,6 +216,9 @@ reg_t kTextSize32(EngineState *s, int argc, reg_t *argv) {
g_sci->_gfxText32->setFont(argv[2].toUint16());
reg_t *rect = s->_segMan->derefRegPtr(argv[0], 4);
+ if (rect == nullptr) {
+ error("kTextSize: %04x:%04x cannot be dereferenced", PRINT_REG(argv[0]));
+ }
Common::String text = s->_segMan->getString(argv[1]);
int16 maxWidth = argc > 3 ? argv[3].toSint16() : 0;
diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp
index 303de079aa..6fd130bceb 100644
--- a/engines/sci/engine/kscripts.cpp
+++ b/engines/sci/engine/kscripts.cpp
@@ -260,9 +260,6 @@ reg_t kDisposeScript(EngineState *s, int argc, reg_t *argv) {
if (argc != 2) {
return s->r_acc;
} else {
- // This exists in the KQ5CD and GK1 interpreter. We know it is used
- // when GK1 starts up, before the Sierra logo.
- warning("kDisposeScript called with 2 parameters, still untested");
return argv[1];
}
}
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index 0cc1e752e1..302f046458 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -806,8 +806,6 @@ void GfxPalette32::saveLoadWithSerializer(Common::Serializer &s) {
s.syncAsUint16LE(cycler->numTimesPaused);
}
}
-
- // TODO: _clutTable
}
#endif
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index 8039c5f282..116ffdd5a2 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -2934,6 +2934,84 @@ static const uint16 qfg3PatchChiefPriority[] = {
PATCH_END
};
+// There are 3 points that can't be achieved in the game. They should've been
+// awarded for telling Rakeesh and Kreesha (room 285) about the Simabni
+// initiation.
+// However the array of posibble messages the hero can tell in that room
+// (local 156) is missing the "Tell about Initiation" message (#31) which
+// awards these points.
+// This patch adds the message to that array, thus allowing the hero to tell
+// that message (after completing the initiation) and gain the 3 points.
+// A side effect of increasing the local156 array is that the next local
+// array is shifted and shrinks in size from 4 words to 3. The patch changes
+// the 2 locations in the script that reference that array, to point to the new
+// location ($aa --> $ab). It is safe to shrink the 2nd array to 3 words
+// because only the first element in it is ever used.
+//
+// Note: You have to re-enter the room in case a saved game was loaded from a
+// previous version of ScummVM and that saved game was made inside that room.
+//
+// Applies to: English, French, German, Italian, Spanish and the GOG release.
+// Responsible method: heap in script 285
+// Fixes bug #7086
+static const uint16 qfg3SignatureMissingPoints1[] = {
+ // local[$9c] = [0 -41 -76 1 -30 -77 -33 -34 -35 -36 -37 -42 -80 999]
+ // local[$aa] = [0 0 0 0]
+ SIG_UINT16(0x0000), // 0 START MARKER
+ SIG_MAGICDWORD,
+ SIG_UINT16(0xFFD7), // -41 "Greet"
+ SIG_UINT16(0xFFB4), // -76 "Say Good-bye"
+ SIG_UINT16(0x0001), // 1 "Tell about Tarna"
+ SIG_UINT16(0xFFE2), // -30 "Tell about Simani"
+ SIG_UINT16(0xFFB3), // -77 "Tell about Prisoner"
+ SIG_UINT16(0xFFDF), // -33 "Dispelled Leopard Lady"
+ SIG_UINT16(0xFFDE), // -34 "Tell about Leopard Lady"
+ SIG_UINT16(0xFFDD), // -35 "Tell about Leopard Lady"
+ SIG_UINT16(0xFFDC), // -36 "Tell about Leopard Lady"
+ SIG_UINT16(0xFFDB), // -37 "Tell about Village"
+ SIG_UINT16(0xFFD6), // -42 "Greet"
+ SIG_UINT16(0xFFB0), // -80 "Say Good-bye"
+ SIG_UINT16(0x03E7), // 999 END MARKER
+ SIG_ADDTOOFFSET(+2), // local[$aa][0]
+ SIG_END
+};
+
+static const uint16 qfg3PatchMissingPoints1[] = {
+ PATCH_ADDTOOFFSET(+14),
+ PATCH_UINT16(0xFFE1), // -31 "Tell about Initiation"
+ PATCH_UINT16(0xFFDE), // -34 "Tell about Leopard Lady"
+ PATCH_UINT16(0xFFDD), // -35 "Tell about Leopard Lady"
+ PATCH_UINT16(0xFFDC), // -36 "Tell about Leopard Lady"
+ PATCH_UINT16(0xFFDB), // -37 "Tell about Village"
+ PATCH_UINT16(0xFFD6), // -42 "Greet"
+ PATCH_UINT16(0xFFB0), // -80 "Say Good-bye"
+ PATCH_UINT16(0x03E7), // 999 END MARKER
+ PATCH_GETORIGINALBYTE(+28), // local[$aa][0].low
+ PATCH_GETORIGINALBYTE(+29), // local[$aa][0].high
+ PATCH_END
+};
+
+static const uint16 qfg3SignatureMissingPoints2a[] = {
+ SIG_MAGICDWORD,
+ 0x35, 0x00, // ldi 0
+ 0xb3, 0xaa, // sali local[$aa]
+ SIG_END
+};
+
+static const uint16 qfg3SignatureMissingPoints2b[] = {
+ SIG_MAGICDWORD,
+ 0x36, // push
+ 0x5b, 0x02, 0xaa, // lea local[$aa]
+ SIG_END
+};
+
+static const uint16 qfg3PatchMissingPoints2[] = {
+ PATCH_ADDTOOFFSET(+3),
+ 0xab, // local[$aa] ==> local[$ab]
+ PATCH_END
+};
+
+
// Partly WORKAROUND:
// During combat, the game is not properly throttled. That's because the game uses
// an inner loop for combat and does not iterate through the main loop.
@@ -2995,14 +3073,17 @@ static const uint16 qfg3PatchCombatSpeedThrottling2[] = {
// script, description, signature patch
static const SciScriptPatcherEntry qfg3Signatures[] = {
- { true, 944, "import dialog continuous calls", 1, qfg3SignatureImportDialog, qfg3PatchImportDialog },
- { true, 440, "dialog crash when asking about Woo", 1, qfg3SignatureWooDialog, qfg3PatchWooDialog },
- { true, 440, "dialog crash when asking about Woo", 1, qfg3SignatureWooDialogAlt, qfg3PatchWooDialogAlt },
- { true, 52, "export character save bug", 2, qfg3SignatureExportChar, qfg3PatchExportChar },
- { true, 54, "import character from QfG1 bug", 1, qfg3SignatureImportQfG1Char, qfg3PatchImportQfG1Char },
- { true, 640, "chief in hut priority fix", 1, qfg3SignatureChiefPriority, qfg3PatchChiefPriority },
- { true, 550, "combat speed throttling script", 1, qfg3SignatureCombatSpeedThrottling1, qfg3PatchCombatSpeedThrottling1 },
- { true, 550, "combat speed throttling heap", 1, qfg3SignatureCombatSpeedThrottling2, qfg3PatchCombatSpeedThrottling2 },
+ { true, 944, "import dialog continuous calls", 1, qfg3SignatureImportDialog, qfg3PatchImportDialog },
+ { true, 440, "dialog crash when asking about Woo", 1, qfg3SignatureWooDialog, qfg3PatchWooDialog },
+ { true, 440, "dialog crash when asking about Woo", 1, qfg3SignatureWooDialogAlt, qfg3PatchWooDialogAlt },
+ { true, 52, "export character save bug", 2, qfg3SignatureExportChar, qfg3PatchExportChar },
+ { true, 54, "import character from QfG1 bug", 1, qfg3SignatureImportQfG1Char, qfg3PatchImportQfG1Char },
+ { true, 640, "chief in hut priority fix", 1, qfg3SignatureChiefPriority, qfg3PatchChiefPriority },
+ { true, 285, "missing points for telling about initiation heap", 1, qfg3SignatureMissingPoints1, qfg3PatchMissingPoints1 },
+ { true, 285, "missing points for telling about initiation script", 1, qfg3SignatureMissingPoints2a, qfg3PatchMissingPoints2 },
+ { true, 285, "missing points for telling about initiation script", 1, qfg3SignatureMissingPoints2b, qfg3PatchMissingPoints2 },
+ { true, 550, "combat speed throttling script", 1, qfg3SignatureCombatSpeedThrottling1, qfg3PatchCombatSpeedThrottling1 },
+ { true, 550, "combat speed throttling heap", 1, qfg3SignatureCombatSpeedThrottling2, qfg3PatchCombatSpeedThrottling2 },
SCI_SIGNATUREENTRY_TERMINATOR
};
diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index 3832f4cf04..0cb8ff48d7 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -407,6 +407,7 @@ const SciWorkaroundEntry kCelWide_workarounds[] = {
{ GID_PQ2, -1, 255, 0, "DIcon", "setSize", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // when showing picture within windows, called with 2nd/3rd parameters as objects
{ GID_SQ1, 1, 255, 0, "DIcon", "setSize", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // DEMO: Called with 2nd/3rd parameters as objects when clicking on the menu - bug #5012
{ GID_FANMADE, -1, 979, 0, "DIcon", "setSize", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // In The Gem Scenario and perhaps other fanmade games, this is called with 2nd/3rd parameters as objects - bug #5144
+ { GID_LSL6HIRES, -1, 94, 0, "ll6ControlPanel", "init", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // when opening the "controls" panel from the main menu, the third argument is missing
SCI_WORKAROUNDENTRY_TERMINATOR
};
diff --git a/engines/sci/graphics/celobj32.cpp b/engines/sci/graphics/celobj32.cpp
index 693bc5f196..77d333a717 100644
--- a/engines/sci/graphics/celobj32.cpp
+++ b/engines/sci/graphics/celobj32.cpp
@@ -120,6 +120,7 @@ struct SCALER_NoScale {
const int16 _sourceY;
SCALER_NoScale(const CelObj &celObj, const int16 maxWidth, const Common::Point &scaledPosition) :
+ _row(nullptr),
_reader(celObj, FLIP ? celObj._width : maxWidth),
_lastIndex(celObj._width - 1),
_sourceX(scaledPosition.x),
@@ -166,6 +167,7 @@ struct SCALER_Scale {
static int16 _valuesY[1024];
SCALER_Scale(const CelObj &celObj, const Common::Rect &targetRect, const Common::Point &scaledPosition, const Ratio scaleX, const Ratio scaleY) :
+ _row(nullptr),
#ifndef NDEBUG
_maxX(targetRect.right - 1),
#endif
@@ -525,30 +527,30 @@ int CelObj::_nextCacheId = 1;
CelCache *CelObj::_cache = nullptr;
int CelObj::searchCache(const CelInfo32 &celInfo, int *nextInsertIndex) const {
+ *nextInsertIndex = -1;
int oldestId = _nextCacheId + 1;
- int oldestIndex = -1;
+ int oldestIndex = 0;
for (int i = 0, len = _cache->size(); i < len; ++i) {
CelCacheEntry &entry = (*_cache)[i];
- if (entry.celObj != nullptr) {
- if (entry.celObj->_info == celInfo) {
- entry.id = ++_nextCacheId;
- return i;
+ if (entry.celObj == nullptr) {
+ if (*nextInsertIndex == -1) {
+ *nextInsertIndex = i;
}
-
- if (oldestId > entry.id) {
- oldestId = entry.id;
- oldestIndex = i;
- }
- } else if (oldestIndex == -1) {
+ } else if (entry.celObj->_info == celInfo) {
+ entry.id = ++_nextCacheId;
+ return i;
+ } else if (oldestId > entry.id) {
+ oldestId = entry.id;
oldestIndex = i;
}
}
- // NOTE: Unlike the original SCI engine code, the out-param
- // here is only updated if there was not a cache hit.
- *nextInsertIndex = oldestIndex;
+ if (*nextInsertIndex == -1) {
+ *nextInsertIndex = oldestIndex;
+ }
+
return -1;
}
@@ -734,7 +736,11 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int
int cacheIndex = searchCache(_info, &cacheInsertIndex);
if (cacheIndex != -1) {
CelCacheEntry &entry = (*_cache)[cacheIndex];
- *this = *dynamic_cast<CelObjView *>(entry.celObj);
+ const CelObjView *const cachedCelObj = dynamic_cast<CelObjView *>(entry.celObj);
+ if (cachedCelObj == nullptr) {
+ error("Expected a CelObjView in cache slot %d", cacheIndex);
+ }
+ *this = *cachedCelObj;
entry.id = ++_nextCacheId;
return;
}
@@ -866,7 +872,11 @@ CelObjView *CelObjView::duplicate() const {
}
byte *CelObjView::getResPointer() const {
- return g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, _info.resourceId), false)->data;
+ const Resource *const resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, _info.resourceId), false);
+ if (resource == nullptr) {
+ error("Failed to load view %d from resource manager", _info.resourceId);
+ }
+ return resource->data;
}
#pragma mark -
@@ -885,7 +895,11 @@ CelObjPic::CelObjPic(const GuiResourceId picId, const int16 celNo) {
int cacheIndex = searchCache(_info, &cacheInsertIndex);
if (cacheIndex != -1) {
CelCacheEntry &entry = (*_cache)[cacheIndex];
- *this = *dynamic_cast<CelObjPic *>(entry.celObj);
+ const CelObjPic *const cachedCelObj = dynamic_cast<CelObjPic *>(entry.celObj);
+ if (cachedCelObj == nullptr) {
+ error("Expected a CelObjPic in cache slot %d", cacheIndex);
+ }
+ *this = *cachedCelObj;
entry.id = ++_nextCacheId;
return;
}
@@ -979,7 +993,11 @@ CelObjPic *CelObjPic::duplicate() const {
}
byte *CelObjPic::getResPointer() const {
- return g_sci->getResMan()->findResource(ResourceId(kResourceTypePic, _info.resourceId), false)->data;
+ const Resource *const resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypePic, _info.resourceId), false);
+ if (resource == nullptr) {
+ error("Failed to load pic %d from resource manager", _info.resourceId);
+ }
+ return resource->data;
}
#pragma mark -
diff --git a/engines/sci/graphics/celobj32.h b/engines/sci/graphics/celobj32.h
index 0bb4b03ae2..6e401b3df4 100644
--- a/engines/sci/graphics/celobj32.h
+++ b/engines/sci/graphics/celobj32.h
@@ -474,7 +474,7 @@ private:
bool analyzeForRemap() const;
public:
- CelObjView(GuiResourceId viewId, int16 loopNo, int16 celNo);
+ CelObjView(const GuiResourceId viewId, const int16 loopNo, const int16 celNo);
virtual ~CelObjView() override {};
using CelObj::draw;
@@ -525,7 +525,7 @@ public:
*/
int16 _priority;
- CelObjPic(GuiResourceId pictureId, int16 celNo);
+ CelObjPic(const GuiResourceId pictureId, const int16 celNo);
virtual ~CelObjPic() override {};
using CelObj::draw;
@@ -546,7 +546,7 @@ public:
*/
class CelObjMem : public CelObj {
public:
- CelObjMem(reg_t bitmap);
+ CelObjMem(const reg_t bitmap);
virtual ~CelObjMem() override {};
virtual CelObjMem *duplicate() const override;
@@ -562,7 +562,7 @@ public:
*/
class CelObjColor : public CelObj {
public:
- CelObjColor(uint8 color, int16 width, int16 height);
+ CelObjColor(const uint8 color, const int16 width, const int16 height);
virtual ~CelObjColor() override {};
using CelObj::draw;
diff --git a/engines/sci/graphics/compare.cpp b/engines/sci/graphics/compare.cpp
index 729eeeaf81..130416ff60 100644
--- a/engines/sci/graphics/compare.cpp
+++ b/engines/sci/graphics/compare.cpp
@@ -162,12 +162,20 @@ reg_t GfxCompare::kernelCantBeHere32(const reg_t curObject, const reg_t listRefe
// rects before operating on them, but this call leverages SCI16 engine
// code that operates on inclusive rects, so the rect's bottom-right
// point is not modified like in other SCI32 kernel calls
- Common::Rect checkRect(
- readSelectorValue(_segMan, curObject, SELECTOR(brLeft)),
- readSelectorValue(_segMan, curObject, SELECTOR(brTop)),
- readSelectorValue(_segMan, curObject, SELECTOR(brRight)),
- readSelectorValue(_segMan, curObject, SELECTOR(brBottom))
- );
+ Common::Rect checkRect;
+
+ // At least LSL6 hires passes invalid rectangles which trigger the
+ // isValidRect assertion in the Rect constructor; this is avoided by
+ // assigning the properties after construction and then testing the
+ // rect for validity ourselves here. SSCI does not care about whether
+ // or not the rects are valid
+ checkRect.left = readSelectorValue(_segMan, curObject, SELECTOR(brLeft));
+ checkRect.top = readSelectorValue(_segMan, curObject, SELECTOR(brTop));
+ checkRect.right = readSelectorValue(_segMan, curObject, SELECTOR(brRight));
+ checkRect.bottom = readSelectorValue(_segMan, curObject, SELECTOR(brBottom));
+ if (!checkRect.isValidRect()) {
+ return make_reg(0, 0);
+ }
uint16 result = 0;
uint16 signal = readSelectorValue(_segMan, curObject, SELECTOR(signal));
diff --git a/engines/sci/graphics/controls32.cpp b/engines/sci/graphics/controls32.cpp
index a877d8c276..faf1d7d1a2 100644
--- a/engines/sci/graphics/controls32.cpp
+++ b/engines/sci/graphics/controls32.cpp
@@ -104,10 +104,7 @@ reg_t GfxControls32::kernelEditText(const reg_t controlObject) {
bool dimmed = readSelectorValue(_segMan, controlObject, SELECTOR(dimmed));
editor.bitmap = _gfxText32->createFontBitmap(width, height, editor.textRect, editor.text, editor.foreColor, editor.backColor, editor.skipColor, editor.fontId, alignment, editor.borderColor, dimmed, true);
} else {
- Common::String title = _segMan->getString(titleObject);
- int16 titleBackColor = readSelectorValue(_segMan, controlObject, SELECTOR(titleBack));
- int16 titleForeColor = readSelectorValue(_segMan, controlObject, SELECTOR(titleFore));
- editor.bitmap = _gfxText32->createTitledBitmap(width, height, editor.textRect, editor.text, editor.foreColor, editor.backColor, editor.skipColor, editor.fontId, alignment, editor.borderColor, title, titleForeColor, titleBackColor, titleFontId, true);
+ error("Titled bitmaps are not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
}
}
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index 6454a1eb32..64ae828a50 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -680,7 +680,7 @@ void GfxFrameout::calcLists(ScreenItemListList &drawLists, EraseListList &eraseL
int splitCount = splitRects(*rectlist[rectIndex], _planes[innerIndex]->_screenRect, outRects);
if (splitCount == 0) {
- if (visibleInnerPlane != nullptr) {
+ if (visibleInnerPlane != nullptr && visibleOuterPlane != nullptr) {
// same priority, or relative priority between inner/outer changed
if ((visibleOuterPlane->_priority - visibleInnerPlane->_priority) * (outerPlane->_priority - innerPlane->_priority) <= 0) {
if (outerPlane->_priority <= innerPlane->_priority) {
@@ -697,7 +697,7 @@ void GfxFrameout::calcLists(ScreenItemListList &drawLists, EraseListList &eraseL
rectlist.add(outRects[i]);
}
- if (visibleInnerPlane != nullptr) {
+ if (visibleInnerPlane != nullptr && visibleOuterPlane != nullptr) {
// same priority, or relative priority between inner/outer changed
if ((visibleOuterPlane->_priority - visibleInnerPlane->_priority) * (outerPlane->_priority - innerPlane->_priority) <= 0) {
*rectlist[rectIndex] = outerPlane->_screenRect.findIntersectingRect(innerPlane->_screenRect);
@@ -987,7 +987,7 @@ void GfxFrameout::alterVmap(const Palette &palette1, const Palette &palette2, co
if (styleRanges[paletteIndex] == style) {
int minDiff = 262140;
- int minDiffIndex;
+ int minDiffIndex = paletteIndex;
for (int i = 0; i < 236; ++i) {
if (styleRanges[i] != style) {
@@ -1007,7 +1007,7 @@ void GfxFrameout::alterVmap(const Palette &palette1, const Palette &palette2, co
if (style == 1 && styleRanges[paletteIndex] == 0) {
int minDiff = 262140;
- int minDiffIndex;
+ int minDiffIndex = paletteIndex;
for (int i = 0; i < 236; ++i) {
int r = palette2.colors[i].r;
diff --git a/engines/sci/graphics/plane32.cpp b/engines/sci/graphics/plane32.cpp
index d05e4f79e1..470986fb3c 100644
--- a/engines/sci/graphics/plane32.cpp
+++ b/engines/sci/graphics/plane32.cpp
@@ -45,8 +45,6 @@ void DrawList::add(ScreenItem *screenItem, const Common::Rect &rect) {
uint16 Plane::_nextObjectId = 20000;
Plane::Plane(const Common::Rect &gameRect, PlanePictureCodes pictureId) :
-_width(g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth),
-_height(g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight),
_pictureId(pictureId),
_mirrored(false),
_back(0),
@@ -65,8 +63,6 @@ _gameRect(gameRect) {
}
Plane::Plane(reg_t object) :
-_width(g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth),
-_height(g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight),
_priorityChanged(false),
_object(object),
_redrawAllCount(g_sci->_gfxFrameout->getScreenCount()),
@@ -97,8 +93,6 @@ _moved(0) {
Plane::Plane(const Plane &other) :
_pictureId(other._pictureId),
_mirrored(other._mirrored),
-_field_34(other._field_34), _field_38(other._field_38),
-_field_3C(other._field_3C), _field_40(other._field_40),
_back(other._back),
_object(other._object),
_priority(other._priority),
@@ -116,11 +110,7 @@ void Plane::operator=(const Plane &other) {
_mirrored = other._mirrored;
_priority = other._priority;
_back = other._back;
- _width = other._width;
- _field_34 = other._field_34;
- _height = other._height;
_screenRect = other._screenRect;
- _field_3C = other._field_3C;
_priorityChanged = other._priorityChanged;
}
@@ -183,7 +173,7 @@ void Plane::addPicInternal(const GuiResourceId pictureId, const Common::Point *p
screenItem->_pictureId = pictureId;
screenItem->_mirrorX = mirrorX;
screenItem->_priority = celObj->_priority;
- screenItem->_fixPriority = true;
+ screenItem->_fixedPriority = true;
if (position != nullptr) {
screenItem->_position = *position + celObj->_relativePosition;
} else {
@@ -769,8 +759,6 @@ void Plane::sync(const Plane *other, const Common::Rect &screenRect) {
}
convertGameRectToPlaneRect();
- _width = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
- _height = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
_screenRect = _planeRect;
// NOTE: screenRect originally was retrieved through globals
// instead of being passed into the function
diff --git a/engines/sci/graphics/plane32.h b/engines/sci/graphics/plane32.h
index 770a6fa445..c93fb5b64e 100644
--- a/engines/sci/graphics/plane32.h
+++ b/engines/sci/graphics/plane32.h
@@ -101,16 +101,6 @@ private:
static uint16 _nextObjectId;
/**
- * The dimensions of the plane, in game script
- * coordinates.
- * TODO: These are never used and are always
- * scriptWidth x scriptHeight in SCI engine? The actual
- * dimensions of the plane are always in
- * gameRect/planeRect.
- */
- int16 _width, _height;
-
- /**
* For planes that are used to render picture data, the
* resource ID of the picture to be displayed. This
* value may also be one of the special
@@ -135,10 +125,6 @@ private:
*/
bool _pictureChanged;
- // TODO: Are these ever actually used?
- int _field_34, _field_38; // probably a point or ratio
- int _field_3C, _field_40; // probably a point or ratio
-
/**
* Converts the dimensions of the game rect used by
* scripts to the dimensions of the plane rect used to
@@ -275,7 +261,11 @@ public:
* given screen rect.
*/
inline void clipScreenRect(const Common::Rect &screenRect) {
- if (_screenRect.intersects(screenRect)) {
+ // LSL6 hires creates planes with invalid rects; SSCI does not
+ // care about this, but `Common::Rect::clip` does, so we need to
+ // check whether or not the rect is actually valid before clipping
+ // and only clip valid rects
+ if (_screenRect.isValidRect() && _screenRect.intersects(screenRect)) {
_screenRect.clip(screenRect);
} else {
_screenRect.left = 0;
diff --git a/engines/sci/graphics/screen_item32.cpp b/engines/sci/graphics/screen_item32.cpp
index c3fdbb6845..fba0fa0422 100644
--- a/engines/sci/graphics/screen_item32.cpp
+++ b/engines/sci/graphics/screen_item32.cpp
@@ -55,7 +55,7 @@ _useInsetRect(false),
_z(0),
_celInfo(celInfo),
_celObj(nullptr),
-_fixPriority(false),
+_fixedPriority(false),
_position(0, 0),
_object(make_reg(0, _nextObjectId++)),
_pictureId(-1),
@@ -70,7 +70,7 @@ _useInsetRect(false),
_z(0),
_celInfo(celInfo),
_celObj(nullptr),
-_fixPriority(false),
+_fixedPriority(false),
_position(rect.left, rect.top),
_object(make_reg(0, _nextObjectId++)),
_pictureId(-1),
@@ -90,7 +90,7 @@ _useInsetRect(false),
_z(0),
_celInfo(celInfo),
_celObj(nullptr),
-_fixPriority(false),
+_fixedPriority(false),
_position(position),
_object(make_reg(0, _nextObjectId++)),
_pictureId(-1),
@@ -209,10 +209,10 @@ void ScreenItem::setFromObject(SegManager *segMan, const reg_t object, const boo
}
if (readSelectorValue(segMan, object, SELECTOR(fixPriority))) {
- _fixPriority = true;
+ _fixedPriority = true;
_priority = readSelectorValue(segMan, object, SELECTOR(priority));
} else {
- _fixPriority = false;
+ _fixedPriority = false;
writeSelectorValue(segMan, object, SELECTOR(priority), _position.y);
}
@@ -326,6 +326,9 @@ void ScreenItem::calcRects(const Plane &plane) {
mulinc(temp, celToScreenX, Ratio());
CelObjPic *celObjPic = dynamic_cast<CelObjPic *>(_celObj);
+ if (celObjPic == nullptr) {
+ error("Expected a CelObjPic");
+ }
temp.translate((celObjPic->_relativePosition.x * scriptToScreenX).toInt() - displaceX, 0);
// TODO: This is weird.
@@ -369,6 +372,9 @@ void ScreenItem::calcRects(const Plane &plane) {
}
CelObjPic *celObjPic = dynamic_cast<CelObjPic *>(_celObj);
+ if (celObjPic == nullptr) {
+ error("Expected a CelObjPic");
+ }
temp.translate(celObjPic->_relativePosition.x - (displaceX * scaleX).toInt(), celObjPic->_relativePosition.y - (celObj._displace.y * scaleY).toInt());
// TODO: This is weird.
@@ -402,7 +408,7 @@ void ScreenItem::calcRects(const Plane &plane) {
_screenRect.top = 0;
}
- if (!_fixPriority) {
+ if (!_fixedPriority) {
_priority = _z + _position.y;
}
} else {
diff --git a/engines/sci/graphics/screen_item32.h b/engines/sci/graphics/screen_item32.h
index 977d80ebad..91f54b48e9 100644
--- a/engines/sci/graphics/screen_item32.h
+++ b/engines/sci/graphics/screen_item32.h
@@ -132,7 +132,7 @@ public:
* in place. Otherwise, the priority of the screen item
* is calculated from its y-position + z-index.
*/
- bool _fixPriority;
+ bool _fixedPriority;
/**
* The rendering priority of the screen item, relative
@@ -273,7 +273,7 @@ public:
typedef StablePointerArray<ScreenItem, 250> ScreenItemListBase;
class ScreenItemList : public ScreenItemListBase {
- static bool inline sortHelper(const ScreenItem *a, const ScreenItem *b) {
+ inline static bool sortHelper(const ScreenItem *a, const ScreenItem *b) {
return *a < *b;
}
public:
diff --git a/engines/sci/graphics/text32.cpp b/engines/sci/graphics/text32.cpp
index 99ffc6e328..d1c223d5d5 100644
--- a/engines/sci/graphics/text32.cpp
+++ b/engines/sci/graphics/text32.cpp
@@ -48,12 +48,6 @@ GfxText32::GfxText32(SegManager *segMan, GfxCache *fonts) :
// Not a typo, the original engine did not initialise height, only width
_width(0),
_text(""),
- _field_20(0),
- _field_2C(2),
- _field_30(0),
- _field_34(0),
- _field_38(0),
- _field_3C(0),
_bitmap(NULL_REG) {
_fontId = _defaultFontId;
_font = _cache->getFont(_defaultFontId);
@@ -61,7 +55,6 @@ GfxText32::GfxText32(SegManager *segMan, GfxCache *fonts) :
reg_t GfxText32::createFontBitmap(int16 width, int16 height, const Common::Rect &rect, const Common::String &text, const uint8 foreColor, const uint8 backColor, const uint8 skipColor, const GuiResourceId fontId, const TextAlign alignment, const int16 borderColor, const bool dimmed, const bool doScaling) {
- _field_22 = 0;
_borderColor = borderColor;
_text = text;
_textRect = rect;
@@ -111,7 +104,6 @@ reg_t GfxText32::createFontBitmap(int16 width, int16 height, const Common::Rect
}
reg_t GfxText32::createFontBitmap(const CelInfo32 &celInfo, const Common::Rect &rect, const Common::String &text, const int16 foreColor, const int16 backColor, const GuiResourceId fontId, const int16 skipColor, const int16 borderColor, const bool dimmed) {
- _field_22 = 0;
_borderColor = borderColor;
_text = text;
_textRect = rect;
@@ -171,11 +163,6 @@ reg_t GfxText32::createFontBitmap(const CelInfo32 &celInfo, const Common::Rect &
return _bitmap;
}
-reg_t GfxText32::createTitledBitmap(const int16 width, const int16 height, const Common::Rect &textRect, const Common::String &text, const int16 foreColor, const int16 backColor, const int16 skipColor, const GuiResourceId fontId, const TextAlign alignment, const int16 borderColor, Common::String &title, const int16 titleForeColor, const int16 titleBackColor, const GuiResourceId titleFontId, const bool doScaling) {
- warning("TODO: createTitledBitmap incomplete !");
- return createFontBitmap(width, height, textRect, text, foreColor, backColor, skipColor, fontId, alignment, borderColor, false, doScaling);
-}
-
void GfxText32::setFont(const GuiResourceId fontId) {
// NOTE: In SCI engine this calls FontMgr::BuildFontTable and then a font
// table is built on the FontMgr directly; instead, because we already have
@@ -558,12 +545,7 @@ Common::Rect GfxText32::getTextSize(const Common::String &text, int16 maxWidth,
if (maxWidth >= 0) {
if (maxWidth == 0) {
- // TODO: This was hardcoded to 192, but guessing
- // that it was originally 60% of the scriptWidth
- // before the compiler took over.
- // Verify this by looking at a game that uses a
- // scriptWidth other than 320, like LSL7
- maxWidth = _scaledWidth * (scriptWidth * 0.6) / scriptWidth;
+ maxWidth = _scaledWidth * 3 / 5;
}
result.right = maxWidth;
diff --git a/engines/sci/graphics/text32.h b/engines/sci/graphics/text32.h
index 5768ea0c59..20adb3d7c7 100644
--- a/engines/sci/graphics/text32.h
+++ b/engines/sci/graphics/text32.h
@@ -304,17 +304,6 @@ private:
*/
TextAlign _alignment;
- int16 _field_20;
-
- /**
- * TODO: Document
- */
- int16 _field_22;
-
- int _field_2C, _field_30, _field_34, _field_38;
-
- int16 _field_3C;
-
/**
* The position of the text draw cursor.
*/
@@ -392,11 +381,6 @@ public:
*/
reg_t createFontBitmap(const CelInfo32 &celInfo, const Common::Rect &rect, const Common::String &text, const int16 foreColor, const int16 backColor, const GuiResourceId fontId, const int16 skipColor, const int16 borderColor, const bool dimmed);
- /**
- * Creates a font bitmap with a title.
- */
- reg_t createTitledBitmap(const int16 width, const int16 height, const Common::Rect &textRect, const Common::String &text, const int16 foreColor, const int16 backColor, const int16 skipColor, const GuiResourceId fontId, const TextAlign alignment, const int16 borderColor, Common::String &title, const int16 titleForeColor, const int16 titleBackColor, const GuiResourceId titleFontId, const bool doScaling);
-
inline int scaleUpWidth(int value) const {
const int scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
return (value * scriptWidth + _scaledWidth - 1) / _scaledWidth;
diff --git a/engines/sci/sci.h b/engines/sci/sci.h
index 7df3d38163..c49a516d01 100644
--- a/engines/sci/sci.h
+++ b/engines/sci/sci.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef SCI_H
-#define SCI_H
+#ifndef SCI_SCI_H
+#define SCI_SCI_H
#include "engines/engine.h"
#include "common/macresman.h"
@@ -460,4 +460,4 @@ const char *getSciVersionDesc(SciVersion version);
} // End of namespace Sci
-#endif // SCI_H
+#endif // SCI_SCI_H
diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp
index 3a69b5f03c..cd54c175cc 100644
--- a/engines/scumm/actor.cpp
+++ b/engines/scumm/actor.cpp
@@ -2479,6 +2479,13 @@ void ScummEngine::setActorRedrawFlags() {
_actors[j]->_needRedraw = true;
}
} else {
+ if (_game.heversion >= 72) {
+ for (j = 1; j < _numActors; j++) {
+ if (_actors[j]->_costume && _actors[j]->_heXmapNum)
+ _actors[j]->_needRedraw = true;
+ }
+ }
+
for (i = 0; i < _gdi->_numStrips; i++) {
int strip = _screenStartStrip + i;
if (testGfxAnyUsageBits(strip)) {
diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp
index 0867b20fc3..4c9d1221aa 100644
--- a/engines/scumm/detection.cpp
+++ b/engines/scumm/detection.cpp
@@ -186,6 +186,11 @@ Common::String ScummEngine_v70he::generateFilename(const int room) const {
}
if (_filenamePattern.genMethod == kGenHEPC || _filenamePattern.genMethod == kGenHEIOS) {
+ if (id == '3' && _game.id == GID_MOONBASE) {
+ result = Common::String::format("%s.u32", _filenamePattern.pattern);
+ break;
+ }
+
// For HE >= 98, we already called snprintf above.
if (_game.heversion < 98 || room < 0)
result = Common::String::format("%s.he%c", _filenamePattern.pattern, id);
diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h
index 5a994cb699..bb3e7f6ec3 100644
--- a/engines/scumm/detection_tables.h
+++ b/engines/scumm/detection_tables.h
@@ -245,9 +245,11 @@ static const GameSettings gameVariantsTable[] = {
{"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)},
+ {"monkey", "SE Talkie", 0, GID_MONKEY, 5, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, GF_AUDIOTRACKS, UNK, GUIO0()},
{"monkey2", "", 0, GID_MONKEY2, 5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO1(GUIO_NOSPEECH)},
{"monkey2", "FM-TOWNS", 0, GID_MONKEY2, 5, 0, MDT_PCSPK | MDT_TOWNS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, Common::kPlatformFMTowns, GUIO5(GUIO_NOSPEECH, GUIO_MIDITOWNS, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_NOASPECT)},
+ {"monkey2", "SE Talkie",0, GID_MONKEY2, 5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO0()},
{"atlantis", "", 0, GID_INDY4, 5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO0()},
{"atlantis", "Steam", "steam", GID_INDY4, 5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO0()},
diff --git a/engines/scumm/he/intern_he.h b/engines/scumm/he/intern_he.h
index 370f54c1d8..7f7babc604 100644
--- a/engines/scumm/he/intern_he.h
+++ b/engines/scumm/he/intern_he.h
@@ -184,8 +184,11 @@ protected:
};
#ifdef ENABLE_HE
+class Moonbase;
+
class ScummEngine_v71he : public ScummEngine_v70he {
friend class Wiz;
+ friend class Moonbase;
protected:
bool _skipProcessActors;
@@ -423,6 +426,7 @@ protected:
class ScummEngine_v90he : public ScummEngine_v80he {
friend class LogicHE;
+ friend class Moonbase;
friend class MoviePlayer;
friend class Sprite;
@@ -433,7 +437,7 @@ protected:
byte filename[260];
int32 status;
int32 flags;
- int32 unk2;
+ int32 number;
int32 wizResNum;
};
@@ -571,16 +575,25 @@ protected:
};
class ScummEngine_v100he : public ScummEngine_v99he {
+friend class AI;
+
protected:
ResType _heResType;
int32 _heResId;
byte _debugInputBuffer[256];
+
+public:
+ Moonbase *_moonbase;
+
public:
- ScummEngine_v100he(OSystem *syst, const DetectorResult &dr) : ScummEngine_v99he(syst, dr) {}
+ ScummEngine_v100he(OSystem *syst, const DetectorResult &dr);
+ ~ScummEngine_v100he();
virtual void resetScumm();
+ virtual void setupScummVars();
+
protected:
virtual void setupOpcodes();
@@ -626,6 +639,14 @@ protected:
void o100_getSpriteInfo();
void o100_getWizData();
void o100_getVideoData();
+
+protected:
+ byte VAR_U32_USER_VAR_A;
+ byte VAR_U32_USER_VAR_B;
+ byte VAR_U32_USER_VAR_C;
+ byte VAR_U32_USER_VAR_D;
+ byte VAR_U32_USER_VAR_E;
+ byte VAR_U32_USER_VAR_F;
};
class ScummEngine_vCUPhe : public Engine {
diff --git a/engines/scumm/he/logic/moonbase_logic.cpp b/engines/scumm/he/logic/moonbase_logic.cpp
new file mode 100644
index 0000000000..1b596fc54c
--- /dev/null
+++ b/engines/scumm/he/logic/moonbase_logic.cpp
@@ -0,0 +1,255 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/he/intern_he.h"
+#include "scumm/he/logic_he.h"
+#include "scumm/he/moonbase/moonbase.h"
+#include "scumm/he/moonbase/ai_main.h"
+
+namespace Scumm {
+
+/**
+ * Logic code for:
+ * Moonbase Commander
+ */
+class LogicHEmoonbase : public LogicHE {
+public:
+ LogicHEmoonbase(ScummEngine_v100he *vm) : LogicHE(vm) { _vm1 = vm; }
+
+ int versionID();
+
+ int32 dispatch(int op, int numArgs, int32 *args);
+
+private:
+ void op_create_multi_state_wiz(int op, int numArgs, int32 *args);
+ void op_load_multi_channel_wiz(int op, int numArgs, int32 *args);
+ void op_wiz_from_multi_channel_wiz(int op, int numArgs, int32 *args);
+ void op_dos_command(int op, int numArgs, int32 *args);
+ void op_set_fow_sentinel(int32 *args);
+ void op_set_fow_information(int op, int numArgs, int32 *args);
+ int op_set_fow_image(int op, int numArgs, int32 *args);
+
+ void op_ai_test_kludge(int op, int numArgs, int32 *args);
+ int op_ai_master_control_program(int op, int numArgs, int32 *args);
+ void op_ai_reset(int op, int numArgs, int32 *args);
+ void op_ai_set_type(int op, int numArgs, int32 *args);
+ void op_ai_clean_up(int op, int numArgs, int32 *args);
+
+private:
+ ScummEngine_v100he *_vm1;
+};
+
+int LogicHEmoonbase::versionID() {
+ if (_vm->_game.features & GF_DEMO)
+ return -100;
+ else if (strcmp(_vm->_game.variant, "1.1") == 0)
+ return 110;
+ else
+ return 100;
+}
+
+#define OP_CREATE_MULTI_STATE_WIZ 100
+#define OP_LOAD_MULTI_CHANNEL_WIZ 101
+#define OP_WIZ_FROM_MULTI_CHANNEL_WIZ 102
+#define OP_DOS_COMMAND 103
+#define OP_SET_FOW_SENTINEL 104
+#define OP_SET_FOW_INFORMATION 105
+#define OP_SET_FOW_IMAGE 106
+
+#define OP_AI_TEST_KLUDGE 10000
+#define OP_AI_MASTER_CONTROL_PROGRAM 10001
+#define OP_AI_RESET 10002
+#define OP_AI_SET_TYPE 10003
+#define OP_AI_CLEAN_UP 10004
+
+#define OP_NET_REMOTE_START_SCRIPT 1492
+#define OP_NET_DO_INIT_ALL 1493
+#define OP_NET_DO_INIT_PROVIDER 1494
+#define OP_NET_DO_INIT_SESSION 1495
+#define OP_NET_DO_INIT_USER 1496
+#define OP_NET_QUERY_PROVIDERS 1497
+#define OP_NET_GET_PROVIDER_NAME 1498
+#define OP_NET_SET_PROVIDER 1499
+#define OP_NET_CLOSE_PROVIDER 1500
+#define OP_NET_QUERY_SESSIONS 1501
+#define OP_NET_GET_SESSION_NAME 1502
+#define OP_NET_CREATE_SESSION 1503
+#define OP_NET_JOIN_SESSION 1504
+#define OP_NET_END_SESSION 1505
+#define OP_NET_ADD_USER 1506
+#define OP_NET_REMOVE_USER 1507
+#define OP_NET_WHO_SENT_THIS 1508
+#define OP_NET_REMOTE_SEND_ARRAY 1509
+#define OP_NET_WHO_AM_I 1510
+#define OP_NET_REMOTE_START_FUNCTION 1511
+#define OP_NET_GET_PLAYER_LONG_NAME 1512
+#define OP_NET_GET_PLAYER_SHORT_NAME 1513
+#define OP_NET_SET_PROVIDER_BY_NAME 1516
+#define OP_NET_HOST_TCPIP_GAME 1517
+#define OP_NET_JOIN_TCPIP_GAME 1518
+#define OP_NET_SET_FAKE_LAG 1555
+#define OP_NET_GET_HOST_NAME 1556
+#define OP_NET_GET_IP_FROM_NAME 1557
+#define OP_NET_GET_SESSION_PLAYER_COUNT 1558
+#define OP_NET_DISABLE_SESSION_PLAYER_JOIN 1559
+#define OP_NET_START_QUERY_SESSIONS 1560
+#define OP_NET_UPDATE_QUERY_SESSIONS 1561
+#define OP_NET_STOP_QUERY_SESSIONS 1562
+#define OP_NET_DESTROY_PLAYER 1563
+#define OP_NET_ENABLE_SESSION_PLAYER_JOIN 1564
+#define OP_NET_SET_AI_PLAYER_COUNT 1565
+
+
+int32 LogicHEmoonbase::dispatch(int op, int numArgs, int32 *args) {
+ switch (op) {
+ case OP_CREATE_MULTI_STATE_WIZ:
+ op_create_multi_state_wiz(op, numArgs, args);
+ break;
+ case OP_LOAD_MULTI_CHANNEL_WIZ:
+ op_load_multi_channel_wiz(op, numArgs, args);
+ break;
+ case OP_WIZ_FROM_MULTI_CHANNEL_WIZ:
+ op_wiz_from_multi_channel_wiz(op, numArgs, args);
+ break;
+ case OP_DOS_COMMAND:
+ op_dos_command(op, numArgs, args);
+ break;
+ case OP_SET_FOW_SENTINEL:
+ op_set_fow_sentinel(args);
+ break;
+ case OP_SET_FOW_INFORMATION:
+ op_set_fow_information(op, numArgs, args);
+ break;
+ case OP_SET_FOW_IMAGE:
+ return op_set_fow_image(op, numArgs, args);
+
+ case OP_AI_TEST_KLUDGE:
+ op_ai_test_kludge(op, numArgs, args);
+ break;
+ case OP_AI_MASTER_CONTROL_PROGRAM:
+ return op_ai_master_control_program(op, numArgs, args);
+ case OP_AI_RESET:
+ op_ai_reset(op, numArgs, args);
+ break;
+ case OP_AI_SET_TYPE:
+ op_ai_set_type(op, numArgs, args);
+ break;
+ case OP_AI_CLEAN_UP:
+ op_ai_clean_up(op, numArgs, args);
+ break;
+
+ default:
+ LogicHE::dispatch(op, numArgs, args);
+ }
+
+ return 0;
+}
+
+void LogicHEmoonbase::op_create_multi_state_wiz(int op, int numArgs, int32 *args) {
+ warning("STUB: op_create_multi_state_wiz()");
+ LogicHE::dispatch(op, numArgs, args);
+}
+
+void LogicHEmoonbase::op_load_multi_channel_wiz(int op, int numArgs, int32 *args) {
+ warning("STUB: op_load_multi_channel_wiz()");
+ LogicHE::dispatch(op, numArgs, args);
+}
+
+void LogicHEmoonbase::op_wiz_from_multi_channel_wiz(int op, int numArgs, int32 *args) {
+ warning("STUB: op_wiz_from_multi_channel_wiz()");
+ LogicHE::dispatch(op, numArgs, args);
+}
+
+void LogicHEmoonbase::op_dos_command(int op, int numArgs, int32 *args) {
+ warning("STUB: op_dos_command()");
+ LogicHE::dispatch(op, numArgs, args);
+}
+
+void LogicHEmoonbase::op_set_fow_sentinel(int32 *args) {
+ debug(2, "op_set_fow_sentinel(%d, %d, %d)", args[0], args[1], args[2]);
+
+ _vm1->_moonbase->_fowSentinelImage = args[0];
+ _vm1->_moonbase->_fowSentinelState = args[1];
+ _vm1->_moonbase->_fowSentinelConditionBits = args[2];
+}
+
+void LogicHEmoonbase::op_set_fow_information(int op, int numArgs, int32 *args) {
+ Common::String str;
+
+ str = Common::String::format("op_set_fow_information(%d", args[0]);
+ for (int i = 1; i < numArgs; i++) {
+ str += Common::String::format(", %d", args[i]);
+ }
+ str += ")";
+
+ debug(2, "%s", str.c_str());
+
+ _vm1->_moonbase->setFOWInfo(
+ args[0], // array
+ args[1], // array down dimension
+ args[2], // array across dimension
+ args[3], // logical view X coordinate
+ args[4], // logical view Y coordinate
+ args[5], // screen draw clip rect x1
+ args[6], // screen draw clip rect y1
+ args[7], // screen draw clip rect x2
+ args[8], // screen draw clip rect y2
+ args[9], // techinque
+ args[10] // frame
+ );
+}
+
+int LogicHEmoonbase::op_set_fow_image(int op, int numArgs, int32 *args) {
+ debug(2, "op_set_fow_image(%d)", args[0]);
+ return _vm1->_moonbase->setFOWImage(args[0]) ? 1 : 0;
+}
+
+void LogicHEmoonbase::op_ai_test_kludge(int op, int numArgs, int32 *args) {
+ warning("STUB: op_ai_test_kludge()");
+ LogicHE::dispatch(op, numArgs, args);
+}
+
+int LogicHEmoonbase::op_ai_master_control_program(int op, int numArgs, int32 *args) {
+ warning("op_ai_master_control_program()");
+ return _vm1->_moonbase->_ai->masterControlProgram(numArgs, args);
+}
+
+void LogicHEmoonbase::op_ai_reset(int op, int numArgs, int32 *args) {
+ warning("op_ai_reset())");
+ _vm1->_moonbase->_ai->resetAI();
+}
+
+void LogicHEmoonbase::op_ai_set_type(int op, int numArgs, int32 *args) {
+ warning("op_ai_set_type()");
+ _vm1->_moonbase->_ai->setAIType(numArgs, args);
+}
+
+void LogicHEmoonbase::op_ai_clean_up(int op, int numArgs, int32 *args) {
+ warning("op_ai_clean_up()");
+ _vm1->_moonbase->_ai->cleanUpAI();
+}
+
+LogicHE *makeLogicHEmoonbase(ScummEngine_v100he *vm) {
+ return new LogicHEmoonbase(vm);
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/logic_he.cpp b/engines/scumm/he/logic_he.cpp
index 366cd3be26..33f5c40464 100644
--- a/engines/scumm/he/logic_he.cpp
+++ b/engines/scumm/he/logic_he.cpp
@@ -102,7 +102,7 @@ LogicHE *LogicHE::makeLogicHE(ScummEngine_v90he *vm) {
return makeLogicHEbasketball(vm);
case GID_MOONBASE:
- return makeLogicHEmoonbase(vm);
+ return makeLogicHEmoonbase((ScummEngine_v100he *)vm);
default:
return new LogicHE(vm);
diff --git a/engines/scumm/he/logic_he.h b/engines/scumm/he/logic_he.h
index cd547f1616..5002ee9434 100644
--- a/engines/scumm/he/logic_he.h
+++ b/engines/scumm/he/logic_he.h
@@ -65,7 +65,7 @@ LogicHE *makeLogicHEfootball2002(ScummEngine_v90he *vm);
LogicHE *makeLogicHEsoccer(ScummEngine_v90he *vm);
LogicHE *makeLogicHEbaseball2001(ScummEngine_v90he *vm);
LogicHE *makeLogicHEbasketball(ScummEngine_v90he *vm);
-LogicHE *makeLogicHEmoonbase(ScummEngine_v90he *vm);
+LogicHE *makeLogicHEmoonbase(ScummEngine_v100he *vm);
} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_defenseunit.cpp b/engines/scumm/he/moonbase/ai_defenseunit.cpp
new file mode 100644
index 0000000000..ab61297603
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_defenseunit.cpp
@@ -0,0 +1,767 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/rect.h"
+#include "common/util.h"
+#include "scumm/he/intern_he.h"
+#include "scumm/he/moonbase/moonbase.h"
+#include "scumm/he/moonbase/ai_defenseunit.h"
+#include "scumm/he/moonbase/ai_main.h"
+
+namespace Scumm {
+
+DefenseUnit::DefenseUnit(AI *ai) : _ai(ai) {
+ _state = DUS_ON;
+
+ _id = -1;
+ _distanceTo = 0;
+ _state = 0;
+ _radius = 0;
+ _armor = 0;
+ _cost = 0;
+}
+
+DefenseUnit::DefenseUnit(DefenseUnit *inUnit, AI *ai) : _ai(ai) {
+ _id = inUnit->getID();
+ _pos.x = inUnit->getPosX();
+ _pos.y = inUnit->getPosY();
+ _distanceTo = inUnit->getDistanceTo();
+ _state = inUnit->getState();
+ _radius = inUnit->getRadius();
+ _armor = inUnit->getArmor();
+ _cost = inUnit->getCost();
+}
+
+DefenseUnit::~DefenseUnit() {
+}
+
+Common::Point *AntiAirUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+ float ratio;
+ int radius;
+ Common::Point *targetPos = new Common::Point;
+
+ if (!distance) distance = 1;
+
+ switch (weaponType) {
+ case ITEM_BOMB:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CLUSTER:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CRAWLER:
+ radius = getRadius();
+
+ if ((distance < radius) || (getState() == DUS_OFF)) {
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ } else {
+ ratio = MAX(0, (getRadius() / distance));
+ targetPos->x = (int16)(getPosX() - ratio * (getPosX() - sourceX));
+ targetPos->y = (int16)(getPosY() - ratio * (getPosY() - sourceY));
+ }
+
+ break;
+
+ case ITEM_EMP:
+ if (getRadius() + 215 > distance) { // Emp radius
+ double x1 = static_cast<double>(sourceX);
+ double y1 = static_cast<double>(sourceY);
+ double x2 = static_cast<double>(getPosX());
+ double y2 = static_cast<double>(getPosY());
+ double r1 = static_cast<double>(215);
+ double r2 = static_cast<double>(getRadius() + 3);
+ double d = static_cast<double>(distance);
+
+ // Formulae for calculating one point of intersection of two circles
+ float root = sqrt((((r1 + r2) * (r1 + r2)) - (d * d)) * ((d * d) - ((r2 - r1) * (r2 - r1))));
+ int x = (int)(((x1 + x2) / 2) + ((x2 - x1) * (r1 * r1 - r2 * r2)) / (2 * d * d) + ((y2 - y1) / (2 * d * d)) * root);
+ int y = (int)(((y1 + y2) / 2) + ((y2 - y1) * (r1 * r1 - r2 * r2)) / (2 * d * d) - ((x2 - x1) / (2 * d * d)) * root);
+
+ targetPos->x = x;
+ targetPos->y = y;
+ } else {
+ ratio = 1 - (getRadius() / static_cast<float>(distance - 20));
+ targetPos->x = (int16)(sourceX + ratio * (getPosX() - sourceX));
+ targetPos->y = (int16)(sourceY + ratio * (getPosY() - sourceY));
+ }
+
+ break;
+
+ default:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+ }
+
+ return targetPos;
+}
+
+int AntiAirUnit::selectWeapon(int index) {
+ switch (index) {
+ case 0:
+ return ITEM_CLUSTER;
+ break;
+
+ case 1:
+ return ITEM_EMP;
+ break;
+
+ case 2:
+ if (getState() == DUS_OFF) {
+ if (_ai->getPlayerEnergy() > 6) {
+ if (!_ai->_vm->_rnd.getRandomNumber(3)) {
+ return ITEM_VIRUS;
+ }
+ }
+
+ if (_ai->getPlayerEnergy() > 2) {
+ if (!_ai->_vm->_rnd.getRandomNumber(1)) {
+ return ITEM_SPIKE;
+ }
+ }
+
+ return ITEM_BOMB;
+ }
+
+ return ITEM_CLUSTER;
+ break;
+
+ default:
+ return ITEM_CLUSTER;
+ break;
+ }
+}
+
+Common::Point *ShieldUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+ float ratio;
+ Common::Point *targetPos = new Common::Point;
+
+ if (getState() == DUS_OFF) {
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ } else {
+ switch (weaponType) {
+ case ITEM_BOMB:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CLUSTER:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CRAWLER:
+ ratio = MAX(0.0, 1.0 - (static_cast<float>(getRadius()) / static_cast<float>(distance - 20)));
+ {
+ int maxX = _ai->getMaxX();
+ int maxY = _ai->getMaxY();
+ int thisX = (static_cast<int>(sourceX + ratio * (getPosX() - sourceX)) + maxX) % maxX;
+ int thisY = (static_cast<int>(sourceY + ratio * (getPosY() - sourceY)) + maxY) % maxY;
+ targetPos->x = thisX;
+ targetPos->y = thisY;
+ }
+ break;
+
+ case ITEM_EMP:
+ if (getRadius() + 215 > distance) { // Emp radius
+ double x1 = static_cast<double>(sourceX);
+ double y1 = static_cast<double>(sourceY);
+ double x2 = static_cast<double>(getPosX());
+ double y2 = static_cast<double>(getPosY());
+ double r1 = static_cast<double>(215);
+ double r2 = static_cast<double>(getRadius() + 10);
+ double d = static_cast<double>(distance);
+
+ // Formulae for calculating one point of intersection of two circles
+ float root = sqrt((((r1 + r2) * (r1 + r2)) - (d * d)) * ((d * d) - ((r2 - r1) * (r2 - r1))));
+ int x = (int)(((x1 + x2) / 2) + ((x2 - x1) * (r1 * r1 - r2 * r2)) / (2 * d * d) + ((y2 - y1) / (2 * d * d)) * root);
+ int y = (int)(((y1 + y2) / 2) + ((y2 - y1) * (r1 * r1 - r2 * r2)) / (2 * d * d) - ((x2 - x1) / (2 * d * d)) * root);
+
+ targetPos->x = x;
+ targetPos->y = y;
+ } else {
+ ratio = 1 - (getRadius() / static_cast<float>(distance - 20));
+ targetPos->x = (int16)(sourceX + ratio * (getPosX() - sourceX));
+ targetPos->y = (int16)(sourceY + ratio * (getPosY() - sourceY));
+ }
+
+ if (distance < getRadius()) {
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ }
+
+ break;
+
+ default:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+ }
+ }
+
+ return targetPos;
+}
+
+int ShieldUnit::selectWeapon(int index) {
+ warning("Shield weapon select");
+
+ int myUnit = _ai->getClosestUnit(getPosX(), getPosY(), _ai->getMaxX(), _ai->getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 0);
+ int dist = _ai->getDistance(getPosX(), getPosY(), _ai->getHubX(myUnit), _ai->getHubY(myUnit));
+
+ if ((dist < (getRadius() - 20)) && (dist > 90)) {
+ return ITEM_SPIKE;
+ }
+
+ switch (index) {
+ case 0:
+ if (getState() == DUS_OFF) {
+ if (_ai->getPlayerEnergy() < 3) {
+ return ITEM_BOMB;
+ } else {
+ return ITEM_SPIKE;
+ }
+ }
+
+ return ITEM_EMP;
+ break;
+
+ case 1:
+ if (dist < getRadius() + 150) {
+ return ITEM_EMP;
+ } else {
+ return ITEM_CRAWLER;
+ }
+
+ break;
+
+ default:
+ return ITEM_EMP;
+ break;
+ }
+}
+
+Common::Point *MineUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+ float ratio;
+ Common::Point *targetPos = new Common::Point;
+
+ switch (weaponType) {
+ case ITEM_BOMB:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CLUSTER:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_EMP:
+ ratio = 1 - (getRadius() / static_cast<float>(distance - 20));
+ targetPos->x = (int16)(sourceX + ratio * (getPosX() - sourceX));
+ targetPos->y = (int16)(sourceY + ratio * (getPosY() - sourceY));
+ break;
+
+ default:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+ }
+
+ return targetPos;
+}
+
+int MineUnit::selectWeapon(int index) {
+ int myUnit = _ai->getClosestUnit(getPosX(), getPosY(), _ai->getMaxX(), _ai->getCurrentPlayer(), 1, 0, 0, 0);
+ int x = getPosX();
+ int y = getPosY();
+
+ int dist = _ai->getDistance(x, y, _ai->getHubX(myUnit), _ai->getHubY(myUnit));
+
+ if ((getState() == DUS_ON) && (dist < 110)) {
+ return ITEM_EMP;
+ } else {
+ return ITEM_BOMB;
+ }
+}
+
+
+Common::Point *HubUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+ Common::Point *targetPos = new Common::Point;
+
+ if (!distance) distance = 1;
+
+ switch (weaponType) {
+ case ITEM_BOMB:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CLUSTER:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CRAWLER:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ default:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+ }
+
+ return targetPos;
+}
+
+int HubUnit::selectWeapon(int index) {
+ warning("Hub weapon select");
+
+ int energy = _ai->getPlayerEnergy();
+
+ if (energy > 6) {
+ //possibly choose crawler
+ if (_ai->getBuildingWorth(getID()) > 21) {
+ return ITEM_CRAWLER;
+ }
+ }
+
+ //choose betw/ bomb and cluster
+ if (_ai->getBuildingArmor(getID()) < 1.5) {
+ return ITEM_CLUSTER;
+ }
+
+ if (energy > 2) {
+ if (!_ai->_vm->_rnd.getRandomNumber(3)) {
+ return ITEM_SPIKE;
+ }
+
+ if (!_ai->_vm->_rnd.getRandomNumber(4)) {
+ return ITEM_GUIDED;
+ }
+
+ if (!_ai->_vm->_rnd.getRandomNumber(4)) {
+ return ITEM_MINE;
+ }
+
+ if (!_ai->_vm->_rnd.getRandomNumber(9)) {
+ return ITEM_EMP;
+ }
+ }
+
+ return ITEM_BOMB;
+}
+
+
+Common::Point *TowerUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+ Common::Point *targetPos = new Common::Point;
+
+ if (!distance) distance = 1;
+
+ switch (weaponType) {
+ case ITEM_BOMB:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_SPIKE:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ default:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+ }
+
+ return targetPos;
+}
+
+int TowerUnit::selectWeapon(int index) {
+ switch (index) {
+ case 0:
+ return ITEM_SPIKE;
+ break;
+
+ default:
+ return ITEM_SPIKE;
+ break;
+ }
+}
+
+
+Common::Point *BridgeUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+ Common::Point *targetPos = new Common::Point;
+
+ if (!distance) distance = 1;
+
+ switch (weaponType) {
+ case ITEM_BOMB:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CLUSTER:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ default:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+ }
+
+ return targetPos;
+}
+
+int BridgeUnit::selectWeapon(int index) {
+ switch (index) {
+ case 0:
+ return ITEM_BOMB;
+ break;
+
+ case 1:
+ return ITEM_CLUSTER;
+ break;
+
+ default:
+ return ITEM_BOMB;
+ break;
+ }
+}
+
+Common::Point *EnergyUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+ Common::Point *targetPos = new Common::Point;
+
+ if (!distance) distance = 1;
+
+ switch (weaponType) {
+ case ITEM_BOMB:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CLUSTER:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CRAWLER:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ default:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+ }
+
+ return targetPos;
+}
+
+int EnergyUnit::selectWeapon(int index) {
+ warning("Energy weapon select");
+
+ int energy = _ai->getPlayerEnergy();
+
+ if (energy > 6) {
+ //possibly choose crawler
+ if (_ai->getBuildingWorth(getID()) > 21) {
+ return ITEM_CRAWLER;
+ }
+ }
+
+ //choose betw/ bomb and cluster
+ if (_ai->getBuildingArmor(getID()) < 1.5) {
+ return ITEM_CLUSTER;
+ }
+
+ if (energy > 2) {
+ if (!_ai->_vm->_rnd.getRandomNumber(3)) {
+ return ITEM_EMP;
+ }
+ }
+
+ return ITEM_BOMB;
+}
+
+Common::Point *OffenseUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+ Common::Point *targetPos = new Common::Point;
+
+ if (!distance) distance = 1;
+
+ switch (weaponType) {
+ case ITEM_BOMB:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CLUSTER:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CRAWLER:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ default:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+ }
+
+ return targetPos;
+}
+
+int OffenseUnit::selectWeapon(int index) {
+ warning("Offense weapon select");
+
+ int energy = _ai->getPlayerEnergy();
+
+ if (energy > 6) {
+ //possibly choose crawler
+ if (_ai->getBuildingWorth(getID()) > 21) {
+ return ITEM_CRAWLER;
+ }
+ }
+
+ //choose betw/ bomb and cluster
+ if (_ai->getBuildingArmor(getID()) < 1.5) {
+ return ITEM_CLUSTER;
+ }
+
+ return ITEM_BOMB;
+}
+
+Common::Point *CrawlerUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+ Common::Point *targetPos = new Common::Point;
+
+ if (!distance)
+ distance = 1;
+
+ switch (weaponType) {
+ case ITEM_BOMB:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CLUSTER:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CRAWLER:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ default:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+ }
+
+ return targetPos;
+}
+
+int CrawlerUnit::selectWeapon(int index) {
+ warning("Crawler weapon select");
+ int myUnit = _ai->getClosestUnit(getPosX(), getPosY(), _ai->getMaxX(), _ai->getCurrentPlayer(), 1, 0, 0, 0);
+ int dist = _ai->getDistance(_ai->getHubX(myUnit), _ai->getHubY(myUnit), getPosX(), getPosY());
+
+ int x = getPosX();
+ int y = getPosY();
+ int energy = _ai->getPlayerEnergy();
+ int terrain = _ai->getTerrain(x, y);
+
+ if (terrain != TERRAIN_TYPE_WATER) {
+ if ((energy > 2) && (dist < 220)) {
+ return ITEM_RECLAIMER;
+ } else {
+ return ITEM_BOMB;
+ }
+ } else {
+ if (energy > 6) {
+ return ITEM_CRAWLER;
+ }
+
+ if (energy > 2) {
+ if (_ai->_vm->_rnd.getRandomNumber(1)) {
+ return ITEM_MINE;
+ } else {
+ return ITEM_TIME_EXPIRED;
+ }
+ }
+ }
+
+ return SKIP_TURN;
+}
+
+AntiAirUnit::AntiAirUnit(AI *ai) : DefenseUnit(ai) {
+ setRadius(190);
+ setArmor(3);
+ setCost(1);
+}
+
+ShieldUnit::ShieldUnit(AI *ai) : DefenseUnit(ai) {
+ setRadius(170);
+ setArmor(3);
+ setCost(7);
+}
+
+MineUnit::MineUnit(AI *ai) : DefenseUnit(ai) {
+ setRadius(80);
+ setArmor(1);
+ setCost(3);
+}
+
+HubUnit::HubUnit(AI *ai) : DefenseUnit(ai) {
+ setRadius(1);
+ setArmor(5);
+ setCost(7);
+}
+
+TowerUnit::TowerUnit(AI *ai) : DefenseUnit(ai) {
+ setRadius(1);
+ setArmor(3);
+ setCost(1);
+}
+
+BridgeUnit::BridgeUnit(AI *ai) : DefenseUnit(ai) {
+ setRadius(1);
+ setArmor(3);
+ setCost(1);
+}
+
+EnergyUnit::EnergyUnit(AI *ai) : DefenseUnit(ai) {
+ setRadius(1);
+ setArmor(5);
+ setCost(7);
+}
+
+OffenseUnit::OffenseUnit(AI *ai) : DefenseUnit(ai) {
+ setRadius(1);
+ setArmor(3);
+ setCost(7);
+}
+
+CrawlerUnit::CrawlerUnit(AI *ai) : DefenseUnit(ai) {
+ setRadius(1);
+ setArmor(3);
+ setCost(7);
+}
+
+AntiAirUnit::AntiAirUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
+ setID(inUnit->getID());
+ setPos(inUnit->getPosX(), inUnit->getPosY());
+ setDistanceTo(inUnit->getDistanceTo());
+ setState(inUnit->getState());
+ setRadius(inUnit->getRadius());
+ setArmor(inUnit->getArmor());
+
+}
+
+ShieldUnit::ShieldUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
+ setID(inUnit->getID());
+ setPos(inUnit->getPosX(), inUnit->getPosY());
+ setDistanceTo(inUnit->getDistanceTo());
+ setState(inUnit->getState());
+ setRadius(inUnit->getRadius());
+ setArmor(inUnit->getArmor());
+}
+
+MineUnit::MineUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
+ setID(inUnit->getID());
+ setPos(inUnit->getPosX(), inUnit->getPosY());
+ setDistanceTo(inUnit->getDistanceTo());
+ setState(inUnit->getState());
+ setRadius(inUnit->getRadius());
+ setArmor(inUnit->getArmor());
+}
+
+HubUnit::HubUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
+ setID(inUnit->getID());
+ setPos(inUnit->getPosX(), inUnit->getPosY());
+ setDistanceTo(inUnit->getDistanceTo());
+ setState(inUnit->getState());
+ setRadius(inUnit->getRadius());
+ setArmor(inUnit->getArmor());
+}
+
+TowerUnit::TowerUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
+ setID(inUnit->getID());
+ setPos(inUnit->getPosX(), inUnit->getPosY());
+ setDistanceTo(inUnit->getDistanceTo());
+ setState(inUnit->getState());
+ setRadius(inUnit->getRadius());
+ setArmor(inUnit->getArmor());
+}
+
+BridgeUnit::BridgeUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
+ setID(inUnit->getID());
+ setPos(inUnit->getPosX(), inUnit->getPosY());
+ setDistanceTo(inUnit->getDistanceTo());
+ setState(inUnit->getState());
+ setRadius(inUnit->getRadius());
+ setArmor(inUnit->getArmor());
+}
+
+EnergyUnit::EnergyUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
+ setID(inUnit->getID());
+ setPos(inUnit->getPosX(), inUnit->getPosY());
+ setDistanceTo(inUnit->getDistanceTo());
+ setState(inUnit->getState());
+ setRadius(inUnit->getRadius());
+ setArmor(inUnit->getArmor());
+}
+
+OffenseUnit::OffenseUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
+ setID(inUnit->getID());
+ setPos(inUnit->getPosX(), inUnit->getPosY());
+ setDistanceTo(inUnit->getDistanceTo());
+ setState(inUnit->getState());
+ setRadius(inUnit->getRadius());
+ setArmor(inUnit->getArmor());
+}
+
+CrawlerUnit::CrawlerUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
+ setID(inUnit->getID());
+ setPos(inUnit->getPosX(), inUnit->getPosY());
+ setDistanceTo(inUnit->getDistanceTo());
+ setState(inUnit->getState());
+ setRadius(inUnit->getRadius());
+ setArmor(inUnit->getArmor());
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_defenseunit.h b/engines/scumm/he/moonbase/ai_defenseunit.h
new file mode 100644
index 0000000000..a6085da859
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_defenseunit.h
@@ -0,0 +1,195 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_HE_MOONBASE_AI_DEFENCEUNIT_H
+#define SCUMM_HE_MOONBASE_AI_DEFENCEUNIT_H
+
+namespace Scumm {
+
+class AI;
+
+enum {
+ DUT_ANTI_AIR = 1,
+ DUT_SHIELD = 2,
+ DUT_MINE = 3,
+ DUT_HUB = 4,
+ DUT_TOWER = 5,
+ DUT_BRIDGE = 6,
+ DUT_ENERGY = 7,
+ DUT_OFFENSE = 8,
+ DUT_CRAWLER = 9
+};
+
+enum {
+ DUS_ON = 1,
+ DUS_OFF = 2,
+ DUS_DESTROYED = 3
+};
+
+class DefenseUnit {
+private:
+ int _id;
+ Common::Point _pos;
+ int _distanceTo;
+ int _state;
+ int _radius;
+ int _armor;
+ int _cost;
+
+protected:
+ AI *_ai;
+
+public:
+ DefenseUnit(AI *ai);
+ DefenseUnit(DefenseUnit *inUnit, AI *ai);
+
+ virtual ~DefenseUnit();
+
+ void setID(int id) { _id = id; }
+ void setDistanceTo(int distanceTo) { _distanceTo = distanceTo; }
+ void setState(int state) { _state = state; }
+ void setRadius(int radius) { _radius = radius; }
+ void setArmor(int armor) { _armor = armor; }
+ void setDamage(int damage) { _armor -= damage; }
+ void setPos(int x, int y) {
+ _pos.x = x;
+ _pos.y = y;
+ }
+ void setCost(int cost) { _cost = cost; }
+
+ int getID() const { return _id; }
+ int getDistanceTo() const { return _distanceTo; }
+ int getState() const { return _state; }
+ int getRadius() const { return _radius; }
+ int getArmor() const { return _armor; }
+ int getPosX() const { return _pos.x; }
+ int getPosY() const { return _pos.y; }
+ int getCost() const { return _cost; }
+
+ virtual int getType() const = 0;
+
+ virtual Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) = 0;
+ virtual int selectWeapon(int index) = 0;
+};
+
+class AntiAirUnit : public DefenseUnit {
+private:
+
+public:
+ AntiAirUnit(AI *ai);
+ AntiAirUnit(DefenseUnit *inUnit, AI *ai);
+ int getType() const { return DUT_ANTI_AIR; }
+ Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+ int selectWeapon(int index);
+};
+
+class ShieldUnit : public DefenseUnit {
+private:
+
+public:
+ ShieldUnit(AI *ai);
+ ShieldUnit(DefenseUnit *inUnit, AI *ai);
+ int getType() const { return DUT_SHIELD; }
+ Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+ int selectWeapon(int index);
+};
+
+class MineUnit : public DefenseUnit {
+private:
+
+public:
+ MineUnit(AI *ai);
+ MineUnit(DefenseUnit *inUnit, AI *ai);
+ int getType() const { return DUT_MINE; }
+ Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+ int selectWeapon(int index);
+};
+
+class HubUnit : public DefenseUnit {
+private:
+
+public:
+ HubUnit(AI *ai);
+ HubUnit(DefenseUnit *inUnit, AI *ai);
+ int getType() const { return DUT_HUB; }
+ Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+ int selectWeapon(int index);
+};
+
+class TowerUnit : public DefenseUnit {
+private:
+
+public:
+ TowerUnit(AI *ai);
+ TowerUnit(DefenseUnit *inUnit, AI *ai);
+ int getType() const { return DUT_TOWER; }
+ Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+ int selectWeapon(int index);
+};
+
+class BridgeUnit : public DefenseUnit {
+private:
+
+public:
+ BridgeUnit(AI *ai);
+ BridgeUnit(DefenseUnit *inUnit, AI *ai);
+ int getType() const { return DUT_BRIDGE; }
+ Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+ int selectWeapon(int index);
+};
+
+class EnergyUnit : public DefenseUnit {
+private:
+
+public:
+ EnergyUnit(AI *ai);
+ EnergyUnit(DefenseUnit *inUnit, AI *ai);
+ int getType() const { return DUT_ENERGY; }
+ Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+ int selectWeapon(int index);
+};
+
+class OffenseUnit : public DefenseUnit {
+private:
+
+public:
+ OffenseUnit(AI *ai);
+ OffenseUnit(DefenseUnit *inUnit, AI *ai);
+ int getType() const { return DUT_OFFENSE; }
+ Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+ int selectWeapon(int index);
+};
+
+class CrawlerUnit : public DefenseUnit {
+private:
+
+public:
+ CrawlerUnit(AI *ai);
+ CrawlerUnit(DefenseUnit *inUnit, AI *ai);
+ int getType() const { return DUT_CRAWLER; }
+ Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+ int selectWeapon(int index);
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/he/moonbase/ai_main.cpp b/engines/scumm/he/moonbase/ai_main.cpp
new file mode 100644
index 0000000000..9c9ff8bb01
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_main.cpp
@@ -0,0 +1,3067 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/he/intern_he.h"
+
+#include "scumm/he/moonbase/moonbase.h"
+#include "scumm/he/moonbase/ai_main.h"
+#include "scumm/he/moonbase/ai_traveller.h"
+#include "scumm/he/moonbase/ai_targetacquisition.h"
+#include "scumm/he/moonbase/ai_types.h"
+#include "scumm/he/moonbase/ai_pattern.h"
+
+namespace Scumm {
+
+enum {
+ F_GET_SCUMM_DATA = 0,
+ F_GET_WORLD_DIST = 1,
+ F_GET_WORLD_ANGLE = 2,
+ F_GET_TERRAIN_TYPE = 3,
+ F_GET_CLOSEST_UNIT = 4,
+ F_SIMULATE_BUILDING_LAUNCH = 5,
+ F_GET_POWER_ANGLE_FROM_POINT = 6,
+ F_CHECK_IF_WATER_STATE = 7,
+ F_GET_UNITS_WITHIN_RADIUS = 8,
+ F_GET_LANDING_POINT = 9,
+ F_GET_ENEMY_UNITS_VISIBLE = 10,
+ F_CHECK_IF_WATER_SQUARE = 11,
+ F_GET_GROUND_ALTITUDE = 12,
+ F_CHECK_FOR_CORD_OVERLAP = 13,
+ F_CHECK_FOR_ANGLE_OVERLAP = 14,
+ F_ESTIMATE_NEXT_ROUND_ENERGY = 15,
+ F_CHECK_FOR_UNIT_OVERLAP = 16,
+ F_GET_COORDINATE_VISIBILITY = 17,
+ F_CHECK_FOR_ENERGY_SQUARE = 18,
+ F_AI_CHAT = 19
+};
+
+enum {
+ D_GET_HUB_X = 1,
+ D_GET_HUB_Y = 2,
+ D_GET_WORLD_X_SIZE = 3,
+ D_GET_WORLD_Y_SIZE = 4,
+ D_GET_CURRENT_PLAYER = 5,
+ D_GET_MAX_POWER = 6,
+ D_GET_MIN_POWER = 7,
+ D_GET_TERRAIN_SQUARE_SIZE = 8,
+ D_GET_BUILDING_OWNER = 9,
+ D_GET_BUILDING_STATE = 10,
+ D_GET_BUILDING_TYPE = 11,
+ D_DEBUG_BREAK = 12,
+ D_GET_ENERGY_POOLS_ARRAY = 13,
+ D_GET_COORDINATE_VISIBILITY = 14,
+ D_GET_UNIT_VISIBILITY = 15,
+ D_GET_ENERGY_POOL_VISIBILITY = 16,
+ D_GET_NUMBER_OF_POOLS = 17,
+ D_GET_NUMBER_OF_PLAYERS = 18,
+ D_GET_BUILDING_ARMOR = 19,
+ D_GET_BUILDING_WORTH = 20,
+ D_GET_PLAYER_ENERGY = 21,
+ D_GET_PLAYER_MAX_TIME = 22,
+ D_GET_WIND_X_SPEED = 23,
+ D_GET_WIND_Y_SPEED = 24,
+ D_GET_TOTAL_WIND_SPEED = 25,
+ D_GET_WIND_X_SPEED_MAX = 26,
+ D_GET_WIND_Y_SPEED_MAX = 27,
+ D_GET_BIG_X_SIZE = 28,
+ D_GET_BIG_Y_SIZE = 29,
+ D_GET_ENERGY_POOL_WIDTH = 30,
+ D_GET_BUILDING_MAX_ARMOR = 31,
+ D_GET_TIMER_VALUE = 32,
+ D_GET_LAST_ATTACKED_X = 33,
+ D_GET_LAST_ATTACKED_Y = 34,
+ D_PRINT_DEBUG_TIMER = 35,
+ D_GET_PLAYER_TEAM = 36,
+ D_GET_BUILDING_TEAM = 37,
+ D_GET_FOW = 38,
+ D_GET_ANIM_SPEED = 39,
+ D_GET_BUILDING_STACK_PTR = 40,
+ D_GET_TURN_COUNTER = 41
+};
+
+enum {
+ AI_TYPE_PLAYER_NUM = 0,
+ AI_TYPE_TYPE = 1
+};
+
+enum {
+ ENERGY_MODE = 0,
+ OFFENSE_MODE = 1,
+ DEFENSE_MODE = 2
+};
+
+enum {
+ LAUNCH_SOURCE_HUB = 0,
+ LAUNCH_UNIT = 1,
+ LAUNCH_ANGLE = 2,
+ LAUNCH_POWER = 3,
+
+ MAX_LAUNCH_POWER = 560,
+ MAX_FIRING_DISTANCE = 560
+};
+
+enum {
+ SCALE_X = 50,
+ SCALE_Y = 50,
+ SCALE_Z = 50,
+
+ GRAVITY_CONSTANT = (MAX_LAUNCH_POWER *MAX_LAUNCH_POWER) / MAX_FIRING_DISTANCE,
+
+ HEIGHT_LOW = 20,
+
+ NODE_RADIUS = 7,
+ NODE_DIAMETER = NODE_RADIUS * 2 + 2,
+ NODE_DETECT_RADIUS = NODE_RADIUS - 1,
+
+ BUILDING_HUB_RADIUS = 16
+};
+
+enum {
+ STATE_CHOOSE_BEHAVIOR = 0,
+ STATE_CHOOSE_TARGET = 1,
+ STATE_ATTEMPT_SEARCH = 2,
+ STATE_INIT_APPROACH_TARGET = 3,
+ STATE_APPROACH_TARGET = 4,
+ STATE_INIT_ACQUIRE_TARGET = 5,
+ STATE_ACQUIRE_TARGET = 6,
+ STATE_ENERGIZE_TARGET = 7,
+ STATE_OFFEND_TARGET = 8,
+ STATE_DEFEND_TARGET = 9,
+ STATE_LAUNCH = 10,
+ STATE_CRAWLER_DECISION = 11,
+
+ TREE_DEPTH = 2
+};
+
+AI::AI(ScummEngine_v100he *vm) : _vm(vm) {
+ memset(_aiType, 0, sizeof(_aiType));
+ _aiState = STATE_CHOOSE_BEHAVIOR;
+ _behavior = 2;
+ _energyHogType = 0;
+
+ memset(_moveList, 0, sizeof(_moveList));
+ _mcpParams = 0;
+}
+
+void AI::resetAI() {
+ _aiState = STATE_CHOOSE_BEHAVIOR;
+ warning("----------------------> Resetting AI");
+
+ for (int i = 1; i != 5; i++) {
+ if (_aiType[i]) {
+ delete _aiType[i];
+ _aiType[i] = NULL;
+ }
+
+ _aiType[i] = new AIEntity(BRUTAKAS);
+ }
+
+ for (int i = 1; i != 5; i++) {
+ if (_moveList[i]) {
+ delete _moveList[i];
+ _moveList[i] = NULL;
+ }
+
+ _moveList[i] = new patternList;
+ }
+}
+
+void AI::cleanUpAI() {
+ warning("----------------------> Cleaning Up AI");
+
+ for (int i = 1; i != 5; i++) {
+ if (_aiType[i]) {
+ delete _aiType[i];
+ _aiType[i] = NULL;
+ }
+ }
+
+ for (int i = 1; i != 5; i++) {
+ if (_moveList[i]) {
+ delete _moveList[i];
+ _moveList[i] = NULL;
+ }
+ }
+}
+
+void AI::setAIType(const int paramCount, const int32 *params) {
+ if (_aiType[params[AI_TYPE_PLAYER_NUM]]) {
+ delete _aiType[params[AI_TYPE_PLAYER_NUM]];
+ _aiType[params[AI_TYPE_PLAYER_NUM]] = NULL;
+ }
+
+ _aiType[params[AI_TYPE_PLAYER_NUM]] = new AIEntity(params[AI_TYPE_TYPE]);
+
+ if (params[AI_TYPE_TYPE] == ENERGY_HOG) {
+ _energyHogType = 1;
+ } else {
+ _energyHogType = 0;
+ }
+
+ warning("AI for player %d is %s", params[AI_TYPE_PLAYER_NUM], _aiType[params[AI_TYPE_PLAYER_NUM]]->getNameString());
+}
+
+int AI::masterControlProgram(const int paramCount, const int32 *params) {
+ static Tree *myTree;
+
+ static int index;
+
+ _mcpParams = params;
+
+ static int lastSource[5];
+ static int lastAngle[5];
+ static int lastPower[5];
+
+
+ static int sourceHub;
+ static int target;
+
+ static int targetX;
+ static int targetY;
+
+ static int _acquireTarget = 0;
+
+ static int *launchAction = NULL;
+ static int *currentLaunchAction = NULL;
+
+ static int OLflag = 0;
+ static int TAflag = 0;
+
+
+ Node *retNode;
+ static int retNodeFlag;
+
+ // Memory cleanup in case of quit during game
+ if (_vm->readVar(_vm->VAR_U32_USER_VAR_F)) {
+ if (myTree != NULL) {
+ delete myTree;
+ myTree = NULL;
+ }
+
+ if (launchAction != NULL) {
+ delete launchAction;
+ launchAction = NULL;
+ }
+
+ if (currentLaunchAction != NULL) {
+ delete currentLaunchAction;
+ currentLaunchAction = NULL;
+ }
+
+ return 1;
+ }
+
+ int currentPlayer = getCurrentPlayer();
+
+ int maxTime = getPlayerMaxTime();
+ int timerValue = getTimerValue(3);
+
+ // If timer has run out
+ if ((_aiState > STATE_CHOOSE_BEHAVIOR) && ((maxTime) && (timerValue > maxTime))) {
+ if (myTree != NULL) {
+ delete myTree;
+ myTree = NULL;
+ }
+
+ if (launchAction != NULL) {
+ delete launchAction;
+ launchAction = NULL;
+ }
+
+ launchAction = new int[4];
+
+ if (currentLaunchAction != NULL) {
+ launchAction[LAUNCH_SOURCE_HUB] = currentLaunchAction[LAUNCH_SOURCE_HUB];
+ launchAction[LAUNCH_UNIT] = currentLaunchAction[LAUNCH_UNIT];
+ launchAction[LAUNCH_ANGLE] = currentLaunchAction[LAUNCH_ANGLE];
+ launchAction[LAUNCH_POWER] = currentLaunchAction[LAUNCH_POWER];
+ delete currentLaunchAction;
+ currentLaunchAction = NULL;
+ } else {
+ if (!_vm->_rnd.getRandomNumber(1))
+ launchAction[1] = ITEM_TIME_EXPIRED;
+ else
+ launchAction[1] = SKIP_TURN;
+ }
+
+ _aiState = STATE_LAUNCH;
+ }
+
+ static int old_aiState = 0;
+
+ if (old_aiState != _aiState) {
+ warning("<<%d>>", _aiState);
+ old_aiState = _aiState;
+ }
+
+ switch (_aiState) {
+ case STATE_CHOOSE_BEHAVIOR:
+ _behavior = chooseBehavior();
+ warning("Behavior mode: %d", _behavior);
+
+ if ((int)_vm->_rnd.getRandomNumber(99) < _aiType[getCurrentPlayer()]->getBehaviorVariation() * AI_VAR_BASE_BEHAVIOR + 1) {
+ if (_vm->_rnd.getRandomNumber(1)) {
+ _behavior--;
+
+ if (_behavior < ENERGY_MODE)
+ _behavior = DEFENSE_MODE;
+ } else {
+ _behavior++;
+
+ if (_behavior > DEFENSE_MODE)
+ _behavior = ENERGY_MODE;
+ }
+
+ warning("Alternative behavior: %d", _behavior);
+ }
+
+ if (_behavior == ENERGY_MODE)
+ if (!getNumberOfPools())
+ _behavior = OFFENSE_MODE;
+
+ if (_aiType[getCurrentPlayer()]->getID() == CRAWLER_CHUCKER)
+ _behavior = OFFENSE_MODE;
+
+ if (launchAction != NULL) {
+ delete launchAction;
+ launchAction = NULL;
+ }
+
+ index = 0;
+ _aiState = STATE_CHOOSE_TARGET;
+ break;
+
+ case STATE_CHOOSE_TARGET:
+ target = chooseTarget(_behavior);
+
+ if (!target)
+ target = chooseTarget(OFFENSE_MODE);
+
+ if (_behavior == ENERGY_MODE) {
+ int energyPoolScummArray = getEnergyPoolsArray();
+ targetX = _vm->_moonbase->readFromArray(energyPoolScummArray, target, ENERGY_POOL_X);
+ targetY = _vm->_moonbase->readFromArray(energyPoolScummArray, target, ENERGY_POOL_Y);
+ } else {
+ targetX = getHubX(target);
+ targetY = getHubY(target);
+ }
+
+ warning("Target (%d, %d) id: %d", targetX, targetY, target);
+
+ if (getFOW())
+ _aiState = STATE_ATTEMPT_SEARCH;
+ else
+ _aiState = STATE_INIT_APPROACH_TARGET;
+
+ break;
+
+ case STATE_ATTEMPT_SEARCH:
+ if (!getCoordinateVisibility(targetX, targetY, currentPlayer)) {
+ int closestHub = getClosestUnit(targetX, targetY, getMaxX(), currentPlayer, 1, BUILDING_MAIN_BASE, 1, 0);
+ int targetAngle = calcAngle(getHubX(closestHub), getHubY(closestHub), targetX, targetY);
+ int testX = static_cast<int>(getHubX(closestHub) + (500 * cos(degToRad(targetAngle))) + getMaxX()) % getMaxX();
+ int testY = static_cast<int>(getHubY(closestHub) + (500 * sin(degToRad(targetAngle))) + getMaxY()) % getMaxY();
+
+ int balloonFlag = 0;
+
+ int unitsArray = getUnitsWithinRadius(testX, testY, 500);
+ int unitsCounter = 0;
+
+ //see if any balloons are already in the area
+ int nextBuilding = _vm->_moonbase->readFromArray(unitsArray, 0, unitsCounter);
+
+ while (nextBuilding) {
+ if (((getBuildingType(nextBuilding) == BUILDING_BALLOON) || (getBuildingType(nextBuilding) == BUILDING_TOWER)) && (getBuildingTeam(nextBuilding) == getPlayerTeam(currentPlayer))) {
+ balloonFlag = 1;
+ nextBuilding = 0;
+ continue;
+ }
+
+ unitsCounter++;
+ nextBuilding = _vm->_moonbase->readFromArray(unitsArray, 0, unitsCounter);
+ }
+
+ _vm->_moonbase->deallocateArray(unitsArray);
+
+ if (!balloonFlag) {
+ launchAction = new int[4];
+ launchAction[LAUNCH_SOURCE_HUB] = closestHub;
+
+ if (getPlayerEnergy() > 3) {
+ launchAction[LAUNCH_UNIT] = ITEM_BALLOON;
+ launchAction[LAUNCH_POWER] = getMaxPower();
+ } else {
+ launchAction[LAUNCH_UNIT] = ITEM_TOWER;
+ launchAction[LAUNCH_POWER] = getMinPower();
+ }
+
+ launchAction[LAUNCH_ANGLE] = targetAngle + (_vm->_rnd.getRandomNumber(89) - 45);
+
+ int newTargetPos = abs(fakeSimulateWeaponLaunch(getHubX(closestHub), getHubY(closestHub), launchAction[LAUNCH_POWER], launchAction[LAUNCH_ANGLE]));
+ targetX = newTargetPos % getMaxX();
+ targetY = newTargetPos / getMaxY();
+
+ _aiState = STATE_INIT_ACQUIRE_TARGET;
+ break;
+ }
+ }
+
+ _aiState = STATE_INIT_APPROACH_TARGET;
+ break;
+
+ case STATE_INIT_APPROACH_TARGET:
+ {
+ int closestOL = getClosestUnit(targetX, targetY, 900, currentPlayer, 1, BUILDING_OFFENSIVE_LAUNCHER, 1);
+
+ if (closestOL && (_behavior == OFFENSE_MODE)) {
+ _aiState = STATE_OFFEND_TARGET;
+ break;
+ }
+ }
+
+ // get closest hub...if attack mode and almost close enough, maybe throw an offense
+ if ((_behavior == OFFENSE_MODE) && (getPlayerEnergy() > 6)) {
+ if (!_vm->_rnd.getRandomNumber(2)) {
+ int closestHub = getClosestUnit(targetX, targetY, getMaxX(), currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+
+ int dist = getDistance(targetX, targetY, getHubX(closestHub), getHubY(closestHub));
+
+ if ((dist > 470) && (dist < 900)) {
+ int closestOL = getClosestUnit(targetX, targetY, 900, currentPlayer, 1, BUILDING_OFFENSIVE_LAUNCHER, 0);
+
+ if (!closestOL) {
+ // Launch an OL
+ OLflag = 1;
+ targetX = getHubX(closestHub);
+ targetY = getHubY(closestHub);
+
+ _aiState = STATE_DEFEND_TARGET;
+ break;
+ }
+ }
+ }
+ }
+
+ if ((_behavior == OFFENSE_MODE) && (_aiType[currentPlayer]->getID() == RANGER) && (getPlayerEnergy() > 2)) {
+ int closestHub = getClosestUnit(targetX, targetY, getMaxX(), currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+ int dist = getDistance(targetX, targetY, getHubX(closestHub), getHubY(closestHub));
+
+ if (dist < 750) {
+ _aiState = STATE_OFFEND_TARGET;
+ break;
+ }
+ }
+
+ myTree = initApproachTarget(targetX, targetY, &retNode);
+
+ // If no need to approach, apply appropriate behavior
+ if (retNode == myTree->getBaseNode()) {
+ switch (_behavior) {
+ case 0:
+ _aiState = STATE_ENERGIZE_TARGET;
+ break;
+
+ case 1:
+ _aiState = STATE_OFFEND_TARGET;
+ break;
+
+ case 2:
+ _aiState = STATE_DEFEND_TARGET;
+ break;
+
+ case -1:
+ _aiState = STATE_LAUNCH;
+ break;
+ }
+
+ delete myTree;
+ myTree = NULL;
+ break;
+ }
+
+ delete retNode;
+ retNode = NULL;
+
+ if (getPlayerEnergy() < 7) {
+ if (!_vm->_rnd.getRandomNumber(3)) {
+ _behavior = DEFENSE_MODE;
+ _aiState = STATE_CHOOSE_TARGET;
+ } else {
+ if (launchAction == NULL) {
+ launchAction = new int[4];
+ }
+
+ if (!_vm->_rnd.getRandomNumber(2)) {
+ launchAction[1] = ITEM_TIME_EXPIRED;
+ } else {
+ launchAction[1] = SKIP_TURN;
+ }
+
+ _aiState = STATE_LAUNCH;
+ }
+
+ delete myTree;
+ myTree = NULL;
+ break;
+ }
+
+ _aiState = STATE_CRAWLER_DECISION;
+ break;
+
+ // If behavior is offense, possibly just chuck a crawler
+ case STATE_CRAWLER_DECISION:
+ {
+ // Brace just here to scope throwCrawler
+ int throwCrawler = 0;
+
+ if (_behavior == OFFENSE_MODE) {
+ if (getPlayerEnergy() > 6) {
+ int crawlerTest = _vm->_rnd.getRandomNumber(9);
+
+ if (!crawlerTest)
+ throwCrawler = 1;
+ }
+ }
+
+ if (_aiType[getCurrentPlayer()]->getID() == CRAWLER_CHUCKER) {
+ if (getPlayerEnergy() > 6) {
+ throwCrawler = 1;
+ } else {
+ launchAction = new int[4];
+
+ if (!_vm->_rnd.getRandomNumber(1))
+ launchAction[1] = ITEM_TIME_EXPIRED;
+ else
+ launchAction[1] = SKIP_TURN;
+
+ _aiState = STATE_LAUNCH;
+ delete myTree;
+ myTree = NULL;
+ }
+ }
+
+ if (throwCrawler) {
+ sourceHub = getClosestUnit(targetX, targetY, getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1);
+ int powAngle = getPowerAngleFromPoint(getHubX(sourceHub), getHubY(sourceHub), targetX, targetY, 15);
+ powAngle = abs(powAngle);
+ int power = powAngle / 360;
+ int angle = powAngle - (power * 360);
+
+ launchAction = new int[4];
+ launchAction[0] = sourceHub;
+ launchAction[1] = ITEM_CRAWLER;
+ warning("CRAWLER DECISION is launching a crawler");
+ launchAction[2] = angle;
+ launchAction[3] = power;
+ retNodeFlag = 0;
+
+ // Need to update target so acquire can work
+ int targetCoords = fakeSimulateWeaponLaunch(getHubX(launchAction[LAUNCH_SOURCE_HUB]), getHubY(launchAction[LAUNCH_SOURCE_HUB]), launchAction[LAUNCH_POWER], launchAction[LAUNCH_ANGLE]);
+ targetX = targetCoords % getMaxX();
+ targetY = targetCoords / getMaxX();
+ targetX = (targetX + getMaxX()) % getMaxX();
+ targetY = (targetY + getMaxY()) % getMaxY();
+
+ _aiState = STATE_INIT_ACQUIRE_TARGET;
+ delete myTree;
+ myTree = NULL;
+ } else {
+ _aiState = STATE_APPROACH_TARGET;
+ }
+ break;
+ }
+
+ // ApproachTarget returns NULL if target is already reachable
+ case STATE_APPROACH_TARGET:
+ {
+ int x, y;
+ Node *currentNode = NULL;
+ launchAction = approachTarget(myTree, x, y, &currentNode);
+ }
+
+ if (launchAction != NULL) {
+ if (launchAction[0] == -1) {
+ warning("Creating fake target approach hub");
+ TAflag = 1;
+ int closestHub = getClosestUnit(targetX, targetY, getMaxX(), currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+ targetX = getHubX(closestHub);
+ targetY = getHubY(closestHub);
+
+ delete launchAction;
+ launchAction = NULL;
+ _aiState = STATE_DEFEND_TARGET;
+ delete myTree;
+ myTree = NULL;
+ break;
+ }
+
+ // Need to update target so acquire can work
+ int targetCoords = fakeSimulateWeaponLaunch(getHubX(launchAction[LAUNCH_SOURCE_HUB]), getHubY(launchAction[LAUNCH_SOURCE_HUB]), launchAction[LAUNCH_POWER], launchAction[LAUNCH_ANGLE]);
+ targetX = targetCoords % getMaxX();
+ targetY = targetCoords / getMaxX();
+ targetX = (targetX + getMaxX()) % getMaxX();
+ targetY = (targetY + getMaxY()) % getMaxY();
+
+ _aiState = STATE_INIT_ACQUIRE_TARGET;
+ _behavior = -1;
+
+ delete myTree;
+ myTree = NULL;
+ }
+
+ break;
+
+ case STATE_ENERGIZE_TARGET:
+ launchAction = energizeTarget(targetX, targetY, index);
+
+ if (launchAction != NULL) {
+ if (launchAction[0]) {
+ assert(launchAction[0] > 0);
+
+ if (launchAction[1] == ITEM_HUB) {
+ index = 0;
+ retNodeFlag = 0;
+ _aiState = STATE_INIT_ACQUIRE_TARGET;
+ } else {
+ index = 0;
+ _aiState = STATE_INIT_ACQUIRE_TARGET;
+ }
+ } else {
+ index++;
+ delete launchAction;
+ launchAction = NULL;
+ }
+ } else {
+ _behavior = DEFENSE_MODE;
+ retNodeFlag = 0;
+ index = 0;
+ _aiState = STATE_CHOOSE_TARGET;
+ }
+ break;
+
+ case STATE_OFFEND_TARGET:
+ launchAction = offendTarget(targetX, targetY, index);
+
+ if (launchAction != NULL) {
+ if (launchAction[0]) {
+ retNodeFlag = 0;
+ _aiState = STATE_INIT_ACQUIRE_TARGET;
+ } else {
+ index++;
+ delete launchAction;
+ launchAction = NULL;
+ }
+ }
+ break;
+
+ case STATE_DEFEND_TARGET:
+ launchAction = defendTarget(targetX, targetY, index);
+
+ if (launchAction != NULL) {
+ if (launchAction[0]) {
+ retNodeFlag = 0;
+ _aiState = STATE_INIT_ACQUIRE_TARGET;
+
+ if (launchAction[LAUNCH_UNIT] != ITEM_BRIDGE) {
+ if (OLflag) {
+ OLflag = 0;
+ launchAction[LAUNCH_UNIT] = ITEM_OFFENSE;
+ }
+
+ if (TAflag) {
+ TAflag = 0;
+ warning("replacing defense unit %d with a hub", launchAction[LAUNCH_UNIT]);
+ launchAction[LAUNCH_UNIT] = ITEM_HUB;
+ }
+ }
+ } else {
+ index++;
+ delete launchAction;
+ launchAction = NULL;
+ }
+ }
+ break;
+
+ case STATE_INIT_ACQUIRE_TARGET:
+ myTree = initAcquireTarget(targetX, targetY, &retNode);
+
+ if (myTree == NULL) {
+ _aiState = STATE_LAUNCH;
+ break;
+ }
+
+ // This next line is a questionable fix
+ if (retNode == myTree->getBaseNode())
+ retNodeFlag = 1;
+
+ _acquireTarget = 0;
+
+ _aiState = STATE_ACQUIRE_TARGET;
+ break;
+
+ case STATE_ACQUIRE_TARGET: {
+ // Here to scope tempLaunchAction
+ int *tempLaunchAction = NULL;
+
+ int errCod = 0;
+
+ _acquireTarget++;
+
+ if (!retNodeFlag) {
+ tempLaunchAction = acquireTarget(targetX, targetY, myTree, errCod);
+ } else {
+ warning("NOT acquiring target!!!!!!!");
+ _acquireTarget = 101;
+ }
+
+ if (tempLaunchAction != NULL) {
+ if (launchAction != NULL) {
+ delete launchAction;
+ launchAction = NULL;
+ }
+
+ launchAction = tempLaunchAction;
+ }
+
+ // If no hubs are available for launching...turn must be skipped
+ if (launchAction != NULL) {
+ if (launchAction[LAUNCH_SOURCE_HUB] == 0) {
+ launchAction[LAUNCH_UNIT] = SKIP_TURN;
+ }
+ }
+
+ if ((tempLaunchAction != NULL) || (errCod == 1) || (_acquireTarget > 100)) {
+ if (tempLaunchAction == NULL) {
+ warning("\nABORTING acquire target!!!!!");
+ }
+
+ assert(launchAction != NULL);
+ delete myTree;
+ myTree = NULL;
+ _aiState = STATE_LAUNCH;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (_aiState == STATE_LAUNCH) {
+ static float randomAttenuation = 1;
+
+ if (((launchAction[LAUNCH_UNIT] == ITEM_REPAIR) || (launchAction[LAUNCH_UNIT] == ITEM_ANTIAIR) || (launchAction[LAUNCH_UNIT] == ITEM_BRIDGE) || (launchAction[LAUNCH_UNIT] == ITEM_TOWER) || (launchAction[LAUNCH_UNIT] == ITEM_RECLAIMER) || (launchAction[LAUNCH_UNIT] == ITEM_BALLOON) || (launchAction[LAUNCH_UNIT] == ITEM_MINE) || (launchAction[LAUNCH_UNIT] == ITEM_ENERGY) || (launchAction[LAUNCH_UNIT] == ITEM_SHIELD) || (launchAction[LAUNCH_UNIT] == ITEM_OFFENSE) || (launchAction[LAUNCH_UNIT] == ITEM_HUB)) && (getBuildingType(launchAction[LAUNCH_SOURCE_HUB]) == BUILDING_OFFENSIVE_LAUNCHER)) {
+ if (getPlayerEnergy() > 2) {
+ launchAction[LAUNCH_UNIT] = ITEM_GUIDED;
+ } else {
+ launchAction[LAUNCH_UNIT] = ITEM_BOMB;
+ }
+ }
+
+ if ((lastSource[currentPlayer] == launchAction[LAUNCH_SOURCE_HUB]) && (lastAngle[currentPlayer] == launchAction[LAUNCH_ANGLE]) && (lastPower[currentPlayer] == launchAction[LAUNCH_POWER])) {
+ randomAttenuation -= .2f;
+ randomAttenuation = MAX(randomAttenuation, 0.0f);
+ warning("Attenuating...");
+ } else {
+ randomAttenuation = 1;
+ }
+
+ lastSource[currentPlayer] = launchAction[LAUNCH_SOURCE_HUB];
+ lastAngle[currentPlayer] = launchAction[LAUNCH_ANGLE];
+ lastPower[currentPlayer] = launchAction[LAUNCH_POWER];
+
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_A, launchAction[LAUNCH_SOURCE_HUB]);
+ int energy = getPlayerEnergy();
+ warning("Computer's energy: %d", energy);
+
+ // Check if there's enough energy to launch this item
+ int n = (launchAction[1] / 6);
+ int energyRequired = (1 + n * n + n);
+
+ if (((energy - energyRequired) < 0) || (!launchAction[LAUNCH_SOURCE_HUB])) {
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_B, SKIP_TURN);
+ } else {
+ assert((launchAction[LAUNCH_UNIT] >= 0) && (launchAction[LAUNCH_UNIT] <= 18));
+
+ if ((launchAction[LAUNCH_UNIT] < 0) || (launchAction[LAUNCH_UNIT] > 18)) launchAction[LAUNCH_UNIT] = 0;
+
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_B, launchAction[LAUNCH_UNIT]);
+ }
+
+ if (launchAction[LAUNCH_UNIT] == ITEM_BOMB) {
+ if (energy > 2) {
+ if (!_vm->_rnd.getRandomNumber(4)) {
+ launchAction[LAUNCH_UNIT] = ITEM_GUIDED;
+ }
+ }
+ }
+
+ {
+ // ANGLE setting
+ int angleAdjustment = (int)(_vm->_rnd.getRandomNumber(_aiType[getCurrentPlayer()]->getAngleVariation() * AI_VAR_BASE_ANGLE) * 3.6);
+ //pos or neg choice
+ angleAdjustment *= ((_vm->_rnd.getRandomNumber(1) * 2) - 1);
+ angleAdjustment *= randomAttenuation;
+
+ int safeAngle = 0;
+ int lu = launchAction[LAUNCH_UNIT];
+
+ if ((lu == ITEM_ANTIAIR) || (lu == ITEM_TOWER) || (lu == ITEM_ENERGY) || (lu == ITEM_SHIELD) || (lu == ITEM_OFFENSE) || (lu == ITEM_HUB)) {
+ for (int i = 1; i < 90; i++) {
+ assert((launchAction[LAUNCH_ANGLE] < 1000) && (angleAdjustment < 360));
+
+ if (checkForAngleOverlap(launchAction[LAUNCH_SOURCE_HUB], launchAction[LAUNCH_ANGLE] + angleAdjustment)) {
+ angleAdjustment += (i % 2 ? i : -i);
+ } else {
+ safeAngle = 1;
+ i = 90;
+ }
+ }
+ } else {
+ safeAngle = 1;
+ }
+
+ if (!safeAngle) angleAdjustment = 0;
+
+ warning("Angle adjustment = %d", angleAdjustment);
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_C, launchAction[LAUNCH_ANGLE] + angleAdjustment);
+ }
+
+ {
+ // POWER setting
+ int powerRangeFactor = (getMaxPower() - getMinPower()) / 100;
+ int powerAdjustment = static_cast<float>(_vm->_rnd.getRandomNumber(_aiType[getCurrentPlayer()]->getPowerVariation() * AI_VAR_BASE_POWER)) * powerRangeFactor;
+ //pos or neg choice
+ powerAdjustment *= ((_vm->_rnd.getRandomNumber(1) * 2) - 1);
+ powerAdjustment *= randomAttenuation;
+
+ warning("Power adjustment = %d", powerAdjustment);
+ int newPower = MIN(getMaxPower(), launchAction[LAUNCH_POWER] + powerAdjustment);
+ newPower = MAX(getMinPower(), launchAction[LAUNCH_POWER] + powerAdjustment);
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_D, newPower);
+
+ assert(_vm->readVar(_vm->VAR_U32_USER_VAR_B) != -1);
+
+ if (launchAction[LAUNCH_UNIT] != SKIP_TURN) {
+ if ((launchAction[LAUNCH_SOURCE_HUB] > 0) && (launchAction[LAUNCH_SOURCE_HUB] <= 500)) {
+ if (getBuildingState(launchAction[LAUNCH_SOURCE_HUB]) != 0) {
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_B, SKIP_TURN);
+ }
+ } else {
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_B, SKIP_TURN);
+ }
+ }
+
+ if ((launchAction[LAUNCH_UNIT] == SKIP_TURN) || (launchAction[LAUNCH_POWER] == 0)) {
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_D, -1);
+ }
+ }
+
+
+ if ((launchAction[LAUNCH_SOURCE_HUB] > 0) && (launchAction[LAUNCH_SOURCE_HUB] <= 500)) {
+ int nearbyOpponents = getUnitsWithinRadius(getHubX(launchAction[LAUNCH_SOURCE_HUB]), getHubY(launchAction[LAUNCH_SOURCE_HUB]), 180);
+ int opponentCounter = 0;
+ int opponentBuilding = _vm->_moonbase->readFromArray(nearbyOpponents, 0, opponentCounter);
+ int defenseOn = 0;
+ int defenseOff = 0;
+
+ while (opponentBuilding) {
+ if (getBuildingOwner(opponentBuilding)) {
+ if ((getBuildingType(opponentBuilding) == BUILDING_ANTI_AIR) && (getBuildingTeam(opponentBuilding) != getPlayerTeam(currentPlayer))) {
+ if (getBuildingState(opponentBuilding) == 0) {
+ defenseOn = 1;
+ } else {
+ defenseOff = 1;
+ }
+ }
+ }
+
+ opponentCounter++;
+ opponentBuilding = _vm->_moonbase->readFromArray(nearbyOpponents, 0, opponentCounter);
+ }
+
+ _vm->_moonbase->deallocateArray(nearbyOpponents);
+
+ if (defenseOn && defenseOff) {
+ if (!_vm->_rnd.getRandomNumber(1)) {
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_B, ITEM_TIME_EXPIRED);
+ } else {
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_B, SKIP_TURN);
+ }
+ } else {
+ if (defenseOn) {
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_B, ITEM_CLUSTER);
+ int temp = _vm->_rnd.getRandomNumber(2);
+ int tempPower = 0;
+
+ switch (temp) {
+ case 0:
+ tempPower = getMinPower();
+ break;
+
+ case 1:
+ tempPower = getMaxPower();
+ break;
+
+ default:
+ tempPower = launchAction[LAUNCH_POWER];
+ }
+
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_D, tempPower);
+ }
+ }
+ }
+
+ delete[] launchAction;
+ launchAction = NULL;
+
+ _aiState = STATE_CHOOSE_BEHAVIOR;
+
+ int rSh, rU, rP, rA = 0;
+ rSh = _vm->readVar(_vm->VAR_U32_USER_VAR_A);
+ rU = _vm->readVar(_vm->VAR_U32_USER_VAR_B);
+ rP = _vm->readVar(_vm->VAR_U32_USER_VAR_D);
+ rA = _vm->readVar(_vm->VAR_U32_USER_VAR_C);
+
+ warning("su: %d unit: %d power: %d angle: %d", rSh, rU, rP, rA);
+
+ {
+ // Checking for patterns
+ if ((_aiType[currentPlayer]->getID() != CRAWLER_CHUCKER) &&
+ (_aiType[currentPlayer]->getID() != ENERGY_HOG) && (getBuildingStackPtr() > 5))
+ _moveList[currentPlayer]->addPattern(rSh, rU, rP, rA);
+
+ int patternFound = _moveList[currentPlayer]->evaluatePattern(rSh, rU, rP, rA);
+
+ if (!_vm->_rnd.getRandomNumber(9))
+ patternFound = 0;
+
+ if (patternFound) {
+ warning("------------------------------------------>Eliminating pattern");
+
+ if (_vm->_rnd.getRandomNumber(1)) {
+ _behavior--;
+
+ if (_behavior < ENERGY_MODE)
+ _behavior = DEFENSE_MODE;
+ } else {
+ _behavior++;
+
+ if (_behavior > DEFENSE_MODE)
+ _behavior = ENERGY_MODE;
+ }
+
+ if (_behavior == ENERGY_MODE)
+ if (!getNumberOfPools())
+ _behavior = OFFENSE_MODE;
+
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_A, 0);
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_B, 0);
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_C, 0);
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_D, 0);
+ _aiState = STATE_CHOOSE_TARGET;
+ }
+ }
+
+ if ((rSh > 0) && (rSh < 501)) {
+ if ((rU == ITEM_ANTIAIR) || (rU == ITEM_TOWER) || (rU == ITEM_ENERGY) || (rU == ITEM_SHIELD) || (rU == ITEM_OFFENSE) || (rU == ITEM_HUB)) {
+ int tryCount = 0;
+
+ while (checkForAngleOverlap(rSh, rA) && tryCount < 25) {
+ rA = _vm->_rnd.getRandomNumber(359);
+ tryCount++;
+ }
+
+ if (tryCount < 25) {
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_C, rA);
+ } else {
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_B, SKIP_TURN);
+ }
+ }
+ }
+ } else {
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_A, 0);
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_B, 0);
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_C, 0);
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_D, 0);
+ }
+
+ // Sending behavior to SCUMM side for profiling
+ int selectedUnit = _vm->readVar(_vm->VAR_U32_USER_VAR_B);
+
+ if (selectedUnit) {
+ if (selectedUnit > 0)
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_E, _behavior);
+ else
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_E, -999);
+ }
+
+ return 1;
+}
+
+int AI::chooseBehavior() {
+ static int dominantMode = 0;
+
+ if (getBuildingStackPtr() < 5)
+ return OFFENSE_MODE;
+
+ int currentPlayer = getCurrentPlayer();
+
+ int AIpersonality = _aiType[currentPlayer]->getID();
+
+ switch (AIpersonality) {
+ case BRUTAKAS:
+ dominantMode = OFFENSE_MODE;
+ break;
+
+ case AGI:
+ dominantMode = DEFENSE_MODE;
+ break;
+
+ case EL_GATO:
+ dominantMode = ENERGY_MODE;
+ break;
+
+ case PIXELAHT:
+ dominantMode = DEFENSE_MODE;
+ break;
+
+ case CYBALL:
+ dominantMode = ENERGY_MODE;
+ break;
+
+ case NEEP:
+ dominantMode = DEFENSE_MODE;
+ break;
+
+ case WARCUPINE:
+ dominantMode = ENERGY_MODE;
+ break;
+
+ case AONE:
+ dominantMode = DEFENSE_MODE;
+ break;
+
+ case SPANDO:
+ dominantMode = ENERGY_MODE;
+ break;
+
+ case ORBNU_LUNATEK:
+ dominantMode = ENERGY_MODE;
+ break;
+
+ case CRAWLER_CHUCKER:
+ dominantMode = OFFENSE_MODE;
+ break;
+
+ case ENERGY_HOG:
+ dominantMode = ENERGY_MODE;
+ {
+ int breakFlag = 0;
+
+ for (int i = 500; i > 0; i--)
+ if ((getBuildingOwner(i) == currentPlayer) && (getBuildingType(i) == BUILDING_ENERGY_COLLECTOR))
+ breakFlag = 1;
+
+ if (!breakFlag)
+ return ENERGY_MODE;
+ }
+ break;
+
+ case RANGER:
+ dominantMode = OFFENSE_MODE;
+
+ //random chance of defense if really early in game, otherwise offense
+ if (_vm->_rnd.getRandomNumber(1) || getTurnCounter() > 4)
+ return OFFENSE_MODE;
+
+ return DEFENSE_MODE;
+ break;
+
+ default: //BRUTAKAS
+ dominantMode = OFFENSE_MODE;
+ break;
+ }
+
+ // get a list of all the visible enemy units
+ int eneCon = 0;
+ int offCon = 0;
+ int defCon = 0;
+
+ // energy mode
+ {
+ warning("Starting Energy Behavior Selection");
+ int minEnergy = 8;
+ int maxEnergy = 14;
+
+ if (dominantMode == ENERGY_MODE) {
+ eneCon = 3;
+ maxEnergy = 21;
+ } else {
+ eneCon = 5;
+ }
+
+
+ // loop through energy pool array
+ int energyPoolScummArray = getEnergyPoolsArray();
+ int numPools = getNumberOfPools();
+
+ // Prevent energy from being chosen if not enough energy to create
+ int energyAmount = getPlayerEnergy();
+
+ if ((energyAmount < 7))
+ numPools = 0;
+
+ for (int i = 1; i <= numPools; i++) {
+ int poolX = _vm->_moonbase->readFromArray(energyPoolScummArray, i, ENERGY_POOL_X);
+ int poolY = _vm->_moonbase->readFromArray(energyPoolScummArray, i, ENERGY_POOL_Y);
+
+ int radius = energyPoolSize(i) / 2;
+ int poolMaxCount = getMaxCollectors(i);
+
+ int energyCount = 0;
+ int energyUnits = getUnitsWithinRadius(poolX, poolY, radius + 30);
+ int energyCounter = 0;
+ int energyBuilding = _vm->_moonbase->readFromArray(energyUnits, 0, energyCounter);
+
+
+ while (energyBuilding) {
+ energyCounter++;
+
+ if ((getBuildingType(energyBuilding) == BUILDING_ENERGY_COLLECTOR) && (getBuildingOwner(energyBuilding) != currentPlayer))
+ energyCount = poolMaxCount;
+
+ if ((getBuildingType(energyBuilding) == BUILDING_ENERGY_COLLECTOR) && (getBuildingOwner(energyBuilding) == currentPlayer))
+ energyCount++;
+
+ energyBuilding = _vm->_moonbase->readFromArray(energyUnits, 0, energyCounter);
+ }
+
+ _vm->_moonbase->deallocateArray(energyUnits);
+
+ if (energyCount < poolMaxCount) {
+ int closestHub = getClosestUnit(poolX, poolY, 300, currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+
+ if (closestHub) {
+ eneCon = MIN(1, eneCon);
+ } else {
+ int secondClosestHub = getClosestUnit(poolX, poolY, 480, currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+
+ if (secondClosestHub)
+ eneCon = MIN(2, eneCon);
+ else
+ eneCon = MIN(3, eneCon);
+ }
+ }
+ }
+
+ int totalEnergy = estimateNextRoundEnergy(currentPlayer);
+
+ if (totalEnergy < minEnergy)
+ eneCon--;
+
+ if (totalEnergy > maxEnergy)
+ eneCon += 2;
+
+ if ((totalEnergy > 34) || (!numPools))
+ eneCon = 10;
+
+ if (dominantMode == ENERGY_MODE)
+ eneCon--;
+ }
+
+
+ // offense mode
+ {
+ warning("Starting Offense Behavior Selection");
+
+ if (dominantMode == OFFENSE_MODE) offCon = 3;
+ else offCon = 5;
+
+ int enemyArray = getEnemyUnitsVisible(currentPlayer);
+ int enemyX = 0;
+ int enemyY = 0;
+ int hubX = 0;
+ int hubY = 0;
+
+ int nearEnemyHub = 0;
+
+ // cycle through the array of buildings
+ for (int i = 0; i < 500; i++) {
+ if (int thisBuilding = _vm->_moonbase->readFromArray(enemyArray, i, 0)) {
+ enemyX = getHubX(thisBuilding);
+ enemyY = getHubY(thisBuilding);
+ int closestHub = getClosestUnit(enemyX, enemyY, 970, currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+ int closestOL = getClosestUnit(enemyX, enemyY, 970, currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+ int dist = 0;
+
+ if (closestOL) {
+ hubX = getHubX(closestOL);
+ hubY = getHubY(closestOL);
+ nearEnemyHub = 1;
+ }
+
+ if (closestHub) {
+ hubX = getHubX(closestHub);
+ hubY = getHubY(closestHub);
+ dist = getDistance(hubX, hubY, enemyX, enemyY);
+
+ if (dist < 480)
+ nearEnemyHub = 1;
+ }
+
+
+ if (closestHub || closestOL) {
+ int numDefenders = 0;
+ int defArray = getUnitsWithinRadius(enemyX, enemyY, 170);
+ int defCounter = 0;
+ int defenseBuilding = _vm->_moonbase->readFromArray(defArray, 0, defCounter);
+
+ while (defenseBuilding) {
+ defCounter++;
+
+ if (((getBuildingType(defenseBuilding) == BUILDING_ANTI_AIR) ||
+ (getBuildingType(defenseBuilding) == BUILDING_SHIELD)) &&
+ (getBuildingOwner(defenseBuilding) != currentPlayer)) {
+ if (getBuildingState(defenseBuilding) == 0)
+ numDefenders++;
+ }
+
+ defenseBuilding = _vm->_moonbase->readFromArray(defArray, 0, defCounter);
+ }
+
+ _vm->_moonbase->deallocateArray(defArray);
+
+ if (!numDefenders) {
+ int defArray2 = getUnitsWithinRadius(hubX, hubY, 170);
+ defCounter = 0;
+ int defenseBuilding2 = _vm->_moonbase->readFromArray(defArray2, 0, defCounter);
+
+ while (defenseBuilding2) {
+ defCounter++;
+
+ if (((getBuildingType(defenseBuilding2) == BUILDING_ANTI_AIR) ||
+ (getBuildingType(defenseBuilding2) == BUILDING_SHIELD)) &&
+ (getBuildingOwner(defenseBuilding2) != currentPlayer))
+ if (getBuildingState(defenseBuilding2) == 0)
+ numDefenders++;
+
+ defenseBuilding2 = _vm->_moonbase->readFromArray(defArray, 0, defCounter);
+ }
+
+ _vm->_moonbase->deallocateArray(defArray2);
+
+ }
+
+ if ((!numDefenders) && (nearEnemyHub)) {
+ if (thisBuilding > 495)
+ offCon = 1 + _vm->_rnd.getRandomNumber(1);
+ else
+ offCon = MIN(offCon, 2);
+ } else {
+ if (thisBuilding > 495) {
+ if (nearEnemyHub) {
+ offCon = MIN(offCon, 2);
+ break;
+ } else {
+ offCon = MIN(offCon, 3);
+ break;
+ }
+ } else {
+ offCon = MIN(offCon, 4);
+ }
+ }
+ }
+
+ if (getBuildingType(thisBuilding) == BUILDING_CRAWLER) {
+ if (getClosestUnit(enemyX, enemyY, 350, currentPlayer, 1, 0, 0)) {
+ int closestHub1 = getClosestUnit(enemyX, enemyY, 460, currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+ int closestMine = getClosestUnit(enemyX, enemyY, 80, 0, 0, BUILDING_EXPLOSIVE_MINE, 1);
+
+ if (closestHub1 && !closestMine)
+ offCon = -1;
+ }
+ }
+ } else {
+ break;
+ }
+ }
+
+ _vm->_moonbase->deallocateArray(enemyArray);
+ offCon--;
+ }
+
+ // defense mode
+ {
+ warning("Starting Defense Behavior Selection");
+
+ if (dominantMode == DEFENSE_MODE)
+ defCon = 3;
+ else
+ defCon = 5;
+
+ int numDefenders = 0;
+ int openFlag = 0;
+
+ int mainHubX = getHubX(0);
+ int mainHubY = getHubY(0);
+ int mainHub = getClosestUnit(mainHubX + 10, mainHubY, 20, currentPlayer, 1, BUILDING_MAIN_BASE, 0);
+
+ int damageFlag = 0;
+
+ // cycle through the array of buildings
+ for (int i = 500; i >= 1; i--) {
+ if ((i < 497) && (defCon < 3))
+ break;
+
+ if (getBuildingOwner(i) == currentPlayer) {
+ int type = getBuildingType(i);
+ int hubX = getHubX(i);
+ int hubY = getHubY(i);
+
+ if (type == BUILDING_MAIN_BASE || type == BUILDING_ENERGY_COLLECTOR || type == BUILDING_OFFENSIVE_LAUNCHER) {
+ int nearEnemy = 0;
+ int closeBuildingsArray = getUnitsWithinRadius(hubX, hubY, 480);
+ int closeBuildingCounter = 0;
+ int closeBuilding = _vm->_moonbase->readFromArray(closeBuildingsArray, 0, closeBuildingCounter);
+
+ while (closeBuilding) {
+ closeBuildingCounter++;
+
+ if ((getBuildingOwner(closeBuilding) != currentPlayer) && (getBuildingType(closeBuilding) == BUILDING_MAIN_BASE)) {
+ nearEnemy = 1;
+ break;
+ }
+
+ closeBuilding = _vm->_moonbase->readFromArray(closeBuildingsArray, 0, closeBuildingCounter);
+ }
+
+ _vm->_moonbase->deallocateArray(closeBuildingsArray);
+
+ int defCounter = 0;
+ int defArray = getUnitsWithinRadius(hubX, hubY, 170);
+ int defenseBuilding = _vm->_moonbase->readFromArray(defArray, 0, defCounter);
+ numDefenders = 0;
+
+ while (defenseBuilding) {
+ defCounter++;
+
+ if (((getBuildingType(defenseBuilding) == BUILDING_ANTI_AIR) || (getBuildingType(defenseBuilding) == BUILDING_SHIELD)) && (getBuildingOwner(defenseBuilding) == currentPlayer)) {
+ //main base has enemies near, but is defended
+ if (getBuildingState(defenseBuilding) == 0)
+ numDefenders++;
+ }
+
+ defenseBuilding = _vm->_moonbase->readFromArray(defArray, 0, defCounter);
+ }
+
+ _vm->_moonbase->deallocateArray(defArray);
+
+ if (numDefenders > 2)
+ defCon++;
+
+ if (numDefenders < 2)
+ if (dominantMode == DEFENSE_MODE)
+ openFlag = 1;
+
+ if (!numDefenders) {
+ if (nearEnemy) {
+ if (i == mainHub) {
+ defCon = 1;
+ break;
+ } else {
+ defCon = MIN(defCon, 2);
+ }
+ } else {
+ if (i == mainHub)
+ defCon = MIN(defCon, 3);
+ else
+ defCon = MIN(defCon, 4);
+ }
+ }
+
+ if (getBuildingArmor(i) < getBuildingMaxArmor(i))
+ damageFlag = 1;
+ }
+ }
+ }
+
+ if (damageFlag && (defCon > 1))
+ defCon--;
+
+ if (!openFlag && defCon == 3)
+ defCon += 2;
+ }
+
+ warning("%s-------------------------------> Energy: %d Offense: %d Defense: %d", _aiType[currentPlayer]->getNameString(), eneCon, offCon, defCon);
+
+ if (dominantMode == DEFENSE_MODE)
+ if ((defCon <= offCon) && (defCon <= eneCon))
+ return DEFENSE_MODE;
+
+ if (dominantMode == OFFENSE_MODE)
+ if ((offCon <= eneCon) && (offCon <= defCon))
+ return OFFENSE_MODE;
+
+ if (dominantMode == ENERGY_MODE)
+ if ((eneCon <= offCon) && (eneCon <= defCon))
+ return ENERGY_MODE;
+
+ if ((defCon <= offCon) && (defCon <= eneCon))
+ return DEFENSE_MODE;
+
+ if ((offCon <= eneCon) && (offCon <= defCon))
+ return OFFENSE_MODE;
+
+ if ((eneCon <= offCon) && (eneCon <= defCon))
+ return ENERGY_MODE;
+
+ return -1;
+}
+
+int AI::chooseTarget(int behavior) {
+ int numPools = getNumberOfPools();
+ int currentPlayer = getCurrentPlayer();
+
+ int selection = 0;
+ int selectionValues[50] = {0};
+ int selectionDist = 10000000;
+
+ if (behavior == ENERGY_MODE) {
+ // loop through energy pool array
+ int energyPoolScummArray = getEnergyPoolsArray();
+
+ for (int i = 1; i <= numPools; i++) {
+ // check # units on pool
+ int numPoolSpots = _vm->_moonbase->readFromArray(energyPoolScummArray, i, ENERGY_POOL_UNITS_ON);
+
+ if (numPoolSpots == 0) {
+ // put this one in the middle
+ warning("Empty pool #%d", i);
+ selectionValues[i] = 2;
+ } else {
+ // get units w/in radius of pool
+ int poolUnitsArray = getUnitsWithinRadius(_vm->_moonbase->readFromArray(energyPoolScummArray, i, ENERGY_POOL_X), _vm->_moonbase->readFromArray(energyPoolScummArray, i, ENERGY_POOL_Y), 50);
+ int enemyPool = 0;
+ int j = 1;
+ int thisPoolUnit = _vm->_moonbase->readFromArray(poolUnitsArray, 0, j);
+
+ while (thisPoolUnit) {
+ if (getBuildingOwner(thisPoolUnit) != currentPlayer)
+ enemyPool = 1;
+
+ j++;
+ thisPoolUnit = _vm->_moonbase->readFromArray(poolUnitsArray, 0, j);
+ }
+
+ _vm->_moonbase->deallocateArray(poolUnitsArray);
+
+ // if enemy collector, put at bottom
+ if (enemyPool) {
+ selectionValues[i] = 1;
+ } else if (numPoolSpots < getMaxCollectors(i)) {
+ selectionValues[i] = 3;
+ } else {
+ // this pool is filled
+ selectionValues[i] = 0;
+ }
+ }
+
+ if (selectionValues[i] > selectionValues[selection]) {
+ selection = i;
+ } else if (selectionValues[i] == selectionValues[selection]) {
+ int poolX = _vm->_moonbase->readFromArray(energyPoolScummArray, i, ENERGY_POOL_X);
+ int poolY = _vm->_moonbase->readFromArray(energyPoolScummArray, i, ENERGY_POOL_Y);
+
+ int closestHub = getClosestUnit(poolX, poolY, getMaxX(), currentPlayer, 1, BUILDING_MAIN_BASE, 1, 100);
+ int thisDist = getDistance(poolX, poolY, getHubX(closestHub), getHubY(closestHub));
+
+ if (thisDist < selectionDist) {
+ selection = i;
+ selectionDist = thisDist;
+ }
+ }
+
+ }
+
+ warning("Pool selected: %d dist: %d", selection, selectionDist);
+ return selection;
+ }
+
+ if (behavior == OFFENSE_MODE) {
+ int returnBuilding = 0;
+ int attackableArray[500];
+ int nearAttackableArray[500];
+ int attackableIndex = 0;
+ int nearAttackableIndex = 0;
+
+ int enemyArray = getEnemyUnitsVisible(currentPlayer);
+
+ for (int i = 500; i >= 1; i--) {
+ int thisBuilding = _vm->_moonbase->readFromArray(enemyArray, i - 1, 0);
+
+ if (thisBuilding) {
+ if (getBuildingType(thisBuilding) == BUILDING_CRAWLER) {
+ if ((getTerrain(getHubX(thisBuilding), getHubY(thisBuilding)) != TERRAIN_TYPE_WATER) || (getPlayerEnergy() > 6)) {
+ if (getClosestUnit(getHubX(thisBuilding), getHubY(thisBuilding), 380, currentPlayer, 1, BUILDING_MAIN_BASE, 1)) {
+ returnBuilding = thisBuilding;
+ _vm->_moonbase->deallocateArray(enemyArray);
+ return returnBuilding;
+ }
+ } else {
+ continue;
+ }
+ }
+
+ int enemyX = getHubX(thisBuilding);
+ int enemyY = getHubY(thisBuilding);
+ int closestHub = getClosestUnit(enemyX, enemyY, 930, currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+
+ int dist = getDistance(enemyX, enemyY, getHubX(closestHub), getHubY(closestHub));
+
+ if (getBuildingType(thisBuilding) != BUILDING_BALLOON) {
+ if (dist < 470) {
+ attackableArray[attackableIndex] = thisBuilding;
+ attackableIndex++;
+ } else {
+ nearAttackableArray[nearAttackableIndex] = thisBuilding;
+ nearAttackableIndex++;
+ }
+ }
+ }
+ }
+
+ _vm->_moonbase->deallocateArray(enemyArray);
+
+ if (attackableIndex) {
+ int thisWorth = 0;
+ int savedWorth = 1;
+ int closestSavedShield = 0;
+ int closestSavedAntiAir = 0;
+
+ for (int i = 0; i < attackableIndex; i++) {
+ thisWorth = getBuildingWorth(attackableArray[i]);
+
+ if (thisWorth == savedWorth) {
+ int closestShield = getClosestUnit(getHubX(attackableArray[i]), getHubY(attackableArray[i]), 180, currentPlayer, 0, BUILDING_SHIELD, 1);
+ int closestAntiAir = getClosestUnit(getHubX(attackableArray[i]), getHubY(attackableArray[i]), 180, currentPlayer, 0, BUILDING_ANTI_AIR, 1);
+
+ if (closestSavedShield > closestShield) {
+ savedWorth = thisWorth;
+ closestSavedShield = closestShield;
+ closestSavedAntiAir = closestAntiAir;
+ returnBuilding = attackableArray[i];
+ } else {
+ if (closestSavedAntiAir > closestAntiAir) {
+ savedWorth = thisWorth;
+ closestSavedShield = closestShield;
+ closestSavedAntiAir = closestAntiAir;
+ returnBuilding = attackableArray[i];
+ }
+ }
+ }
+
+ if (thisWorth > savedWorth) {
+ savedWorth = thisWorth;
+ returnBuilding = attackableArray[i];
+ }
+ }
+ } else {
+ if (nearAttackableIndex) {
+ int thisWorth = 0;
+ int savedWorth = 1;
+ int closestSavedShield = 0;
+ int closestSavedAntiAir = 0;
+
+ for (int i = 0; i < nearAttackableIndex; i++) {
+ thisWorth = getBuildingWorth(nearAttackableArray[i]);
+
+ if (thisWorth == savedWorth) {
+ int closestShield = getClosestUnit(getHubX(nearAttackableArray[i]), getHubY(nearAttackableArray[i]), 180, currentPlayer, 0, BUILDING_SHIELD, 1);
+ int closestAntiAir = getClosestUnit(getHubX(nearAttackableArray[i]), getHubY(nearAttackableArray[i]), 180, currentPlayer, 0, BUILDING_ANTI_AIR, 1);
+
+ if (closestSavedShield > closestShield) {
+ savedWorth = thisWorth;
+ closestSavedShield = closestShield;
+ closestSavedAntiAir = closestAntiAir;
+ returnBuilding = nearAttackableArray[i];
+ } else {
+ if (closestSavedAntiAir > closestAntiAir) {
+ savedWorth = thisWorth;
+ closestSavedShield = closestShield;
+ closestSavedAntiAir = closestAntiAir;
+ returnBuilding = nearAttackableArray[i];
+ }
+ }
+ }
+
+ if (thisWorth > savedWorth) {
+ savedWorth = thisWorth;
+ returnBuilding = nearAttackableArray[i];
+ }
+ }
+ }
+ }
+
+ if (!returnBuilding) {
+ for (int i = 500; i > 496; i--) {
+ if (getBuildingOwner(i)) {
+ if (getBuildingTeam(i) != getPlayerTeam(currentPlayer)) {
+ returnBuilding = i;
+ i = 0;
+ }
+ }
+ }
+ }
+
+ warning("Attack target: %d", returnBuilding);
+
+ assert(returnBuilding);
+ return returnBuilding;
+ }
+
+ if (behavior == DEFENSE_MODE) {
+ int returnBuilding = 0;
+
+ int savedTally = 0;
+ int savedDamage;
+ float savedNumDefenses = 0;
+ int savedWorth = 0;
+
+ float numDefenses = 0;
+ int tally = 0;
+ int attackable = 0;
+ int attacked = 0;
+ int damage = 0;
+
+ int type = 0;
+ int worth = 0;
+
+
+ int attackedX = 0;
+ int attackedY = 0;
+ int attackedUnit = 0;
+
+ if (getLastAttacked(attackedX, attackedY)) {
+ (void)getClosestUnit(attackedX + 10, attackedY, 50, currentPlayer, 1, 0, 0); // Unused?
+ }
+
+ // loop through own units
+ for (int i = 1; i <= 500; i++) {
+ numDefenses = 0;
+ attackable = 0;
+ attacked = 0;
+ damage = 0;
+ type = 0;
+ worth = 0;
+
+ int owner = getBuildingOwner(i);
+
+ if (owner == currentPlayer) {
+ type = getBuildingType(i);
+
+ // if current unit in [hub, offense, energy, tower]
+ if ((type == BUILDING_MAIN_BASE) || (type == BUILDING_ENERGY_COLLECTOR) || (type == BUILDING_OFFENSIVE_LAUNCHER) || (type == BUILDING_TOWER)) {
+ worth = getBuildingWorth(i);
+
+ // Calculate current defenses
+ int x = getHubX(i);
+ int y = getHubY(i);
+ assert(x >= 0);
+ assert(y >= 0);
+
+ int defenseArray = getUnitsWithinRadius(x, y, 180);
+ int j = 0;
+ // cycle through the defense units close to the target building
+ int defenseBuilding = _vm->_moonbase->readFromArray(defenseArray, 0, j);
+
+ // loop on all defenses w/in 180
+ while (defenseBuilding != 0) {
+ int defenseType = getBuildingType(defenseBuilding);
+
+ // sub for each
+ if ((defenseType == BUILDING_ANTI_AIR) || (defenseType == BUILDING_SHIELD)) {
+ if (getBuildingState(defenseBuilding) == 0)
+ numDefenses += 1;
+ else
+ numDefenses += .5;
+ }
+
+ j++;
+ defenseBuilding = _vm->_moonbase->readFromArray(defenseArray, 0, j);
+ }
+
+ _vm->_moonbase->deallocateArray(defenseArray);
+
+ // Calculate if this unit is attackable
+ // get dist to nearest enemy hub, offense
+ int closestHub = getClosestUnit(x, y, getMaxX(), getCurrentPlayer(), 0, BUILDING_MAIN_BASE, 0);
+ int numStridesToHub = getDistance(getHubX(closestHub), getHubY(closestHub), x, y) / 480;
+ closestHub = getClosestUnit(x, y, getMaxX(), getCurrentPlayer(), 0, BUILDING_OFFENSIVE_LAUNCHER, 0);
+ int numStridesToOL = getDistance(getHubX(closestHub), getHubY(closestHub), x, y) / 800;
+
+ // sub for each stride away
+ if (!numStridesToOL || !numStridesToHub)
+ attackable = 1;
+
+ // Check if this unit was just attacked
+ if (attackedUnit == i)
+ attacked = 1;
+
+ if (!numDefenses) {
+ tally = 1;
+
+ if (attackable) {
+ tally = 4;
+
+ if (attacked) {
+ tally = 5;
+ }
+ }
+ } else {
+ if (attackable) {
+ tally = 2;
+
+ if (attacked) {
+ tally = 3;
+ }
+ }
+ }
+
+ // Check if this unit is damaged
+ int saveFlag = 0;
+
+ if (tally > savedTally) {
+ saveFlag = 1;
+ } else {
+ if (tally == savedTally) {
+ if (worth > savedWorth) {
+ saveFlag = 1;
+
+ if (numDefenses > savedNumDefenses) {
+ saveFlag = 0;
+ }
+ }
+
+ if (damage > savedDamage) {
+ saveFlag = 1;
+
+ if (numDefenses > savedNumDefenses) {
+ saveFlag = 0;
+ }
+ }
+
+ if (numDefenses < savedNumDefenses) {
+ saveFlag = 1;
+ }
+
+ if (numDefenses >= 3) {
+ saveFlag = 0;
+ }
+ }
+ }
+
+ if (saveFlag) {
+ savedTally = tally;
+ savedWorth = worth;
+ savedDamage = damage;
+ savedNumDefenses = numDefenses;
+ returnBuilding = i;
+ }
+ }
+ }
+ }
+
+ return returnBuilding;
+ }
+
+ return 0;
+}
+
+Tree *AI::initApproachTarget(int targetX, int targetY, Node **retNode) {
+ int sourceHub = 0;
+
+ if (_behavior == 2)
+ sourceHub = getClosestUnit(targetX + 10, targetY, getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1);
+ else
+ sourceHub = getClosestUnit(targetX + 10, targetY, getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, MIN_DIST);
+
+ Traveller *myTraveller = new Traveller(getHubX(sourceHub), getHubY(sourceHub), this);
+ myTraveller->setSourceHub(sourceHub);
+
+ //target adjustment so that room is allowed for the appropriate shot
+ int tempAngle = calcAngle(getHubX(sourceHub), getHubY(sourceHub), targetX, targetY);
+ int adjX = -120 * cos(degToRad(tempAngle));
+ int adjY = -120 * sin(degToRad(tempAngle));
+
+ Traveller::setTargetPosX(targetX + adjX);
+ Traveller::setTargetPosY(targetY + adjY);
+ Traveller::setMaxDist(340);
+
+ Tree *myTree = new Tree(myTraveller, TREE_DEPTH, this);
+ *retNode = myTree->aStarSearch_singlePassInit();
+
+ return myTree;
+}
+
+int *AI::approachTarget(Tree *myTree, int &xTarget, int &yTarget, Node **currentNode) {
+ int *retVal = NULL;
+
+ *currentNode = NULL;
+ Node *retNode = myTree->aStarSearch_singlePass();
+
+ if (*currentNode != NULL)
+ warning("########################################### Got a possible solution");
+
+ if (myTree->IsBaseNode(retNode)) {
+ warning("########################################### Returning Base Node");
+ retVal = new int[4];
+ retVal[0] = -1;
+ return retVal;
+ }
+
+ if (retNode == NULL) {
+ return retVal;
+ } else {
+ retVal = new int[4];
+
+ Traveller *retTraveller = reinterpret_cast<Traveller *>(retNode->getFirstStep()->getContainedObject());
+
+ // set launching hub, item to launch, angle of launch, power of launch
+ // if water flag is set, launch bridge instead of hub
+ retVal[0] = static_cast<Traveller *>(myTree->getBaseNode()->getContainedObject())->getSourceHub();
+
+ if (retTraveller->getWaterFlag()) {
+ int powAngle = getPowerAngleFromPoint(retTraveller->getWaterSourceX(),
+ retTraveller->getWaterSourceY(),
+ retTraveller->getWaterDestX(),
+ retTraveller->getWaterDestY(),
+ 15);
+
+ powAngle = abs(powAngle);
+ int power = powAngle / 360;
+ int angle = powAngle - (power * 360);
+
+ retVal[0] = getClosestUnit(retTraveller->getWaterSourceX() + 10, retTraveller->getWaterSourceY(), getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 0);
+
+ retVal[1] = ITEM_BRIDGE;
+ retVal[2] = angle;
+ retVal[3] = power;
+
+ warning("Target Bridge Coords: <%d, %d> ", retTraveller->getWaterDestX(), retTraveller->getWaterDestY());
+ } else {
+ retVal[1] = ITEM_HUB;
+ retVal[2] = retTraveller->getAngleTo();
+ retVal[3] = retTraveller->getPowerTo();
+ }
+
+
+ int whoseTurn = getCurrentPlayer();
+
+ if ((_lastXCoord[whoseTurn]).size() >= MAX_MEMORY) {
+ (_lastXCoord[whoseTurn]).erase((_lastXCoord[whoseTurn]).begin());
+ (_lastYCoord[whoseTurn]).erase((_lastYCoord[whoseTurn]).begin());
+ }
+
+ (_lastXCoord[whoseTurn]).push_back(retTraveller->getPosX());
+ (_lastYCoord[whoseTurn]).push_back(retTraveller->getPosY());
+
+ int temp = static_cast<int>(retTraveller->calcT());
+ int temp2 = static_cast<int>(retTraveller->getValueG());
+ int x = static_cast<int>(retTraveller->getPosX());
+ int y = static_cast<int>(retTraveller->getPosY());
+ warning("Target Coords: <%d, %d> G-value: %d T-value: %d", x, y, temp2, temp);
+ xTarget = x;
+ yTarget = y;
+ }
+
+ return retVal;
+}
+
+Tree *AI::initAcquireTarget(int targetX, int targetY, Node **retNode) {
+ int sourceHub = getClosestUnit(targetX, targetY, getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, MIN_DIST);
+ warning("My coords (%d): %d %d", sourceHub, getHubX(sourceHub), getHubY(sourceHub));
+
+ Sortie::setSourcePos(getHubX(sourceHub), getHubY(sourceHub));
+ Sortie::setTargetPos(targetX, targetY);
+ Sortie *myBaseTarget = new Sortie(this);
+ myBaseTarget->setValueG(0);
+
+ myBaseTarget->setUnitType(ITEM_BOMB);
+ myBaseTarget->setShotPos(-1, -1);
+
+ int unitsArray = getUnitsWithinRadius(targetX + 7, targetY, 211);
+
+ warning("Target Coords: <%d, %d> Source Coords: <%d, %d>", targetX, targetY, getHubX(sourceHub) , getHubY(sourceHub));
+
+ myBaseTarget->setEnemyDefenses(unitsArray, targetX, targetY);
+
+ int thisElement = _vm->_moonbase->readFromArray(unitsArray, 0, 0);
+
+ _vm->_moonbase->deallocateArray(unitsArray);
+
+ if (!thisElement) {
+ delete myBaseTarget;
+ return NULL;
+ }
+
+ Tree *myTree = new Tree(myBaseTarget, 4, this);
+ *retNode = myTree->aStarSearch_singlePassInit();
+
+ return myTree;
+}
+
+int *AI::acquireTarget(int targetX, int targetY, Tree *myTree, int &errorCode) {
+ int currentPlayer = getCurrentPlayer();
+ int *retVal = NULL;
+
+ Node *retNode = myTree->aStarSearch_singlePass();
+
+ if (myTree->IsBaseNode(retNode))
+ return acquireTarget(targetX, targetY);
+
+ if (retNode == NULL) {
+ errorCode = 0;
+ return retVal;
+ }
+
+ Sortie *thisSortie = static_cast<Sortie *>(retNode->getFirstStep()->getContainedObject());
+ int unitToShoot = thisSortie->getUnitType();
+
+ if (unitToShoot < 0) {
+ errorCode = 1;
+ return retVal;
+ }
+
+ if (unitToShoot == ITEM_CRAWLER) {
+ warning("target acquisition is launching a crawler");
+ }
+
+ int shotTargetX = thisSortie->getShotPosX();
+ int shotTargetY = thisSortie->getShotPosY();
+ int theTarget = getClosestUnit(shotTargetX + 5, shotTargetY, getMaxX(), 0, 0, 0, 0, 0);
+
+
+ int sourceOL = 0;
+ int sourceX = thisSortie->getSourcePosX();
+ int sourceY = thisSortie->getSourcePosY();
+
+ int sourceHub = getClosestUnit(sourceX + 5, sourceY, getMaxX(), currentPlayer, 1, BUILDING_MAIN_BASE, 1, 0);
+
+ sourceOL = getClosestUnit(sourceX, sourceY, 900, currentPlayer, 1, BUILDING_OFFENSIVE_LAUNCHER, 1, 110);
+
+ if (sourceOL) {
+ sourceHub = sourceOL;
+ sourceX = getHubX(sourceOL);
+ sourceY = getHubY(sourceOL);
+ }
+
+ if (!sourceHub) sourceHub = getClosestUnit(sourceX + 5, sourceY, getMaxX(), currentPlayer, 1, BUILDING_MAIN_BASE, 1, 0);
+
+ int powAngle = getPowerAngleFromPoint(sourceX, sourceY, shotTargetX, shotTargetY, 15, sourceOL);
+ warning("The source (%d: <%d, %d>) The target (%d: <%d, %d>)", sourceHub, sourceX, sourceY, theTarget, shotTargetX, shotTargetY);
+
+ powAngle = abs(powAngle);
+ int power = powAngle / 360;
+ int angle = powAngle - (power * 360);
+
+ retVal = new int[4];
+
+ retVal[0] = sourceHub;
+ retVal[1] = unitToShoot;
+ retVal[2] = angle;
+ retVal[3] = power;
+
+ warning("Unit to shoot: %d", unitToShoot);
+
+ return retVal;
+}
+
+int *AI::acquireTarget(int targetX, int targetY) {
+ int *retVal = new int[4];
+ int sourceHub = getClosestUnit(targetX, targetY, getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 110);
+
+ if (!sourceHub)
+ sourceHub = getClosestUnit(targetX, targetY, getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 0);
+
+ int directAngle = calcAngle(getHubX(sourceHub), getHubY(sourceHub), targetX, targetY);
+ int directDistance = getDistance(getHubX(sourceHub), getHubY(sourceHub), targetX, targetY);
+
+ retVal[0] = sourceHub;
+ retVal[1] = ITEM_OFFENSE;
+ retVal[2] = directAngle;
+ retVal[3] = MAX(MIN(getMaxPower() * directDistance / 500, getMaxPower()), getMinPower());
+
+ return retVal;
+}
+
+int *AI::energizeTarget(int &targetX, int &targetY, int index) {
+ int n = 10;
+ static int currentPlayer = 0;
+ static int pool = 0;
+ static int radius = 0;
+ static int poolUnitsArray = 0;
+ static int j = 0;
+ static int k = 0;
+ static int sameUnit = 0;
+ static int nextUnit = 0;
+ static int attempt = 0;
+
+ if (!index) {
+ warning("index is 0!");
+ currentPlayer = getCurrentPlayer();
+ pool = 0;
+
+ // get the pool that's closest to the target coords
+ for (int i = 1; i <= getNumberOfPools(); i++) {
+ int poolX = _vm->_moonbase->readFromArray(getEnergyPoolsArray(), i, ENERGY_POOL_X);
+ int poolY = _vm->_moonbase->readFromArray(getEnergyPoolsArray(), i, ENERGY_POOL_Y);
+
+ if ((poolX == targetX) && (poolY == targetY)) {
+ pool = i;
+ }
+ }
+
+ // calculate the appropriate radius
+ radius = energyPoolSize(pool) / 2;
+
+ // create test points
+ k = 0;
+ j = 0;
+ nextUnit = 0;
+ sameUnit = 0;
+ attempt = 0;
+ }
+
+ if (poolUnitsArray)
+ _vm->_moonbase->deallocateArray(poolUnitsArray);
+
+ poolUnitsArray = getUnitsWithinRadius(targetX, targetY, 450);
+ assert(poolUnitsArray);
+
+ // 0 is for energy collectors, 1 is for circumnavigating hubs
+ if (k < 2) {
+ if (!sameUnit) {
+ sameUnit = 1;
+ attempt = 0;
+ nextUnit = _vm->_moonbase->readFromArray(poolUnitsArray, 0, j);
+ j++;
+ }
+
+ if (nextUnit) {
+ if ((getBuildingType(nextUnit) == BUILDING_MAIN_BASE) && (getBuildingOwner(nextUnit) == currentPlayer)) {
+ int minAngle = 0;
+ int hubToPoolAngle = 0;
+ int testAngle = 0;
+ int testDist = 0;
+ static int xPos = 0;
+ static int yPos = 0;
+ static int newAttempt = 1;
+
+ if (sameUnit) {
+ if (k == 0) {
+ int poolToHubAngle = calcAngle(targetX, targetY, getHubX(nextUnit), getHubY(nextUnit));
+ minAngle = poolToHubAngle - 45;
+ } else {
+ hubToPoolAngle = calcAngle(getHubX(nextUnit), getHubY(nextUnit), targetX, targetY);
+ }
+ }
+
+ if (attempt < n) {
+ static int power = 0;
+ static int angle = 0;
+
+ if (newAttempt) {
+ newAttempt = 0;
+
+ if (k == 0) {
+ testAngle = (_vm->_rnd.getRandomNumber(89) + minAngle) % 360;
+ testDist = radius;
+
+ xPos = targetX + testDist * cos(degToRad(testAngle));
+ yPos = targetY + testDist * sin(degToRad(testAngle));
+ } else {
+ switch (_vm->_rnd.getRandomNumber(1)) {
+ case 0:
+ testAngle = (hubToPoolAngle + (45 + _vm->_rnd.getRandomNumber(19))) % 360;
+ break;
+
+ default:
+ testAngle = (hubToPoolAngle + (315 - _vm->_rnd.getRandomNumber(19))) % 360;
+ break;
+ }
+
+ testDist = ((((n - attempt) / n) * .5) + .5) * (getDistance(getHubX(nextUnit), getHubY(nextUnit), targetX, targetY) / .8);
+ xPos = getHubX(nextUnit) + testDist * cos(degToRad(testAngle));
+ yPos = getHubY(nextUnit) + testDist * sin(degToRad(testAngle));
+ }
+
+ // check if points are good
+ int powAngle = getPowerAngleFromPoint(getHubX(nextUnit), getHubY(nextUnit), xPos, yPos, 15);
+ powAngle = abs(powAngle);
+
+ power = powAngle / 360;
+ angle = powAngle - (power * 360);
+ }
+
+ int result = 0;
+ result = simulateBuildingLaunch(getHubX(nextUnit), getHubY(nextUnit), power, angle, 10, 1);
+
+ if (result) {
+ newAttempt = 1;
+
+ if (result > 0) {
+ xPos = (xPos + getMaxX()) % getMaxX();
+ yPos = (yPos + getMaxY()) % getMaxY();
+
+ result = 1;
+ } else {
+ // Drop a bridge for the cord
+ int yCoord = -result / getMaxX();
+ int xCoord = -result - (yCoord * getMaxX());
+
+ if (checkIfWaterState(xCoord, yCoord)) {
+ int terrainSquareSize = getTerrainSquareSize();
+ xCoord = ((xCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
+ yCoord = ((yCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
+
+ int xDist = xCoord - xPos;
+ int yDist = yCoord - yPos;
+ xPos = xCoord + (terrainSquareSize * 1.414 * (xDist / (abs(xDist) + 1)));
+ yPos = yCoord + (terrainSquareSize * 1.414 * (yDist / (abs(yDist) + 1)));
+
+ nextUnit = getClosestUnit(xPos, yPos, 480, getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 120);
+ int powAngle = getPowerAngleFromPoint(getHubX(nextUnit), getHubY(nextUnit), xPos, yPos, 15);
+
+ powAngle = abs(powAngle);
+ power = powAngle / 360;
+ angle = powAngle - (power * 360);
+
+ int *retVal = new int[4];
+
+ retVal[0] = nextUnit;
+ retVal[1] = ITEM_BRIDGE;
+ retVal[2] = angle;
+ retVal[3] = power;
+
+ if (nextUnit <= 0)
+ retVal[0] = 0;
+
+ _vm->_moonbase->deallocateArray(poolUnitsArray);
+ poolUnitsArray = 0;
+ return retVal;
+ }
+ }
+
+ if (result > 0) {
+ _vm->_moonbase->deallocateArray(poolUnitsArray);
+ poolUnitsArray = 0;
+
+ targetX = xPos;
+ targetY = yPos;
+
+ int *retVal = new int[4];
+
+ retVal[0] = nextUnit;
+
+ if (k == 0) {
+ retVal[1] = ITEM_ENERGY;
+ } else {
+ retVal[1] = ITEM_HUB;
+ }
+
+ retVal[2] = angle;
+ retVal[3] = power;
+ return retVal;
+ }
+ } else {
+ int *retVal = new int[4];
+ retVal[0] = 0;
+ _vm->_moonbase->deallocateArray(poolUnitsArray);
+ poolUnitsArray = 0;
+
+ return retVal;
+ }
+
+ attempt++;
+ } else {
+ sameUnit = 0;
+ }
+ } else {
+ sameUnit = 0;
+ }
+ } else {
+ sameUnit = 0;
+ k++;
+ j = 0;
+ }
+ } else {
+ _vm->_moonbase->deallocateArray(poolUnitsArray);
+ poolUnitsArray = 0;
+ return NULL;
+ }
+
+ _vm->_moonbase->deallocateArray(poolUnitsArray);
+ poolUnitsArray = 0;
+ int *retVal = new int[4];
+ retVal[0] = 0;
+
+ return retVal;
+}
+
+int *AI::offendTarget(int &targetX, int &targetY, int index) {
+ int *retVal = NULL;
+
+ int target = getClosestUnit(targetX + 10, targetY, 20, 0, 0, 0, 0);
+
+ if (!target)
+ target = getClosestUnit(targetX + 10, targetY, 0, 0, 0, 0, 0);
+
+ warning("The target inside the offendTarget routine is: %d", target);
+ int type = getBuildingType(target);
+ int unit = 0;
+
+ DefenseUnit *thisUnit;
+
+ switch (type) {
+ case BUILDING_OFFENSIVE_LAUNCHER:
+ thisUnit = new OffenseUnit(this);
+ break;
+
+ case BUILDING_TOWER:
+ thisUnit = new TowerUnit(this);
+ break;
+
+ case BUILDING_MAIN_BASE:
+ thisUnit = new HubUnit(this);
+ break;
+
+ case BUILDING_ENERGY_COLLECTOR:
+ thisUnit = new EnergyUnit(this);
+ break;
+
+ case BUILDING_CRAWLER:
+ thisUnit = new CrawlerUnit(this);
+ break;
+
+ case BUILDING_BRIDGE:
+ thisUnit = new BridgeUnit(this);
+ break;
+
+ case BUILDING_SHIELD:
+ thisUnit = new ShieldUnit(this);
+ break;
+
+ default:
+ thisUnit = new HubUnit(this);
+ break;
+ }
+
+ thisUnit->setPos(targetX, targetY);
+ thisUnit->setID(target);
+
+ int sourceHub = getClosestUnit(targetX, targetY, getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 110);
+ int sourceOL = 0;
+ sourceOL = getClosestUnit(targetX, targetY, 900, getCurrentPlayer(), 1, BUILDING_OFFENSIVE_LAUNCHER, 1, 110);
+
+ unit = thisUnit->selectWeapon(_vm->_rnd.getRandomNumber(4));
+
+ if (sourceOL) {
+ if ((unit == ITEM_BOMB) || (unit == ITEM_CLUSTER) || (unit == ITEM_GUIDED) || (unit == ITEM_EMP) || (unit == ITEM_SPIKE) || (unit == ITEM_CRAWLER) || (unit == ITEM_VIRUS)) {
+ sourceHub = sourceOL;
+ }
+ }
+
+ if (!sourceHub) {
+ retVal = new int[4];
+
+ retVal[1] = SKIP_TURN;
+ return retVal;
+ }
+
+
+ if ((thisUnit->getType() == BUILDING_CRAWLER) && (unit == SKIP_TURN)) {
+ retVal = new int[4];
+ retVal[1] = unit;
+ delete thisUnit;
+ return retVal;
+ }
+
+ if (unit == ITEM_CRAWLER) {
+ warning("******** offense is launching a crawler ********");
+ warning("The defensive unit is: %d", unit);
+ }
+
+ Common::Point *targetCoords;
+ int dist = getDistance(getHubX(sourceHub), getHubY(sourceHub), targetX, targetY);
+ targetCoords = thisUnit->createTargetPos(0, dist, unit, getHubX(sourceHub), getHubY(sourceHub));
+
+ int powAngle = getPowerAngleFromPoint(getHubX(sourceHub), getHubY(sourceHub), targetCoords->x, targetCoords->y, 15, sourceOL);
+ powAngle = abs(powAngle);
+ int power = powAngle / 360;
+ int angle = powAngle % 360;
+
+ if (unit == ITEM_MINE)
+ power -= 30;
+
+ targetX = targetCoords->x;
+ targetY = targetCoords->y;
+
+ if (targetX < 0)
+ targetX = (targetX + getMaxX()) % getMaxX();
+
+ if (targetY < 0)
+ targetY = (targetY + getMaxY()) % getMaxY();
+
+ assert(targetX >= 0 && targetY >= 0);
+ delete targetCoords;
+ delete thisUnit;
+
+ retVal = new int[4];
+
+ retVal[0] = sourceHub;
+ retVal[1] = unit;
+ retVal[2] = angle;
+ retVal[3] = power;
+
+ return retVal;
+}
+
+int *AI::defendTarget(int &targetX, int &targetY, int index) {
+ int *retVal = NULL;
+ Defender *thisDefender = new Defender(this);
+ int defStatus = thisDefender->calculateDefenseUnitPosition(targetX, targetY, index);
+
+ if (defStatus > 0) {
+ targetX = thisDefender->getTargetX();
+ targetY = thisDefender->getTargetY();
+ retVal = new int[4];
+
+ retVal[0] = thisDefender->getSourceUnit();
+ retVal[1] = thisDefender->getUnit();
+ retVal[2] = thisDefender->getAngle();
+ retVal[3] = thisDefender->getPower();
+ }
+
+ if (defStatus == 0) {
+ retVal = new int[4];
+ retVal[0] = 0;
+ }
+
+ if (defStatus == -1) {
+ if (thisDefender->getTargetX() || thisDefender->getTargetY()) {
+ targetX = thisDefender->getTargetX();
+ targetY = thisDefender->getTargetY();
+ }
+
+ retVal = new int[4];
+ retVal[0] = thisDefender->getSourceUnit();
+ retVal[1] = thisDefender->getUnit();
+ retVal[2] = thisDefender->getAngle();
+ retVal[3] = thisDefender->getPower();
+ }
+
+ if (defStatus == -3) {
+ retVal = new int[4];
+ retVal[0] = 0;
+ retVal[1] = SKIP_TURN;
+ retVal[2] = 0;
+ retVal[3] = 0;
+ }
+
+ assert(targetX >= 0 && targetY >= 0);
+
+ if (retVal[1] == ITEM_CRAWLER) {
+ warning("defend target is launching a crawler");
+ }
+
+ delete thisDefender;
+ return retVal;
+}
+
+int AI::getClosestUnit(int x, int y, int radius, int player, int alignment, int unitType, int checkUnitEnabled) {
+ assert((unitType >= 0) && (unitType <= 12));
+
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_CLOSEST_UNIT], 7, x, y, radius, player, alignment, unitType, checkUnitEnabled);
+ return retVal;
+}
+
+int AI::getClosestUnit(int x, int y, int radius, int player, int alignment, int unitType, int checkUnitEnabled, int minDist) {
+ assert((unitType >= 0) && (unitType <= 12));
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_CLOSEST_UNIT], 8, x, y, radius, player, alignment, unitType, checkUnitEnabled, minDist);
+ return retVal;
+}
+
+int AI::getDistance(int originX, int originY, int endX, int endY) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_WORLD_DIST], 4, originX, originY, endX, endY);
+ return retVal;
+}
+
+int AI::calcAngle(int originX, int originY, int endX, int endY) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_WORLD_ANGLE], 5, originX, originY, endX, endY, 0);
+ return retVal;
+}
+
+int AI::calcAngle(int originX, int originY, int endX, int endY, int noWrapFlag) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_WORLD_ANGLE], 5, originX, originY, endX, endY, noWrapFlag);
+ return retVal;
+}
+
+int AI::getTerrain(int x, int y) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_TERRAIN_TYPE], 2, x, y);
+ return retVal;
+}
+
+int AI::estimateNextRoundEnergy(int player) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_ESTIMATE_NEXT_ROUND_ENERGY], 1, player);
+ return retVal / 10;
+}
+
+int AI::getHubX(int hub) {
+ assert(hub >= 0 && hub <= 500);
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_HUB_X, hub);
+ return retVal;
+}
+
+int AI::getHubY(int hub) {
+ assert(hub >= 0 && hub <= 500);
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_HUB_Y, hub);
+ return retVal;
+}
+
+int AI::getMaxX() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_WORLD_X_SIZE);
+ return retVal;
+}
+
+int AI::getMaxY() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_WORLD_Y_SIZE);
+ return retVal;
+}
+
+int AI::getCurrentPlayer() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_CURRENT_PLAYER);
+ assert(retVal != 0);
+ return retVal;
+}
+
+int AI::getMaxPower() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_MAX_POWER);
+ return retVal;
+}
+
+int AI::getMinPower() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_MIN_POWER);
+ return retVal;
+}
+
+int AI::getTerrainSquareSize() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_TERRAIN_SQUARE_SIZE);
+ return retVal;
+}
+
+int AI::getBuildingOwner(int building) {
+ assert((building > 0) && (building < 501));
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_OWNER, building);
+ return retVal;
+}
+
+int AI::getBuildingState(int building) {
+ assert((building > 0) && (building < 501));
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_STATE, building);
+ return retVal;
+}
+
+int AI::getBuildingType(int building) {
+ assert((building > 0) && (building < 501));
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_TYPE, building);
+ return retVal;
+}
+
+int AI::getBuildingArmor(int building) {
+ assert((building > 0) && (building < 501));
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_ARMOR, building);
+ return retVal;
+}
+
+int AI::getBuildingWorth(int building) {
+ assert((building > 0) && (building < 501));
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_WORTH, building);
+ return retVal;
+}
+
+int AI::getEnergyPoolsArray() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_ENERGY_POOLS_ARRAY);
+ return retVal;
+}
+
+int AI::getCoordinateVisibility(int x, int y, int playerNum) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 4, D_GET_COORDINATE_VISIBILITY, x, y, playerNum);
+ return retVal;
+}
+
+int AI::getUnitVisibility(int unit, int playerNum) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 3, D_GET_UNIT_VISIBILITY, unit, playerNum);
+ return retVal;
+}
+
+int AI::getEnergyPoolVisibility(int pool, int playerNum) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 3, D_GET_ENERGY_POOL_VISIBILITY, pool, playerNum);
+ return retVal;
+}
+
+int AI::getNumberOfPools() {
+ int retVal = 0;
+
+ if (_aiType[getCurrentPlayer()]->getID() == ENERGY_HOG) {
+ retVal = 1;
+ } else {
+ retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_NUMBER_OF_POOLS);
+ }
+
+ return retVal;
+}
+
+int AI::getNumberOfPlayers() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_NUMBER_OF_PLAYERS);
+ return retVal;
+}
+
+int AI::getPlayerEnergy() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_PLAYER_ENERGY);
+ return static_cast<int>(static_cast<float>(retVal) / 10.0);
+}
+
+int AI::getPlayerMaxTime() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_PLAYER_MAX_TIME);
+ return retVal;
+}
+
+int AI::getWindXSpeed() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_WIND_X_SPEED);
+ return retVal;
+}
+
+int AI::getWindYSpeed() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_WIND_Y_SPEED);
+ return retVal;
+}
+
+int AI::getTotalWindSpeed() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_TOTAL_WIND_SPEED);
+ return retVal;
+}
+
+int AI::getWindXSpeedMax() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_WIND_X_SPEED_MAX);
+ return retVal;
+}
+
+int AI::getWindYSpeedMax() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_WIND_Y_SPEED_MAX);
+ return retVal;
+}
+
+int AI::getBigXSize() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_BIG_X_SIZE);
+ return retVal;
+}
+
+int AI::getBigYSize() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_BIG_Y_SIZE);
+ return retVal;
+}
+
+int AI::getEnergyPoolWidth(int pool) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_ENERGY_POOL_WIDTH, pool);
+ return retVal;
+}
+
+int AI::getBuildingMaxArmor(int building) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_MAX_ARMOR, building);
+ return retVal;
+}
+
+int AI::getTimerValue(int timerNum) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_TIMER_VALUE, timerNum);
+ return retVal;
+}
+
+int AI::getLastAttacked(int &x, int &y) {
+ int currentPlayer = getCurrentPlayer();
+ x = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_LAST_ATTACKED_X, currentPlayer);
+ y = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_LAST_ATTACKED_Y, currentPlayer);
+
+ if (x || y) return 1;
+
+ return 0;
+}
+
+int AI::getPlayerTeam(int player) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_PLAYER_TEAM, player);
+ return retVal;
+}
+
+int AI::getBuildingTeam(int building) {
+ assert((building >= 1) && (building <= 500));
+
+ if (getBuildingOwner(building) == 0) return 0;
+
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_TEAM, building);
+ return retVal;
+}
+
+int AI::getFOW() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_FOW);
+ return retVal;
+}
+
+int AI::getAnimSpeed() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_ANIM_SPEED);
+ return retVal;
+}
+
+int AI::getBuildingStackPtr() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_BUILDING_STACK_PTR);
+ return retVal;
+}
+
+int AI::getTurnCounter() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_TURN_COUNTER);
+ return retVal;
+}
+
+int AI::getGroundAltitude(int x, int y) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_GROUND_ALTITUDE], 2, x, y);
+ return retVal;
+}
+
+int AI::checkForCordOverlap(int xStart, int yStart, int affectRadius, int simulateFlag) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_CHECK_FOR_CORD_OVERLAP], 4, xStart, yStart, affectRadius, simulateFlag);
+ return retVal;
+}
+
+int AI::checkForAngleOverlap(int unit, int angle) {
+ assert(angle > -721);
+ assert(angle < 721);
+
+ if (!unit) return 0;
+
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_CHECK_FOR_ANGLE_OVERLAP], 2, unit, angle);
+ return retVal;
+}
+
+int AI::checkForUnitOverlap(int x, int y, int radius, int ignoredUnit) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_CHECK_FOR_UNIT_OVERLAP], 4, x, y, radius, ignoredUnit);
+ return retVal;
+}
+
+int AI::checkForEnergySquare(int x, int y) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_CHECK_FOR_ENERGY_SQUARE], 2, x, y);
+ return retVal;
+}
+
+int AI::aiChat() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_AI_CHAT], 0);
+ return retVal;
+}
+
+int AI::getPowerAngleFromPoint(int originX, int originY, int endX, int endY, int threshold, int olFlag) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_POWER_ANGLE_FROM_POINT], 6, originX, originY, endX, endY, threshold, olFlag);
+ return retVal;
+}
+
+int AI::getPowerAngleFromPoint(int originX, int originY, int endX, int endY, int threshold) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_POWER_ANGLE_FROM_POINT], 5, originX, originY, endX, endY, threshold);
+ return retVal;
+}
+
+int AI::checkIfWaterState(int x, int y) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_CHECK_IF_WATER_STATE], 2, x, y);
+ return retVal;
+}
+
+int AI::checkIfWaterSquare(int x, int y) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_CHECK_IF_WATER_SQUARE], 2, x, y);
+ return retVal;
+}
+
+int AI::getUnitsWithinRadius(int x, int y, int radius) {
+ assert(x >= 0);
+ assert(y >= 0);
+ assert(radius >= 0);
+
+ debug(0, "getUnitsWithinRadius(%d, %d, %d)", x, y, radius);
+
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_UNITS_WITHIN_RADIUS], 3, x, y, radius);
+ return retVal;
+}
+
+int AI::getLandingPoint(int x, int y, int power, int angle) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_LANDING_POINT], 4, x, y, power, angle);
+ return retVal;
+}
+
+int AI::getEnemyUnitsVisible(int playerNum) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_ENEMY_UNITS_VISIBLE], 1, playerNum);
+ return retVal;
+}
+
+float AI::degToRad(float degrees) {
+ return degrees * M_PI / 180.;
+}
+
+void AI::limitLocation(int &a, int &b, int c, int d) {
+ if (a >= 0) {
+ a = (a % c);
+ } else {
+ a = (c - (abs(a) % c));
+ }
+
+ if (b >= 0) {
+ b = (b % d);
+ } else {
+ b = (d - (abs(b) % d));
+ }
+}
+
+int AI::energyPoolSize(int pool) {
+ int width = getEnergyPoolWidth(pool);
+
+ switch (width) {
+ case 126:
+ return 115;
+
+ case 116:
+ return 100;
+
+ case 63:
+ return 60;
+ }
+
+ return 0;
+}
+
+int AI::getMaxCollectors(int pool) {
+ int width = getEnergyPoolWidth(pool);
+
+ switch (width) {
+ case 126:
+ return 4;
+
+ case 116:
+ return 3;
+
+ case 63:
+ return 2;
+ }
+
+ return 0;
+}
+
+int AI::simulateBuildingLaunch(int x, int y, int power, int angle, int numSteps, int isEnergy) {
+ static int sXSpeed = 0;
+ static int sYSpeed = 0;
+ static int sZSpeed = 0;
+ static int sXLoc = 0;
+ static int sYLoc = 0;
+ static int sZLoc = 0;
+ static int sFrictionCount = 0;
+ static int sWhichRadius = 0;
+ static int sWhichUnit = 0;
+
+ int gWindXSpeed = getWindXSpeed();
+ int gWindYSpeed = getWindYSpeed();
+ int gTotalWindSpeed = getTotalWindSpeed();
+ int gWindXSpeedMax = getWindXSpeedMax();
+ int gWindYSpeedMax = getWindYSpeedMax();
+ int bigXSize = getBigXSize();
+ int bigYSize = getBigYSize();
+
+ int groundAltitude = 0;
+ int totalSpeed = 0;
+ int resultingPoint = 0;
+ int unscaledXLoc = 0;
+ int unscaledYLoc = 0;
+ int terrainType = 0;
+ int passedBeyondUnit = 0;
+ int currentDist = 0;
+
+
+ if (!numSteps)
+ numSteps = 1;
+
+ if (!sXSpeed && !sYSpeed) {
+ sZSpeed = (static_cast<int>(.70711 * power)) ;
+ sXSpeed = (static_cast<int>(cos(degToRad(angle)) * sZSpeed)) ;
+ sYSpeed = (static_cast<int>(sin(degToRad(angle)) * sZSpeed)) ;
+
+ sZSpeed *= SCALE_Z;
+
+ sZLoc = (getGroundAltitude(x, y) + HEIGHT_LOW + 10) * SCALE_Z;
+
+ sXLoc = x * SCALE_X;
+ sYLoc = y * SCALE_Y;
+
+ sFrictionCount = 0;
+ sWhichRadius = NODE_DETECT_RADIUS + 1;
+
+ sWhichUnit = getClosestUnit(x + 10, y, 30, getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 0, 0);
+ }
+
+ for (int i = 1; i <= numSteps; i++) {
+ unscaledXLoc = sXLoc / SCALE_X;
+ unscaledYLoc = sYLoc / SCALE_Y;
+
+ groundAltitude = getGroundAltitude(unscaledXLoc, unscaledYLoc);
+ groundAltitude *= SCALE_Z;
+
+ sZLoc += sZSpeed / SCALE_Z;
+
+ resultingPoint = MAX(1, unscaledXLoc + unscaledYLoc * getMaxX());
+
+ if (sZLoc <= groundAltitude) {
+ terrainType = getTerrain(unscaledXLoc, unscaledYLoc);
+
+ sXSpeed = 0;
+ sYSpeed = 0;
+ sFrictionCount = 0;
+
+ if (terrainType == TERRAIN_TYPE_GOOD)
+ return resultingPoint;
+ else
+ return 0 - resultingPoint;
+ } else {
+ if (checkIfWaterState(unscaledXLoc, unscaledYLoc)) {
+ sXSpeed = 0;
+ sYSpeed = 0;
+ sFrictionCount = 0;
+
+ return 0 - resultingPoint;
+ } else {
+ int cfco = 0;
+ int cfuo = 0;
+ int cfes = 0;
+ int cfao = 0;
+ cfao = checkForAngleOverlap(sWhichUnit, angle);
+
+ cfco = checkForCordOverlap(unscaledXLoc, unscaledYLoc, sWhichRadius, 1);
+ cfuo = checkForUnitOverlap(unscaledXLoc, unscaledYLoc, sWhichRadius, sWhichUnit);
+
+ if (!isEnergy)
+ cfes = checkForEnergySquare(unscaledXLoc, unscaledYLoc);
+
+ if (cfco || cfuo || cfes || cfao) {
+ sXSpeed = 0;
+ sYSpeed = 0;
+ sFrictionCount = 0;
+
+ return 0 - resultingPoint;
+ } else {
+ sFrictionCount++;
+
+ if (sFrictionCount == 10) {
+ sFrictionCount = 0;
+
+ if (!gWindXSpeed)
+ sXSpeed = sXSpeed * .95;
+
+ if (!gWindYSpeed)
+ sYSpeed = sYSpeed * .95;
+ }
+
+ if (passedBeyondUnit) {
+ totalSpeed = getDistance(0, 0, sXSpeed, sYSpeed);
+
+ if (totalSpeed > gTotalWindSpeed) {
+ if (gWindXSpeed > 0) {
+ if (sXSpeed < gWindXSpeedMax)
+ sXSpeed += gWindXSpeed;
+ } else {
+ if (sXSpeed > gWindXSpeedMax)
+ sXSpeed += gWindXSpeed;
+ }
+
+ if (gWindYSpeed > 0) {
+ if (sYSpeed < gWindYSpeedMax)
+ sYSpeed += gWindYSpeed;
+ } else {
+ if (sYSpeed > gWindYSpeedMax)
+ sYSpeed += gWindYSpeed;
+ }
+ }
+ } else {
+ currentDist = getDistance(unscaledXLoc, unscaledYLoc, x, y);
+
+ if (currentDist > BUILDING_HUB_RADIUS + NODE_DIAMETER)
+ passedBeyondUnit = 1;
+ }
+
+ sXLoc += sXSpeed;
+ sYLoc += sYSpeed;
+
+ limitLocation(sXLoc, sYLoc, bigXSize, bigYSize);
+
+ sZSpeed -= GRAVITY_CONSTANT;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+int AI::simulateWeaponLaunch(int x, int y, int power, int angle, int numSteps) {
+ static int sXSpeed = 0;
+ static int sYSpeed = 0;
+ static int sZSpeed = 0;
+ static int sXLoc = 0;
+ static int sYLoc = 0;
+ static int sZLoc = 0;
+ static int sFrictionCount = 0;
+
+ int gWindXSpeed = getWindXSpeed();
+ int gWindYSpeed = getWindYSpeed();
+ int gTotalWindSpeed = getTotalWindSpeed();
+ int gWindXSpeedMax = getWindXSpeedMax();
+ int gWindYSpeedMax = getWindYSpeedMax();
+ int bigXSize = getBigXSize();
+ int bigYSize = getBigYSize();
+
+ int groundAltitude = 0;
+ int totalSpeed = 0;
+ int resultingPoint = 0;
+ int unscaledXLoc = 0;
+ int unscaledYLoc = 0;
+ int terrainType = 0;
+ int passedBeyondUnit = 0;
+ int currentDist = 0;
+
+ if (!numSteps) numSteps = 1;
+
+ if (!sXSpeed && !sYSpeed) {
+ sZSpeed = (static_cast<int>(.70711 * power)) ;
+ sXSpeed = (static_cast<int>(cos(degToRad(angle)) * sZSpeed)) ;
+ sYSpeed = (static_cast<int>(sin(degToRad(angle)) * sZSpeed)) ;
+
+ sZSpeed *= SCALE_Z;
+
+ sZLoc = (getGroundAltitude(x, y) + HEIGHT_LOW + 10) * SCALE_Z;
+
+ sXLoc = x * SCALE_X;
+ sYLoc = y * SCALE_Y;
+
+ sFrictionCount = 0;
+ }
+
+ for (int i = 1; i <= numSteps; i++) {
+ unscaledXLoc = sXLoc / SCALE_X;
+ unscaledYLoc = sYLoc / SCALE_Y;
+
+ groundAltitude = getGroundAltitude(unscaledXLoc, unscaledYLoc);
+ groundAltitude *= SCALE_Z;
+ sZLoc += sZSpeed / SCALE_Z;
+ resultingPoint = MAX(1, unscaledXLoc + unscaledYLoc * getMaxX());
+
+ if (sZLoc <= groundAltitude) {
+ terrainType = getTerrain(unscaledXLoc, unscaledYLoc);
+
+ sXSpeed = 0;
+ sYSpeed = 0;
+ sFrictionCount = 0;
+
+ if (terrainType == TERRAIN_TYPE_GOOD)
+ return resultingPoint;
+ else
+ return 0 - resultingPoint;
+ } else {
+ sFrictionCount++;
+
+ if (sFrictionCount == 10) {
+ sFrictionCount = 0;
+
+ if (!gWindXSpeed)
+ sXSpeed = sXSpeed * .95;
+
+ if (!gWindYSpeed)
+ sYSpeed = sYSpeed * .95;
+ }
+
+ if (passedBeyondUnit) {
+ totalSpeed = getDistance(0, 0, sXSpeed, sYSpeed);
+
+ if (totalSpeed > gTotalWindSpeed) {
+ if (gWindXSpeed > 0) {
+ if (sXSpeed < gWindXSpeedMax)
+ sXSpeed += gWindXSpeed;
+ } else {
+ if (sXSpeed > gWindXSpeedMax)
+ sXSpeed += gWindXSpeed;
+ }
+
+ if (gWindYSpeed > 0) {
+ if (sYSpeed < gWindYSpeedMax)
+ sYSpeed += gWindYSpeed;
+ } else {
+ if (sYSpeed > gWindYSpeedMax)
+ sYSpeed += gWindYSpeed;
+ }
+ }
+ } else {
+ currentDist = getDistance(unscaledXLoc, unscaledYLoc, x, y);
+
+ if (currentDist > BUILDING_HUB_RADIUS + NODE_DIAMETER)
+ passedBeyondUnit = 1;
+ }
+
+ sXLoc += sXSpeed;
+ sYLoc += sYSpeed;
+
+ limitLocation(sXLoc, sYLoc, bigXSize, bigYSize);
+
+ sZSpeed -= GRAVITY_CONSTANT;
+ }
+ }
+
+ return 0;
+}
+
+int AI::fakeSimulateWeaponLaunch(int x, int y, int power, int angle) {
+ int distance = power * 480 / getMaxPower();
+ float radAngle = degToRad(angle);
+ int maxX = getMaxX();
+ int maxY = getMaxY();
+
+ x += distance * cos(radAngle);
+ y += distance * sin(radAngle);
+
+ x = (x + maxX) % maxX;
+ y = (y + maxY) % maxY;
+
+ return MAX(1, x + y * maxX);
+}
+
+int AI::getEnergyHogType() {
+ return _energyHogType;
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_main.h b/engines/scumm/he/moonbase/ai_main.h
new file mode 100644
index 0000000000..7a38de9458
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_main.h
@@ -0,0 +1,211 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SCUMM_HE_MOONBASE_AI_MAIN_H
+#define SCUMM_HE_MOONBASE_AI_MAIN_H
+
+#include "common/array.h"
+#include "scumm/he/moonbase/ai_tree.h"
+
+namespace Scumm {
+
+class ScummEngine_v100he;
+class AIEntity;
+class patternList;
+
+enum {
+ TERRAIN_TYPE_GOOD = 0,
+ TERRAIN_TYPE_SLOPE = 1,
+ TERRAIN_TYPE_WATER = 2,
+ MAX_MEMORY = 3
+};
+
+enum {
+ ITEM_BOMB = 0,
+ ITEM_CLUSTER = 1,
+ ITEM_REPAIR = 2,
+ ITEM_ANTIAIR = 3,
+ ITEM_BRIDGE = 4,
+ ITEM_TOWER = 5,
+ ITEM_GUIDED = 6,
+ ITEM_EMP = 7,
+ ITEM_SPIKE = 8,
+ ITEM_RECLAIMER = 9,
+ ITEM_BALLOON = 10,
+ ITEM_MINE = 11,
+ ITEM_CRAWLER = 12,
+ ITEM_VIRUS = 13,
+ ITEM_ENERGY = 14,
+ ITEM_SHIELD = 15,
+ ITEM_OFFENSE = 16,
+ ITEM_HUB = 17,
+ ITEM_TIME_EXPIRED = 18,
+ SKIP_TURN = -999
+};
+
+enum BuildingTypes {
+ BUILDING_ENERGY_COLLECTOR = 3,
+ BUILDING_MAIN_BASE = 4,
+ BUILDING_BRIDGE = 5,
+ BUILDING_TOWER = 6,
+ BUILDING_EXPLOSIVE_MINE = 7,
+ BUILDING_SHIELD = 8,
+ BUILDING_ANTI_AIR = 9,
+ BUILDING_OFFENSIVE_LAUNCHER = 10,
+ BUILDING_BALLOON = 11,
+ BUILDING_CRAWLER = 12
+};
+
+enum {
+ ENERGY_POOL_X = 45,
+ ENERGY_POOL_Y = 46,
+ ENERGY_POOL_UNITS_ON = 47,
+
+ MIN_DIST = 108
+};
+
+class AI {
+public:
+ AI(ScummEngine_v100he *vm);
+
+ void resetAI();
+ void cleanUpAI();
+ void setAIType(const int paramCount, const int32 *params);
+ int masterControlProgram(const int paramCount, const int32 *params);
+
+private:
+ int chooseBehavior();
+ int chooseTarget(int behavior);
+
+ Tree *initApproachTarget(int targetX, int targetY, Node **retNode);
+ int *approachTarget(Tree *myTree, int &x, int &y, Node **currentNode);
+ Tree *initAcquireTarget(int targetX, int targetY, Node **retNode);
+ int *acquireTarget(int targetX, int targetY);
+ int *acquireTarget(int targetX, int targetY, Tree *myTree, int &errorCode);
+ int *offendTarget(int &targetX, int &targetY, int index);
+ int *defendTarget(int &targetX, int &targetY, int index);
+ int *energizeTarget(int &targetX, int &targetY, int index);
+
+public:
+ int getClosestUnit(int x, int y, int radius, int player, int alignment, int unitType, int checkUnitEnabled);
+ int getClosestUnit(int x, int y, int radius, int player, int alignment, int unitType, int checkUnitEnabled, int minDist);
+
+ int getDistance(int originX, int originY, int endX, int endY);
+ int calcAngle(int originX, int originY, int endX, int endY);
+ int calcAngle(int originX, int originY, int endX, int endY, int noWrapFlag);
+ int getTerrain(int x, int y);
+
+ int getHubX(int hub);
+ int getHubY(int hub);
+ int getMaxX();
+ int getMaxY();
+
+ int getCurrentPlayer();
+ int getMaxPower();
+ int getMinPower();
+ int getTerrainSquareSize();
+ int getBuildingOwner(int building);
+ int getBuildingState(int building);
+ int getBuildingType(int building);
+ int getBuildingArmor(int building);
+ int getBuildingMaxArmor(int building);
+ int getBuildingWorth(int building);
+ int getBuildingTeam(int building);
+
+ int getPlayerEnergy();
+ int getPlayerMaxTime();
+ int getTimerValue(int timerNum);
+ int getPlayerTeam(int player);
+
+ int getAnimSpeed();
+
+ int simulateBuildingLaunch(int x, int y, int power, int angle, int numSteps, int isEnergy);
+
+ int getPowerAngleFromPoint(int originX, int originY, int endX, int endY, int threshold, int olFlag);
+ int getPowerAngleFromPoint(int originX, int originY, int endX, int endY, int threshold);
+ int checkIfWaterState(int x, int y);
+ int getUnitsWithinRadius(int x, int y, int radius);
+
+ float degToRad(float degrees);
+
+ int getEnergyHogType();
+
+private:
+ int getEnergyPoolsArray();
+ int getCoordinateVisibility(int x, int y, int playerNum);
+ int getUnitVisibility(int unit, int playerNum);
+ int getEnergyPoolVisibility(int pool, int playerNum);
+ int getNumberOfPools();
+ int getNumberOfPlayers();
+ int getWindXSpeed();
+ int getWindYSpeed();
+ int getTotalWindSpeed();
+ int getWindXSpeedMax();
+ int getWindYSpeedMax();
+ int getBigXSize();
+ int getBigYSize();
+ int getEnergyPoolWidth(int pool);
+ int getLastAttacked(int &x, int &y);
+ int getFOW();
+ int getBuildingStackPtr();
+ int getTurnCounter();
+
+ int getGroundAltitude(int x, int y);
+ int checkForCordOverlap(int xStart, int yStart, int affectRadius, int simulateFlag);
+ int checkForAngleOverlap(int unit, int angle);
+ int estimateNextRoundEnergy(int player);
+ int checkForUnitOverlap(int x, int y, int radius, int ignoredUnit);
+ int checkForEnergySquare(int x, int y);
+ int aiChat();
+
+ int simulateWeaponLaunch(int x, int y, int power, int angle, int numSteps);
+ int fakeSimulateWeaponLaunch(int x, int y, int power, int angle);
+
+ int checkIfWaterSquare(int x, int y);
+
+ int getLandingPoint(int x, int y, int power, int angle);
+ int getEnemyUnitsVisible(int playerNum);
+
+ void limitLocation(int &a, int &b, int c, int d);
+ int energyPoolSize(int pool);
+ int getMaxCollectors(int pool);
+
+public:
+ Common::Array<int> _lastXCoord[5];
+ Common::Array<int> _lastYCoord[5];
+
+ ScummEngine_v100he *_vm;
+
+ AIEntity *_aiType[5];
+
+ int _aiState;
+ int _behavior;
+ int _energyHogType;
+
+ patternList *_moveList[5];
+
+ const int32 *_mcpParams;
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/he/moonbase/ai_node.cpp b/engines/scumm/he/moonbase/ai_node.cpp
new file mode 100644
index 0000000000..083a156a31
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_node.cpp
@@ -0,0 +1,153 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "scumm/he/moonbase/ai_node.h"
+
+namespace Scumm {
+
+IContainedObject::IContainedObject(IContainedObject &sourceContainedObject) {
+ _objID = sourceContainedObject.getObjID();
+ _valueG = sourceContainedObject.getG();
+}
+
+int Node::_nodeCount = 0;
+
+Node::Node() {
+ _parent = NULL;
+ _depth = 0;
+ _nodeCount++;
+ _contents = NULL;
+}
+
+Node::Node(Node *sourceNode) {
+ _parent = NULL;
+ _children = sourceNode->getChildren();
+
+ _depth = sourceNode->getDepth();
+
+ _contents = sourceNode->getContainedObject()->duplicate();
+}
+
+Node::~Node() {
+ if (_contents != NULL) {
+ delete _contents;
+ _contents = NULL;
+ }
+
+ _nodeCount--;
+}
+
+int Node::generateChildren() {
+ int numChildren = _contents->numChildrenToGen();
+
+ int numChildrenGenerated = numChildren;
+ int errorCode = -1;
+ static int i = 0;
+
+ while (i < numChildren) {
+ Node *tempNode = new Node;
+ _children.push_back(tempNode);
+ tempNode->setParent(this);
+ tempNode->setDepth(_depth + 1);
+
+ int completionFlag;
+
+ IContainedObject *thisContObj = _contents->createChildObj(i, completionFlag);
+ assert(!(thisContObj != NULL && completionFlag == 0));
+
+ if (!completionFlag) {
+ _children.pop_back();
+ delete tempNode;
+ return 0;
+ }
+
+ i++;
+
+ if (thisContObj != NULL) {
+ tempNode->setContainedObject(thisContObj);
+ } else {
+ _children.pop_back();
+ delete tempNode;
+ numChildrenGenerated--;
+ }
+ }
+
+ i = 0;
+
+ if (numChildrenGenerated > 0)
+ return numChildrenGenerated;
+
+ return errorCode;
+}
+
+
+int Node::generateNextChild() {
+ int numChildren = _contents->numChildrenToGen();
+
+ static int i = 0;
+
+ Node *tempNode = new Node;
+ _children.push_back(tempNode);
+ tempNode->setParent(this);
+ tempNode->setDepth(_depth + 1);
+
+ int compFlag;
+ IContainedObject *thisContObj = _contents->createChildObj(i, compFlag);
+
+ if (thisContObj != NULL) {
+ tempNode->setContainedObject(thisContObj);
+ } else {
+ _children.pop_back();
+ delete tempNode;
+ }
+
+ ++i;
+
+ if (i > numChildren)
+ i = 0;
+
+ return i;
+}
+
+Node *Node::popChild() {
+ Node *temp;
+
+ temp = _children.back();
+ _children.pop_back();
+ return temp;
+}
+
+Node *Node::getFirstStep() {
+ Node *currentNode = this;
+
+ if (currentNode->getParent() == NULL)
+ return currentNode;
+
+ while (currentNode->getParent()->getParent() != NULL)
+ currentNode = currentNode->getParent();
+
+ assert(currentNode->getDepth() == 1);
+
+ return currentNode;
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_node.h b/engines/scumm/he/moonbase/ai_node.h
new file mode 100644
index 0000000000..0c3ef2f023
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_node.h
@@ -0,0 +1,103 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SCUMM_HE_MOONBASE_AI_NODE_H
+#define SCUMM_HE_MOONBASE_AI_NODE_H
+
+#include "common/array.h"
+
+namespace Scumm {
+
+const float SUCCESS = -1;
+const float FAILURE = 1e20f;
+
+class IContainedObject {
+private:
+ int _objID;
+ float _valueG;
+
+protected:
+ virtual float getG() const { return _valueG; }
+ virtual float calcH() { return 0; }
+
+public:
+ IContainedObject() { _valueG = 0; _objID = -1; }
+ IContainedObject(float inG) { _valueG = inG; _objID = -1; }
+ IContainedObject(IContainedObject &sourceContainedObject);
+ virtual ~IContainedObject() {}
+
+ virtual IContainedObject *duplicate() = 0;
+
+ void setValueG(float inG) { _valueG = inG; }
+ float getValueG() { return _valueG; }
+
+ int getObjID() const { return _objID; }
+ void setObjID(int inputObjID) { _objID = inputObjID; }
+
+ virtual int numChildrenToGen() = 0;
+ virtual IContainedObject *createChildObj(int index, int &completionFlag) = 0;
+
+ virtual int checkSuccess() = 0;
+ virtual float calcT() { return getG(); }
+
+ float returnG() const { return getG(); }
+};
+
+class Node {
+private:
+ Node *_parent;
+ Common::Array<Node *> _children;
+
+ int _depth;
+ static int _nodeCount;
+
+ IContainedObject *_contents;
+
+public:
+ Node();
+ Node(Node *sourceNode);
+ ~Node();
+
+ void setParent(Node *parentPtr) { _parent = parentPtr; }
+ Node *getParent() const { return _parent; }
+
+ void setDepth(int depth) { _depth = depth; }
+ int getDepth() const { return _depth; }
+
+ static int getNodeCount() { return _nodeCount; }
+
+ void setContainedObject(IContainedObject *value) { _contents = value; }
+ IContainedObject *getContainedObject() { return _contents; }
+
+ Common::Array<Node *> getChildren() const { return _children; }
+ int generateChildren();
+ int generateNextChild();
+ Node *popChild();
+
+ float getObjectT() { return _contents->calcT(); }
+
+ Node *getFirstStep();
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/he/moonbase/ai_pattern.h b/engines/scumm/he/moonbase/ai_pattern.h
new file mode 100644
index 0000000000..ae1fa6b55e
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_pattern.h
@@ -0,0 +1,162 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SCUMM_HE_MOONBASE_AI_PATTERN_H
+#define SCUMM_HE_MOONBASE_AI_PATTERN_H
+
+namespace Scumm {
+
+const int NO_PATTERN = 0;
+const int PATTERN_FOUND = 1;
+
+class patternInstance {
+private:
+ int _sourceHub;
+ int _unit;
+ int _power;
+ int _angle;
+
+public:
+ patternInstance() {
+ _sourceHub = 0;
+ _unit = 0;
+ _power = 0;
+ _angle = 0;
+ }
+
+ patternInstance(int sh, int unit, int power, int angle) {
+ setSourceHub(sh);
+ setUnit(unit);
+ setPower(power);
+ setAngle(angle);
+ }
+
+ void setSourceHub(int sh) { _sourceHub = sh; }
+ void setUnit(int unit) { _unit = unit; }
+
+ void setPower(int power) {
+ if (power < 300)
+ _power = 1;
+ else if (power < 480)
+ _power = 2;
+ else
+ _power = 3;
+ }
+
+ void setAngle(int angle) {
+ int tempAngle = angle % 360;
+
+ if ((tempAngle >= 0) && (tempAngle < 90))
+ _angle = 1;
+
+ if ((tempAngle >= 90) && (tempAngle < 180))
+ _angle = 2;
+
+ if ((tempAngle >= 180) && (tempAngle < 270))
+ _angle = 3;
+
+ if ((tempAngle >= 270))
+ _angle = 4;
+ }
+
+ int getSourceHub() const { return _sourceHub; }
+ int getUnit() const { return _unit; }
+ int getPowerIndex() const { return _power; }
+ int getAngleIndex() const { return _angle; }
+
+ static int comparePatterns(patternInstance *p1, patternInstance *p2) {
+ if (p1->getSourceHub() != p2->getSourceHub())
+ return 0;
+
+ if (p1->getUnit() != p2->getUnit())
+ return 0;
+
+ if (p1->getUnit() == -999)
+ return 0;
+
+ int temp = abs(p1->getPowerIndex() - p2->getPowerIndex());
+
+ if (temp > 1)
+ return 0;
+
+ temp = abs(p1->getAngleIndex() - p2->getAngleIndex());
+
+ if (temp > 1 && temp < 3)
+ return 0;
+
+ return 1;
+ }
+};
+
+class patternList {
+private:
+ patternInstance *theList[10];
+ int listIndex;
+
+public:
+ patternList() {
+ for (int i = 0; i < 10; i++) {
+ theList[i] = new patternInstance();
+ }
+
+ listIndex = 0;
+ }
+ ~patternList() {
+ for (int i = 0; i < 10; i++) {
+ delete theList[i];
+ }
+ }
+
+ void addPattern(int sh, int unit, int power, int angle) {
+ theList[listIndex]->setSourceHub(sh);
+ theList[listIndex]->setUnit(unit);
+ theList[listIndex]->setPower(power);
+ theList[listIndex]->setAngle(angle);
+
+ listIndex++;
+
+ if (listIndex > 9)
+ listIndex = 0;
+ }
+
+ int evaluatePattern(int sh, int unit, int power, int angle) {
+ patternInstance *patternToMatch = new patternInstance(sh, unit, power, angle);
+ int matchCount = 0;
+
+ for (int i = 0; i < 9; i++) {
+ if (patternInstance::comparePatterns(theList[i], patternToMatch)) {
+ matchCount++;
+ }
+ }
+
+ delete patternToMatch;
+
+ if (matchCount > 2)
+ return PATTERN_FOUND;
+
+ return NO_PATTERN;
+ }
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/he/moonbase/ai_targetacquisition.cpp b/engines/scumm/he/moonbase/ai_targetacquisition.cpp
new file mode 100644
index 0000000000..02c49dc1a7
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_targetacquisition.cpp
@@ -0,0 +1,557 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/he/intern_he.h"
+#include "scumm/he/moonbase/moonbase.h"
+
+#include "scumm/he/moonbase/ai_targetacquisition.h"
+#include "scumm/he/moonbase/ai_main.h"
+#include "scumm/he/moonbase/ai_weapon.h"
+
+namespace Scumm {
+
+int Sortie::_sSourceX = 0;
+int Sortie::_sSourceY = 0;
+
+int Sortie::_sTargetX = 0;
+int Sortie::_sTargetY = 0;
+
+Sortie::~Sortie() {
+ for (Common::Array<DefenseUnit *>::iterator k = _enemyDefenses.begin(); k != _enemyDefenses.end(); k++) {
+ delete *k;
+ }
+}
+
+void Sortie::setEnemyDefenses(int enemyDefensesScummArray, int defendX, int defendY) {
+ DefenseUnit *thisUnit;
+ int currentPlayer = _ai->getCurrentPlayer();
+
+ for (int i = 0; i < 200; i++) {
+ int thisElement = _ai->_vm->_moonbase->readFromArray(enemyDefensesScummArray, 0, i);
+
+ if (thisElement) {
+ if (_ai->getBuildingOwner(thisElement)) {
+ if (_ai->getPlayerTeam(currentPlayer) != _ai->getBuildingTeam(thisElement)) {
+ int type = _ai->getBuildingType(thisElement);
+
+ switch (type) {
+ case BUILDING_ANTI_AIR:
+ thisUnit = new AntiAirUnit(_ai);
+ break;
+
+ case BUILDING_SHIELD:
+ thisUnit = new ShieldUnit(_ai);
+ break;
+
+ case BUILDING_EXPLOSIVE_MINE:
+ if (_ai->getDistance(_ai->getHubX(thisElement), _ai->getHubY(thisElement), defendX, defendY) < 90)
+ thisUnit = new MineUnit(_ai);
+ else
+ thisUnit = NULL;
+
+ break;
+
+ case BUILDING_CRAWLER:
+ thisUnit = NULL;
+ break;
+
+ default:
+ thisUnit = NULL;
+ break;
+ }
+
+ if (thisUnit != NULL) {
+ thisUnit->setID(thisElement);
+ thisUnit->setPos(_ai->getHubX(thisElement), _ai->getHubY(thisElement));
+
+ if (_ai->getBuildingState(thisElement)) thisUnit->setState(DUS_OFF);
+
+ _enemyDefenses.push_back(thisUnit);
+ }
+ }
+ }
+ } else {
+ i = 200;
+ }
+ }
+}
+
+int *Sortie::getShotPos() const {
+ int *retVal = new int[2];
+
+ retVal[0] = _shotPosX;
+ retVal[1] = _shotPosY;
+
+ return retVal;
+}
+
+int Sortie::numChildrenToGen() {
+ int retVal = MAX<uint>(_enemyDefenses.size(), 1) * NUM_SHOT_POSITIONS * NUM_WEAPONS;
+ return retVal;
+}
+
+IContainedObject *Sortie::createChildObj(int index, int &completionFlag) {
+ float thisDamage;
+ Sortie *retSortie = new Sortie(_ai);
+ int activeDefenses = 0;
+
+ Common::Array<DefenseUnit *> thisEnemyDefenses;
+
+ // Copy the defensive unit list from the parent
+ for (Common::Array<DefenseUnit *>::iterator k = _enemyDefenses.begin(); k != _enemyDefenses.end(); k++) {
+ DefenseUnit *temp;
+
+ switch ((*k)->getType()) {
+ case DUT_ANTI_AIR:
+ temp = new AntiAirUnit(*k, _ai);
+ break;
+
+ case DUT_SHIELD:
+ temp = new ShieldUnit(*k, _ai);
+ break;
+
+ case DUT_MINE:
+ temp = new MineUnit(*k, _ai);
+ break;
+
+ case DUT_CRAWLER:
+ temp = new CrawlerUnit(*k, _ai);
+ break;
+
+ default:
+ temp = new ShieldUnit(*k, _ai);
+ break;
+ }
+
+ thisEnemyDefenses.push_back(temp);
+ }
+
+ // Calculate the current target from the index
+ DefenseUnit *currentTarget = *(thisEnemyDefenses.begin() + static_cast<int>(index / (NUM_WEAPONS * NUM_SHOT_POSITIONS)));
+
+ assert(currentTarget);
+
+ // Pick correct weapon according to index
+ Weapon *currentWeapon = new Weapon(currentTarget->selectWeapon(index % NUM_WEAPONS));
+ retSortie->setUnitType(currentWeapon->getTypeID());
+
+ // Calculate distance from target to source hub
+ int distance = _ai->getDistance(currentTarget->getPosX(), currentTarget->getPosY(), getSourcePosX(), getSourcePosY());
+
+ // Pick correct shot position according to index
+ Common::Point *targetCoords;
+ targetCoords = currentTarget->createTargetPos((static_cast<int>(index / NUM_WEAPONS) % NUM_SHOT_POSITIONS), distance, currentWeapon->getTypeID(), getSourcePosX(), getSourcePosY());
+ retSortie->setShotPos(targetCoords->x, targetCoords->y);
+
+ // Set the g value based on cost of the weapon
+ retSortie->setValueG(getG() + currentWeapon->getCost());
+
+ int AAcounter = 3;
+
+ // Loop through defensive units, toggling anti-air units and deciding if this weapon will land safely
+ for (Common::Array<DefenseUnit *>::iterator i = thisEnemyDefenses.begin(); i != thisEnemyDefenses.end(); i++) {
+ distance = _ai->getDistance((*i)->getPosX(), (*i)->getPosY(), targetCoords->x, targetCoords->y);
+
+ // Check to see if we're within an active defense's radius
+ if ((distance < (*i)->getRadius()) && ((*i)->getState() == DUS_ON)) {
+ activeDefenses++;
+
+ // Turn off this anti-air and drop the coverage count
+ if (((*i)->getType() == DUT_ANTI_AIR)) {
+ (*i)->setState(DUS_OFF);
+
+ if (currentWeapon->getTypeID() == ITEM_CLUSTER)
+ AAcounter--;
+ else
+ AAcounter = 0;
+ }
+
+ // Essentially disable this weapon choice, due to its impact with a shield, or untriggered anti-air
+ if (((*i)->getType() == DUT_SHIELD) || !AAcounter) {
+ retSortie->setValueG(1000);
+ i = thisEnemyDefenses.end() - 1;
+ }
+ } else {
+ // Turn on any anti-airs that were off the previous turn
+ if (((*i)->getType() == DUT_ANTI_AIR) && ((*i)->getState() == DUS_OFF))
+ (*i)->setState(DUS_ON);
+ }
+ }
+
+ // Turn on all the non-anti-air units in preparation for emp's and the next turn
+ for (Common::Array<DefenseUnit *>::iterator i = thisEnemyDefenses.begin(); i != thisEnemyDefenses.end(); i++) {
+ if ((*i)->getType() != DUT_ANTI_AIR) {
+ (*i)->setState(DUS_ON);
+ }
+ }
+
+ // If this weapon is still valid
+ if (retSortie->getValueG() < 1000) {
+ // Apply emp effects and damage to all units in range of weapon
+ for (Common::Array<DefenseUnit *>::iterator i = thisEnemyDefenses.begin(); i != thisEnemyDefenses.end(); ) {
+ // Special simulated crawler detonation location used, since it walks a bit
+ if (currentWeapon->getTypeID() == ITEM_CRAWLER)
+ distance = _ai->getDistance((*i)->getPosX(), (*i)->getPosY(), currentTarget->getPosX(), currentTarget->getPosY());
+ // Normal detonation location used here
+ else {
+ distance = _ai->getDistance((*i)->getPosX(), (*i)->getPosY(), targetCoords->x, targetCoords->y);
+ }
+
+ if (distance < currentWeapon->getRadius()) {
+ // Apply damage
+ thisDamage = currentWeapon->getDamage();
+
+ if ((AAcounter != 3) && (currentWeapon->getTypeID() == ITEM_CLUSTER))
+ thisDamage = 0;
+
+ if (!_ai->_vm->_rnd.getRandomNumber(4))
+ currentWeapon->setTypeID(ITEM_MINE);
+
+ (*i)->setDamage((int)thisDamage);
+
+ // Apply emp effect
+ if (currentWeapon->getTypeID() == ITEM_EMP) {
+ (*i)->setState(DUS_OFF);
+ }
+
+ // Remove destroyed defenses
+ if ((*i)->getArmor() <= 0) {
+ delete *i;
+ i = thisEnemyDefenses.erase(i);
+ } else {
+ i++;
+ }
+ } else {
+ i++;
+ }
+ }
+ }
+
+ retSortie->setEnemyDefenses(thisEnemyDefenses);
+
+ delete targetCoords;
+ delete currentWeapon;
+ return retSortie;
+}
+
+float Sortie::calcH() {
+ float retValue = 0;
+ Common::Array<DefenseUnit *> thisEnemyDefenses = getEnemyDefenses();
+
+ for (Common::Array<DefenseUnit *>::iterator i = thisEnemyDefenses.begin(); i != thisEnemyDefenses.end(); i++) {
+ if ((*i)->getState() == DUS_ON) {
+ switch ((*i)->getType()) {
+ case DUT_ANTI_AIR:
+ retValue += 1;
+
+ case DUT_MINE:
+ retValue += 1;
+ break;
+
+ case DUT_SHIELD:
+ retValue += 1;
+ break;
+ }
+ }
+ }
+
+ return retValue;
+}
+
+int Sortie::checkSuccess() {
+ if (!_enemyDefenses.size())
+ return SUCCESS;
+
+ int targetX = getTargetPosX();
+ int targetY = getTargetPosY();
+
+ int targetCheck = 0;
+
+ for (Common::Array<DefenseUnit *>::iterator i = _enemyDefenses.begin(); i != _enemyDefenses.end(); i++) {
+ if (((*i)->getState() == DUS_ON) && ((*i)->getType() != DUT_HUB)) {
+ return 0;
+ }
+
+ if (((*i)->getPosX() == targetX) && ((*i)->getPosY() == targetY)) targetCheck = 1;
+ }
+
+ if (!targetCheck)
+ return SUCCESS;
+
+ // If shot pos == target pos return SUCCESS;
+ if ((targetX == getShotPosX()) && (getTargetPosY() == getShotPosY())) {
+ return SUCCESS;
+ }
+
+ return 0;
+}
+
+float Sortie::calcT() {
+ return (checkSuccess() != SUCCESS) ? (getG() + calcH()) : SUCCESS;
+}
+
+IContainedObject *Sortie::duplicate() {
+ return this;
+}
+
+
+void Sortie::printEnemyDefenses() {
+ for (Common::Array<DefenseUnit *>::iterator i = _enemyDefenses.begin(); i != _enemyDefenses.end(); i++) {
+ warning("Unit %d - Type: %d, Armor: %d, Status: %d", (*i)->getID(), (*i)->getType(), static_cast<int>((*i)->getArmor()), (*i)->getState());
+ }
+}
+
+int Defender::calculateDefenseUnitPosition(int targetX, int targetY, int index) {
+ int currentPlayer = _ai->getCurrentPlayer();
+
+ //get list of near hubs
+ int unitsArray = _ai->getUnitsWithinRadius(targetX + 5, targetY, 480);
+
+ const int NUM_HUBS = 10;
+ //Order on dist
+ int hubArray[NUM_HUBS] = { 0 };
+ int hubIndex = 0;
+
+ for (int i = 0; i < 200; i++) {
+ int thisUnit = _ai->_vm->_moonbase->readFromArray(unitsArray, 0, i);
+
+ if (thisUnit) {
+ if (((_ai->getBuildingType(thisUnit) == BUILDING_MAIN_BASE) || (_ai->getBuildingType(thisUnit) == BUILDING_OFFENSIVE_LAUNCHER)) && (_ai->getBuildingOwner(thisUnit) == currentPlayer)) {
+ for (int j = 0; j < NUM_HUBS; j++) {
+ if (hubArray[j]) {
+ int distCurrent = _ai->getDistance(targetX, targetY, _ai->getHubX(thisUnit), _ai->getHubY(thisUnit));
+ int distSaved = _ai->getDistance(targetX, targetY, _ai->getHubX(hubArray[j]), _ai->getHubY(hubArray[j]));
+
+ if (distCurrent < distSaved) {
+ hubArray[hubIndex] = hubArray[j];
+ hubArray[j] = thisUnit;
+ hubIndex++;
+ j = 100;
+ }
+ } else {
+ hubArray[j] = thisUnit;
+ hubIndex++;
+ j = 100;
+ }
+ }
+ }
+ }
+
+ if (hubIndex >= NUM_HUBS) {
+ hubIndex = NUM_HUBS;
+ i = 200;
+ }
+ }
+
+ _ai->_vm->_moonbase->deallocateArray(unitsArray);
+
+ //Check if repair is needed
+ int targetUnit = _ai->getClosestUnit(targetX + 5, targetY, 15, currentPlayer, 1, 0, 0, 0);
+
+ if (targetUnit && (targetUnit != BUILDING_CRAWLER) && (_ai->getBuildingTeam(targetUnit) == _ai->getPlayerTeam(currentPlayer))) {
+ int armor = _ai->getBuildingArmor(targetUnit);
+
+ if (armor < _ai->getBuildingMaxArmor(targetUnit)) {
+ unitsArray = _ai->getUnitsWithinRadius(targetX + 5, targetY, 170);
+ int defCount = 0;
+
+ for (int i = 0; i < 200; i++) {
+ int thisUnit = _ai->_vm->_moonbase->readFromArray(unitsArray, 0, i);
+
+ if (thisUnit) {
+ if (((_ai->getBuildingType(thisUnit) == BUILDING_SHIELD) || (_ai->getBuildingType(thisUnit) == BUILDING_ANTI_AIR)) && (_ai->getBuildingOwner(thisUnit) == currentPlayer) && (_ai->getBuildingState(thisUnit) == 0)) {
+ defCount++;
+ i = 200;
+ }
+ }
+ }
+
+ _ai->_vm->_moonbase->deallocateArray(unitsArray);
+
+ if (defCount) {
+ //repair
+ int hubUnit = _ai->getClosestUnit(targetX, targetY, 480, currentPlayer, 1, BUILDING_MAIN_BASE, 1, 110);
+
+ if (hubUnit && (hubUnit != targetUnit)) {
+ int powAngle = abs(_ai->getPowerAngleFromPoint(_ai->getHubX(hubUnit), _ai->getHubY(hubUnit), targetX, targetY, 20));
+ int power = powAngle / 360;
+ int angle = powAngle - (power * 360);
+
+ setTargetX(targetX);
+ setTargetY(targetY);
+
+ setSourceUnit(hubUnit);
+ setUnit(ITEM_REPAIR);
+ setPower(power);
+ setAngle(angle);
+
+ return 1;
+ }
+ }
+ }
+ }
+
+ //For each hub
+ for (int i = 0; i < MIN(NUM_HUBS, hubIndex); i++) {
+ int hubX = _ai->getHubX(hubArray[i]);
+ int hubY = _ai->getHubY(hubArray[i]);
+ //get angle to hub
+ int directAngleToHub = 0;
+
+ //If this hub is the target
+ if ((hubX == targetX) && (hubY == targetY)) {
+ //make the angle seed point at the closest enemy
+ int enemyUnit = _ai->getClosestUnit(hubX, hubY, _ai->getMaxX(), currentPlayer, 0, 0, 0);
+ directAngleToHub = _ai->calcAngle(targetX, targetY, _ai->getHubX(enemyUnit), _ai->getHubY(enemyUnit));
+ } else {
+ directAngleToHub = _ai->calcAngle(targetX, targetY, hubX, hubY);
+ }
+
+ //Number of random chances to land
+ for (int j = 0; j < 3; j++) {
+ //Pick random angle and dist within semicircle (-90 to +90) and (40 to 150)
+ int randAngle = directAngleToHub + _ai->_vm->_rnd.getRandomNumber(179) - 90;
+ int randDist = _ai->_vm->_rnd.getRandomNumber(109) + 40;
+
+ int x = (int)(targetX + randDist * cos(_ai->degToRad(randAngle)));
+ int y = (int)(targetY + randDist * sin(_ai->degToRad(randAngle)));
+
+ int powAngle = _ai->getPowerAngleFromPoint(hubX, hubY, x, y, 20);
+
+ if (powAngle < 0)
+ continue;
+
+ int power = powAngle / 360;
+ int angle = powAngle - (power * 360);
+
+ int coords = 0;
+ coords = _ai->simulateBuildingLaunch(hubX, hubY, power, angle, 100, 0);
+
+ //if valid, return
+ if (coords > 0) {
+ //warning("The prospective launching hub for this defensive unit is: %d", hubArray[i]);
+
+ setSourceX(hubX);
+ setSourceY(hubY);
+ setTargetX((x + _ai->getMaxX()) % _ai->getMaxX());
+ setTargetY((y + _ai->getMaxY()) % _ai->getMaxY());
+ setSourceUnit(hubArray[i]);
+
+ int unitsArray2 = _ai->getUnitsWithinRadius(targetX + 5, targetY, 200);
+ int shieldCount = 0;
+
+ for (int k = 0; k < 200; k++) {
+ int thisUnit = _ai->_vm->_moonbase->readFromArray(unitsArray2, 0, k);
+
+ if (thisUnit) {
+ if ((_ai->getBuildingType(thisUnit) == BUILDING_SHIELD) && (_ai->getBuildingOwner(thisUnit) == currentPlayer))
+ shieldCount++;
+
+ if ((_ai->getBuildingType(thisUnit) == BUILDING_BRIDGE) && (_ai->getBuildingOwner(thisUnit) == currentPlayer)) {
+ shieldCount--;
+ shieldCount = MAX(-1, shieldCount);
+ }
+ }
+ }
+
+ if ((_ai->_vm->_rnd.getRandomNumber((int)pow(3.0f, shieldCount + 1) - 1) == 0) && (_ai->getPlayerEnergy() > 6))
+ setUnit(ITEM_SHIELD);
+ else
+ setUnit(ITEM_ANTIAIR);
+
+ setPower(power);
+ setAngle(angle);
+
+ _ai->_vm->_moonbase->deallocateArray(unitsArray2);
+ return 1;
+ }
+
+ if (coords < 0) {
+ //drop a bridge for the cord
+ int yCoord = -coords / _ai->getMaxX();
+ int xCoord = -coords - (yCoord * _ai->getMaxX());
+
+ if (_ai->checkIfWaterState(xCoord, yCoord)) {
+ int terrainSquareSize = _ai->getTerrainSquareSize();
+ xCoord = ((xCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
+ yCoord = ((yCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
+
+ int xDist = xCoord - x;
+ int yDist = yCoord - y;
+ x = (int)(xCoord + (terrainSquareSize * 1.414 * (xDist / (abs(xDist) + 1))));
+ y = (int)(yCoord + (terrainSquareSize * 1.414 * (yDist / (abs(yDist) + 1))));
+
+ setTargetX(x);
+ setTargetY(y);
+
+ int nextUnit = _ai->getClosestUnit(x, y, 480, _ai->getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 120);
+ powAngle = _ai->getPowerAngleFromPoint(_ai->getHubX(nextUnit), _ai->getHubY(nextUnit), x, y, 15);
+
+ powAngle = abs(powAngle);
+ power = powAngle / 360;
+ angle = powAngle - (power * 360);
+
+ setSourceUnit(nextUnit);
+ setUnit(ITEM_BRIDGE);
+ setPower(power);
+ setAngle(angle);
+
+ return 1;
+ }
+ }
+ }
+ }
+
+ // Else create new hub
+ int count = 0;
+ int coords = 0;
+
+ if (hubIndex == 0) return -3;
+
+ do {
+ int sourceHub = hubArray[_ai->_vm->_rnd.getRandomNumber(hubIndex - 1)];
+
+ setSourceX(_ai->getHubX(sourceHub));
+ setSourceY(_ai->getHubY(sourceHub));
+ setSourceUnit(sourceHub);
+ setUnit(ITEM_HUB);
+ setPower(_ai->_vm->_rnd.getRandomNumber(299) + 200);
+ setAngle(_ai->_vm->_rnd.getRandomNumber(359));
+ count++;
+
+ if (count > (NUM_HUBS * 3)) break;
+
+ coords = _ai->simulateBuildingLaunch(getSourceX(), getSourceY(), getPower(), getAngle(), 100, 0);
+ } while (coords <= 0);
+
+ if (coords > 0) {
+ setTargetX(coords % _ai->getMaxX());
+ setTargetY(coords / _ai->getMaxX());
+ } else {
+ setTargetX(0);
+ setTargetY(0);
+ }
+
+ return -1;
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_targetacquisition.h b/engines/scumm/he/moonbase/ai_targetacquisition.h
new file mode 100644
index 0000000000..9afe0f50ab
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_targetacquisition.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.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_HE_MOONBASE_AI_TARGETACQUISITION_H
+#define SCUMM_HE_MOONBASE_AI_TARGETACQUISITION_H
+
+#include "scumm/he/moonbase/ai_defenseunit.h"
+#include "scumm/he/moonbase/ai_node.h"
+#include "scumm/he/moonbase/ai_tree.h"
+
+namespace Scumm {
+
+const int NUM_IMPT_UNITS = 3;
+const int NUM_SHOT_POSITIONS = 1;
+const int NUM_WEAPONS = 3;
+
+class Sortie : public IContainedObject {
+private:
+ static int _sSourceX;
+ static int _sSourceY;
+
+ static int _sTargetX;
+ static int _sTargetY;
+
+ int _unitType;
+ int _shotPosX, _shotPosY;
+ Common::Array<DefenseUnit *> _enemyDefenses;
+ AI *_ai;
+
+public:
+ Sortie(AI *ai) { _ai = ai; _unitType = 0; _shotPosX = _shotPosY = 0; }
+ virtual ~Sortie();
+
+ static void setSourcePos(int x, int y) {
+ _sSourceX = x;
+ _sSourceY = y;
+ }
+ static void setTargetPos(int x, int y) {
+ _sTargetX = x;
+ _sTargetY = y;
+ }
+
+ void setUnitType(int unitType) { _unitType = unitType; }
+
+ void setShotPosX(int shotPosX) { _shotPosX = shotPosX; }
+ void setShotPosY(int shotPosY) { _shotPosY = shotPosY; }
+ void setShotPos(int shotPosX, int shotPosY) {
+ _shotPosX = shotPosX;
+ _shotPosY = shotPosY;
+ }
+
+ void setEnemyDefenses(Common::Array<DefenseUnit *> enemyDefenses) {
+ _enemyDefenses = enemyDefenses;
+ }
+ void setEnemyDefenses(int enemyDefensesScummArray, int defendX, int defendY);
+
+ void printEnemyDefenses();
+
+ static int getSourcePosX() { return _sSourceX; }
+ static int getSourcePosY() { return _sSourceY; }
+ static int getTargetPosX() { return _sTargetX; }
+ static int getTargetPosY() { return _sTargetY; }
+
+ int getUnitType() const { return _unitType; }
+
+ int getShotPosX() const { return _shotPosX; }
+ int getShotPosY() const { return _shotPosY; }
+ int *getShotPos() const;
+
+ Common::Array<DefenseUnit *> getEnemyDefenses() const { return _enemyDefenses; }
+
+ virtual IContainedObject *duplicate();
+
+ virtual int numChildrenToGen();
+ virtual IContainedObject *createChildObj(int, int &completionFlag);
+
+
+ virtual float calcH();
+ virtual int checkSuccess();
+ virtual float calcT();
+};
+
+class Defender {
+private:
+ int _sourceX;
+ int _sourceY;
+ int _targetX;
+ int _targetY;
+ int _sourceUnit;
+ int _power;
+ int _angle;
+ int _unit;
+ AI *_ai;
+
+public:
+ Defender(AI *ai) : _ai(ai) {}
+ void setSourceX(int sourceX) { _sourceX = sourceX; }
+ void setSourceY(int sourceY) { _sourceY = sourceY; }
+ void setTargetX(int targetX) { _targetX = targetX; }
+ void setTargetY(int targetY) { _targetY = targetY; }
+ void setSourceUnit(int sourceUnit) { _sourceUnit = sourceUnit; }
+ void setPower(int power) { _power = power; }
+ void setAngle(int angle) { _angle = angle; }
+ void setUnit(int unit) { _unit = unit; }
+
+ int getSourceX() const { return _sourceX; }
+ int getSourceY() const { return _sourceY; }
+ int getTargetX() const { return _targetX; }
+ int getTargetY() const { return _targetY; }
+ int getSourceUnit() const { return _sourceUnit; }
+ int getPower() const { return _power; }
+ int getAngle() const { return _angle; }
+ int getUnit() const { return _unit; }
+
+ int calculateDefenseUnitPosition(int targetX, int targetY, int index);
+};
+
+class defenseUnitCompare {
+public:
+ bool operator()(DefenseUnit *x, DefenseUnit *y) {
+ //disabled units go at the end
+ if (x->getState() == DUS_OFF) {
+ warning("OFF");
+ return 0;
+ }
+
+ return x->getDistanceTo() < y->getDistanceTo();
+ }
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/he/moonbase/ai_traveller.cpp b/engines/scumm/he/moonbase/ai_traveller.cpp
new file mode 100644
index 0000000000..b1c9985b9d
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_traveller.cpp
@@ -0,0 +1,277 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "scumm/he/intern_he.h"
+#include "scumm/he/moonbase/moonbase.h"
+#include "scumm/he/moonbase/ai_traveller.h"
+#include "scumm/he/moonbase/ai_main.h"
+
+namespace Scumm {
+
+int Traveller::_targetPosX = 0;
+int Traveller::_targetPosY = 0;
+int Traveller::_maxDist = 0;
+
+int Traveller::_numToGen = 0;
+int Traveller::_sizeAngleStep = 0;
+
+Traveller::Traveller(AI *ai) : _ai(ai) {
+ _waterFlag = 0;
+ setValueG(0);
+ unsetDisabled();
+
+ _sourceHub = 0;
+ _angleTo = 0;
+ _powerTo = 0;
+ _waterSourceX = 0;
+ _waterSourceY = 0;
+ _waterDestX = 0;
+ _waterDestY = 0;
+}
+
+Traveller::Traveller(int originX, int originY, AI *ai) : _ai(ai) {
+ _waterFlag = 0;
+ setValueG(0);
+ unsetDisabled();
+
+ _posX = originX;
+ _posY = originY;
+
+ _sourceHub = 0;
+ _angleTo = 0;
+ _powerTo = 0;
+ _waterSourceX = 0;
+ _waterSourceY = 0;
+ _waterDestX = 0;
+ _waterDestY = 0;
+}
+
+void Traveller::adjustPosX(int offsetX) {
+ int maxX = _ai->getMaxX();
+ int deltaX = _posX + offsetX;
+
+ if (deltaX < 0) _posX = maxX + deltaX;
+ else if (deltaX > maxX) _posX = deltaX - maxX;
+ else _posX = deltaX;
+}
+
+void Traveller::adjustPosY(int offsetY) {
+ int maxY = _ai->getMaxX();
+ int deltaY = _posY + offsetY;
+
+ if (deltaY < 0) _posY = maxY + deltaY;
+ else if (deltaY > maxY) _posY = deltaY - maxY;
+ else _posY = deltaY;
+}
+
+void Traveller::adjustXY(int offsetX, int offsetY) {
+ adjustPosX(offsetX);
+ adjustPosY(offsetY);
+}
+
+float Traveller::calcH() {
+ float retVal = 0;
+ // Calc dist from here to target
+ retVal = _ai->getDistance(_posX, _posY, _targetPosX, _targetPosY);
+ // Divide by _maxDist to get minimum number of jumps to goal
+ retVal /= static_cast<float>(_maxDist);
+
+ return retVal * 2.0;
+}
+
+int Traveller::numChildrenToGen() {
+ if (!_numToGen)
+ _numToGen = _ai->getAnimSpeed() + 2;
+
+ return _numToGen;
+}
+
+IContainedObject *Traveller::createChildObj(int index, int &completionFlag) {
+ static int nodeCount = 0;
+ static int completionState = 1;
+
+ if (!index) nodeCount = 0;
+
+ nodeCount++;
+
+ Traveller *retTraveller = new Traveller(_ai);
+
+ static int dir, angle, power;
+
+ if (completionState) {
+ // Calculate angle between here and target
+ int directAngle = 0;
+
+ if (_ai->getEnergyHogType())
+ directAngle = _ai->calcAngle(_posX, _posY, _targetPosX, _targetPosY, 1);
+ else
+ directAngle = _ai->calcAngle(_posX, _posY, _targetPosX, _targetPosY);
+
+ // Calculate the offset angle for this index
+ if (!_sizeAngleStep)
+ _sizeAngleStep = 52 - (_ai->getAnimSpeed() * 7);
+
+ dir = _sizeAngleStep * ((static_cast<int>(index / NUM_POWER_STEPS) + 1) >> 1);
+ // Calculate the sign value for the offset for this index
+ int orientation = dir * (((static_cast<int>(index / NUM_POWER_STEPS) % 2) << 1) - 1);
+ // Add the offset angle to the direct angle to target
+ angle = orientation + directAngle;
+
+ // Calculate power for this index
+ int maxPower = 0;
+ int directDist = _ai->getDistance(_posX, _posY, _targetPosX, _targetPosY);
+
+ if (directDist > _maxDist + 120)
+ maxPower = _ai->getMaxPower();
+ else
+ maxPower = (int)((static_cast<float>(directDist) / static_cast<float>(_maxDist + 120)) * _ai->getMaxPower());
+
+ maxPower -= 70;
+ power = (int)(maxPower * (1 - ((index % NUM_POWER_STEPS) * SIZE_POWER_STEP)));
+ }
+
+ retTraveller->setAngleTo(angle);
+ retTraveller->setPowerTo(power);
+
+ // Set this object's position to the new one determined by the power and angle from above
+ static int lastSuccessful = 0;
+ int coords = 0;
+
+ if (!(index % NUM_POWER_STEPS) || (!lastSuccessful)) {
+ coords = _ai->simulateBuildingLaunch(_posX, _posY, power, angle, 10, 0);
+ lastSuccessful = 0;
+ } else {
+ completionState = 1;
+ lastSuccessful = 0;
+ }
+
+ if (!coords) {
+ completionFlag = 0;
+ completionState = 0;
+ delete retTraveller;
+ return NULL;
+ } else {
+ completionFlag = 1;
+ completionState = 1;
+ }
+
+ int whoseTurn = _ai->getCurrentPlayer();
+ int maxX = _ai->getMaxX();
+
+ // Check new position to see if landing is clear
+ if (coords > 0) {
+ int yCoord = coords / maxX;
+ int xCoord = coords - (yCoord * maxX);
+
+ int terrain = _ai->getTerrain(xCoord, yCoord);
+ assert(terrain == TERRAIN_TYPE_GOOD);
+
+ float pwr = _ai->getMinPower() * .3;
+ float cosine = cos((static_cast<float>(angle) / 360) * (2 * M_PI));
+ float sine = sin((static_cast<float>(angle) / 360) * (2 * M_PI));
+ int xParam = (int)(xCoord + (pwr * cosine));
+ int yParam = (int)(yCoord + (pwr * sine));
+
+ if (xParam < 0)
+ xParam += _ai->getMaxX();
+ else if (xParam > _ai->getMaxX())
+ xParam -= _ai->getMaxX();
+
+ if (yParam < 0)
+ yParam += _ai->getMaxY();
+ else if (yParam > _ai->getMaxY())
+ yParam -= _ai->getMaxY();
+
+ if (_ai->checkIfWaterState(xParam, yParam)) {
+ delete retTraveller;
+ return NULL;
+ }
+
+ retTraveller->setPosY(yCoord);
+ retTraveller->setPosX(xCoord);
+
+ // Iterate through the previous action list, making sure this one isn't on it
+ for (Common::Array<int>::iterator i = (_ai->_lastXCoord[whoseTurn]).begin(), j = (_ai->_lastYCoord[whoseTurn]).begin(); i != (_ai->_lastXCoord[whoseTurn]).end(); i++, j++) {
+ // Check if this shot is the same as the last time we tried
+ if ((*i == retTraveller->getPosX()) && (*j == retTraveller->getPosY())) {
+ retTraveller->setDisabled();
+ delete retTraveller;
+ return NULL;
+ }
+ }
+
+ retTraveller->setValueG(getG() + 7 + (dir * DIRECTION_WEIGHT));
+ lastSuccessful = 1;
+ } else {
+ int yCoord = -coords / maxX;
+ int xCoord = -coords - (yCoord * maxX);
+
+ // If landing fault is because of water, add 1 extra to g and turn on water flag. Also set coords, and adjust power to water fault location
+ if (_ai->checkIfWaterState(xCoord, yCoord)) {
+ int terrainSquareSize = _ai->getTerrainSquareSize();
+ xCoord = ((xCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
+ yCoord = ((yCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
+
+ int xDist = xCoord - _posX;
+ int yDist = yCoord - _posY;
+ retTraveller->setPosX((int)(xCoord + (terrainSquareSize * 1.414 * (xDist / (abs(xDist) + 1)))));
+ retTraveller->setPosY((int)(yCoord + (terrainSquareSize * 1.414 * (yDist / (abs(yDist) + 1)))));
+
+ int closestHub = _ai->getClosestUnit(retTraveller->getPosX(), retTraveller->getPosY(), _ai->getMaxX(), _ai->getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 110);
+
+ retTraveller->setWaterSourceX(_ai->getHubX(closestHub));
+ retTraveller->setWaterSourceY(_ai->getHubY(closestHub));
+ retTraveller->setWaterDestX(retTraveller->getPosX());
+ retTraveller->setWaterDestY(retTraveller->getPosY());
+
+ retTraveller->setPowerTo(power);
+ retTraveller->setAngleTo(angle);
+
+ retTraveller->setValueG(getG() + 10 + (dir * DIRECTION_WEIGHT));
+ retTraveller->enableWaterFlag();
+ } else {
+ // If not, set G to highest value
+ retTraveller->setDisabled();
+ delete retTraveller;
+ return NULL;
+ }
+ }
+
+ return retTraveller;
+}
+
+int Traveller::checkSuccess() {
+ if (_ai->getDistance(_posX + 1, _posY, _targetPosX, _targetPosY) < _maxDist)
+ return SUCCESS;
+
+ return 0;
+}
+
+float Traveller::calcT() {
+ assert(!_disabled);
+
+ if (_disabled) return FAILURE;
+
+ return (checkSuccess() != SUCCESS) ? (getG() + calcH()) : SUCCESS;
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_traveller.h b/engines/scumm/he/moonbase/ai_traveller.h
new file mode 100644
index 0000000000..20e69eb76c
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_traveller.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.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_HE_MOONBASE_AI_TRAVELER_H
+#define SCUMM_HE_MOONBASE_AI_TRAVELER_H
+
+#include "scumm/he/moonbase/ai_node.h"
+
+namespace Scumm {
+
+const int NUM_TO_GEN = 9;
+
+const int NUM_POWER_STEPS = 3;
+const double SIZE_POWER_STEP = .15;
+const int SIZE_ANGLE_STEP = 45;
+const int VARIATION_EXTENT = 3;
+const int DIRECTION_WEIGHT = 5;
+
+class Traveller : public IContainedObject {
+private:
+ static int _targetPosX;
+ static int _targetPosY;
+ static int _maxDist;
+
+ static int _numToGen;
+ static int _sizeAngleStep;
+
+ int _sourceHub;
+
+ int _posX;
+ int _posY;
+ int _angleTo;
+ int _powerTo;
+
+ int _disabled;
+ int _waterFlag;
+ int _waterSourceX;
+ int _waterSourceY;
+ int _waterDestX;
+ int _waterDestY;
+
+ AI *_ai;
+
+protected:
+ virtual float calcH();
+
+public:
+ Traveller(AI *ai);
+ Traveller(int originX, int originY, AI *ai);
+ ~Traveller() {}
+
+ IContainedObject *duplicate() { return this; }
+
+ static void setTargetPosX(int posX) { _targetPosX = posX; }
+ static void setTargetPosY(int posY) { _targetPosY = posY; }
+ static void setMaxDist(int maxDist) { _maxDist = maxDist; }
+
+ void setSourceHub(int sourceHub) { _sourceHub = sourceHub; }
+
+ void setPosX(int posX) { _posX = posX; }
+ void setPosY(int posY) { _posY = posY; }
+ void setAngleTo(int angleTo) { _angleTo = angleTo; }
+ void setPowerTo(int powerTo) { _powerTo = powerTo; }
+
+ void setWaterSourceX(int waterSourceX) { _waterSourceX = waterSourceX; }
+ void setWaterSourceY(int waterSourceY) { _waterSourceY = waterSourceY; }
+
+ void setWaterDestX(int waterDestX) { _waterDestX = waterDestX; }
+ void setWaterDestY(int waterDestY) { _waterDestY = waterDestY; }
+
+ int getSourceHub() const { return _sourceHub; }
+
+ int getPosX() const { return _posX; }
+ int getPosY() const { return _posY; }
+ int getAngleTo() const { return _angleTo; }
+ int getPowerTo() const { return _powerTo; }
+
+ int getWaterSourceX() const { return _waterSourceX; }
+ int getWaterSourceY() const { return _waterSourceY; }
+ int getWaterDestX() const { return _waterDestX; }
+ int getWaterDestY() const { return _waterDestY; }
+
+ void setDisabled() { _disabled = 1; }
+ void unsetDisabled() { _disabled = 0; }
+ int getDisabled() { return _disabled; }
+
+ void adjustPosX(int offsetX);
+ void adjustPosY(int offsetY);
+ void adjustXY(int offsetX, int offsetY);
+
+ void enableWaterFlag() { _waterFlag = 1; }
+ void disableWaterFlag() { _waterFlag = 0; }
+ int getWaterFlag() const { return _waterFlag; }
+
+ virtual int numChildrenToGen();
+ virtual IContainedObject *createChildObj(int, int &);
+
+ virtual int checkSuccess();
+ virtual float calcT();
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/he/moonbase/ai_tree.cpp b/engines/scumm/he/moonbase/ai_tree.cpp
new file mode 100644
index 0000000000..d18536812b
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_tree.cpp
@@ -0,0 +1,245 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "scumm/he/intern_he.h"
+
+#include "scumm/he/moonbase/moonbase.h"
+#include "scumm/he/moonbase/ai_tree.h"
+#include "scumm/he/moonbase/ai_main.h"
+
+namespace Scumm {
+
+static int compareTreeNodes(const void *a, const void *b) {
+ if (((const TreeNode *)a)->value < ((const TreeNode *)b)->value)
+ return -1;
+ else if (((const TreeNode *)a)->value > ((const TreeNode *)b)->value)
+ return 1;
+ else
+ return 0;
+}
+
+Tree::Tree(AI *ai) : _ai(ai) {
+ pBaseNode = new Node;
+ _maxDepth = MAX_DEPTH;
+ _maxNodes = MAX_NODES;
+ _currentNode = 0;
+ _currentChildIndex = 0;
+
+ _currentMap = new Common::SortedArray<TreeNode *>(compareTreeNodes);
+}
+
+Tree::Tree(IContainedObject *contents, AI *ai) : _ai(ai) {
+ pBaseNode = new Node;
+ pBaseNode->setContainedObject(contents);
+ _maxDepth = MAX_DEPTH;
+ _maxNodes = MAX_NODES;
+ _currentNode = 0;
+ _currentChildIndex = 0;
+
+ _currentMap = new Common::SortedArray<TreeNode *>(compareTreeNodes);
+}
+
+Tree::Tree(IContainedObject *contents, int maxDepth, AI *ai) : _ai(ai) {
+ pBaseNode = new Node;
+ pBaseNode->setContainedObject(contents);
+ _maxDepth = maxDepth;
+ _maxNodes = MAX_NODES;
+ _currentNode = 0;
+ _currentChildIndex = 0;
+
+ _currentMap = new Common::SortedArray<TreeNode *>(compareTreeNodes);
+}
+
+Tree::Tree(IContainedObject *contents, int maxDepth, int maxNodes, AI *ai) : _ai(ai) {
+ pBaseNode = new Node;
+ pBaseNode->setContainedObject(contents);
+ _maxDepth = maxDepth;
+ _maxNodes = maxNodes;
+ _currentNode = 0;
+ _currentChildIndex = 0;
+
+ _currentMap = new Common::SortedArray<TreeNode *>(compareTreeNodes);
+}
+
+void Tree::duplicateTree(Node *sourceNode, Node *destNode) {
+ Common::Array<Node *> vUnvisited = sourceNode->getChildren();
+
+ while (vUnvisited.size()) {
+ Node *newNode = new Node(*(vUnvisited.end()));
+ newNode->setParent(destNode);
+ (destNode->getChildren()).push_back(newNode);
+ duplicateTree(*(vUnvisited.end()), newNode);
+ vUnvisited.pop_back();
+ }
+}
+
+Tree::Tree(const Tree *sourceTree, AI *ai) : _ai(ai) {
+ pBaseNode = new Node(sourceTree->getBaseNode());
+ _maxDepth = sourceTree->getMaxDepth();
+ _maxNodes = sourceTree->getMaxNodes();
+ _currentMap = new Common::SortedArray<TreeNode *>(compareTreeNodes);
+ _currentNode = 0;
+ _currentChildIndex = 0;
+
+ duplicateTree(sourceTree->getBaseNode(), pBaseNode);
+}
+
+Tree::~Tree() {
+ // Delete all nodes
+ Node *pNodeItr = pBaseNode;
+
+ // Depth first traversal of nodes to delete them
+ while (pNodeItr != NULL) {
+ // If any children are left, move to one of them
+ if (!(pNodeItr->getChildren().empty())) {
+ pNodeItr = pNodeItr->popChild();
+ } else {
+ // Delete this node, and move up to the parent for further processing
+ Node *pTemp = pNodeItr;
+ pNodeItr = pNodeItr->getParent();
+ delete pTemp;
+ pTemp = NULL;
+ }
+ }
+
+ delete _currentMap;
+}
+
+Node *Tree::aStarSearch() {
+ Common::SortedArray<TreeNode *> mmfpOpen(compareTreeNodes);
+
+ Node *currentNode = NULL;
+ float currentT;
+
+ Node *retNode = NULL;
+
+ float temp = pBaseNode->getContainedObject()->calcT();
+
+ if (static_cast<int>(temp) != SUCCESS) {
+ mmfpOpen.insert(new TreeNode(pBaseNode->getObjectT(), pBaseNode));
+
+ while (mmfpOpen.size() && (retNode == NULL)) {
+ currentNode = mmfpOpen.front()->node;
+ mmfpOpen.erase(mmfpOpen.begin());
+
+ if ((currentNode->getDepth() < _maxDepth) && (Node::getNodeCount() < _maxNodes)) {
+ // Generate nodes
+ Common::Array<Node *> vChildren = currentNode->getChildren();
+
+ for (Common::Array<Node *>::iterator i = vChildren.begin(); i != vChildren.end(); i++) {
+ IContainedObject *pTemp = (*i)->getContainedObject();
+ currentT = pTemp->calcT();
+
+ if (currentT == SUCCESS)
+ retNode = *i;
+ else
+ mmfpOpen.insert(new TreeNode(currentT, (*i)));
+ }
+ } else {
+ retNode = currentNode;
+ }
+ }
+ } else {
+ retNode = pBaseNode;
+ }
+
+ return retNode;
+}
+
+
+Node *Tree::aStarSearch_singlePassInit() {
+ Node *retNode = NULL;
+
+ _currentChildIndex = 1;
+
+ float temp = pBaseNode->getContainedObject()->calcT();
+
+ if (static_cast<int>(temp) != SUCCESS) {
+ _currentMap->insert(new TreeNode(pBaseNode->getObjectT(), pBaseNode));
+ } else {
+ retNode = pBaseNode;
+ }
+
+ return retNode;
+}
+
+Node *Tree::aStarSearch_singlePass() {
+ float currentT = 0.0;
+ Node *retNode = NULL;
+
+ static int maxTime = 0;
+
+ if (_currentChildIndex == 1) {
+ maxTime = _ai->getPlayerMaxTime();
+ }
+
+ if (_currentChildIndex) {
+ if (!(_currentMap->size())) {
+ retNode = _currentNode;
+ return retNode;
+ }
+
+ _currentNode = _currentMap->front()->node;
+ _currentMap->erase(_currentMap->begin());
+ }
+
+ if ((_currentNode->getDepth() < _maxDepth) && (Node::getNodeCount() < _maxNodes) && ((!maxTime) || (_ai->getTimerValue(3) < maxTime))) {
+ // Generate nodes
+ _currentChildIndex = _currentNode->generateChildren();
+
+ if (_currentChildIndex) {
+ Common::Array<Node *> vChildren = _currentNode->getChildren();
+
+ if (!vChildren.size() && !_currentMap->size()) {
+ _currentChildIndex = 0;
+ retNode = _currentNode;
+ }
+
+ for (Common::Array<Node *>::iterator i = vChildren.begin(); i != vChildren.end(); i++) {
+ IContainedObject *pTemp = (*i)->getContainedObject();
+ currentT = pTemp->calcT();
+
+ if (currentT == SUCCESS) {
+ retNode = *i;
+ i = vChildren.end() - 1;
+ } else {
+ _currentMap->insert(new TreeNode(currentT, (*i)));
+ }
+ }
+
+ if (!(_currentMap->size()) && (currentT != SUCCESS)) {
+ assert(_currentNode != NULL);
+ retNode = _currentNode;
+ }
+ }
+ } else {
+ retNode = _currentNode;
+ }
+
+ return retNode;
+}
+
+int Tree::IsBaseNode(Node *thisNode) {
+ return (thisNode == pBaseNode);
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_tree.h b/engines/scumm/he/moonbase/ai_tree.h
new file mode 100644
index 0000000000..45d4963bc1
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_tree.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.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_HE_MOONBASE_AI_TREE_H
+#define SCUMM_HE_MOONBASE_AI_TREE_H
+
+#include "common/array.h"
+#include "scumm/he/moonbase/ai_node.h"
+
+namespace Scumm {
+
+const int MAX_DEPTH = 100;
+const int MAX_NODES = 1000000;
+
+class AI;
+
+struct TreeNode {
+ float value;
+ Node *node;
+
+ TreeNode(float v, Node *n) { value = v; node = n; }
+};
+
+class Tree {
+private:
+ Node *pBaseNode;
+
+ int _maxDepth;
+ int _maxNodes;
+
+ int _currentChildIndex;
+
+ Common::SortedArray<TreeNode *> *_currentMap;
+ Node *_currentNode;
+
+ AI *_ai;
+
+public:
+ Tree(AI *ai);
+ Tree(IContainedObject *contents, AI *ai);
+ Tree(IContainedObject *contents, int maxDepth, AI *ai);
+ Tree(IContainedObject *contents, int maxDepth, int maxNodes, AI *ai);
+ Tree(const Tree *sourceTree, AI *ai);
+ ~Tree();
+
+ void duplicateTree(Node *sourceNode, Node *destNode);
+
+ Node *getBaseNode() const { return pBaseNode; }
+ void setMaxDepth(int maxDepth) { _maxDepth = maxDepth; }
+ int getMaxDepth() const { return _maxDepth; }
+
+ void setMaxNodes(int maxNodes) { _maxNodes = maxNodes; }
+ int getMaxNodes() const { return _maxNodes; }
+
+ Node *aStarSearch();
+
+ Node *aStarSearch_singlePassInit();
+ Node *aStarSearch_singlePass();
+
+ int IsBaseNode(Node *thisNode);
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/he/moonbase/ai_types.cpp b/engines/scumm/he/moonbase/ai_types.cpp
new file mode 100644
index 0000000000..e134f5ee12
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_types.cpp
@@ -0,0 +1,176 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/textconsole.h"
+#include "scumm/he/moonbase/ai_types.h"
+
+namespace Scumm {
+
+AIEntity::AIEntity(int id) {
+ switch (id) {
+ default:
+ case BRUTAKAS:
+ warning("BRUTAKAS");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "BRUTAKAS");
+ _behaviorVariation = AI_VAR_SMALL;
+ _targetVariation = AI_VAR_SMALL;
+ _angleVariation = AI_VAR_SMALL;
+ _powerVariation = AI_VAR_SMALL;
+ break;
+
+ case AGI:
+ warning("Agi");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "Agi");
+ _behaviorVariation = AI_VAR_SMALL;
+ _targetVariation = AI_VAR_MEDIUM;
+ _angleVariation = AI_VAR_MEDIUM;
+ _powerVariation = AI_VAR_LARGE;
+ break;
+
+ case EL_GATO:
+ warning("El Gato de la Noche");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "El Gato de la Noche");
+ _behaviorVariation = AI_VAR_SMALL;
+ _targetVariation = AI_VAR_SMALL;
+ _angleVariation = AI_VAR_SMALL;
+ _powerVariation = AI_VAR_MEDIUM;
+ break;
+
+ case PIXELAHT:
+ warning("Pixelaht");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "Pixelaht");
+ _behaviorVariation = AI_VAR_SMALL;
+ _targetVariation = AI_VAR_LARGE;
+ _angleVariation = AI_VAR_MEDIUM;
+ _powerVariation = AI_VAR_SMALL;
+ break;
+
+ case CYBALL:
+ warning("cYbaLL");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "cYbaLL");
+ _behaviorVariation = AI_VAR_LARGE;
+ _targetVariation = AI_VAR_LARGE;
+ _angleVariation = AI_VAR_SMALL;
+ _powerVariation = AI_VAR_SMALL;
+ break;
+
+ case NEEP:
+ warning("Neep! Neep!");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "Neep! Neep!");
+ _behaviorVariation = AI_VAR_MEDIUM;
+ _targetVariation = AI_VAR_SMALL;
+ _angleVariation = AI_VAR_SMALL;
+ _powerVariation = AI_VAR_LARGE;
+ break;
+
+ case WARCUPINE:
+ warning("WARcupine");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "WARcupine");
+ _behaviorVariation = AI_VAR_SMALL;
+ _targetVariation = AI_VAR_SMALL;
+ _angleVariation = AI_VAR_LARGE;
+ _powerVariation = AI_VAR_MEDIUM;
+ break;
+
+ case AONE:
+ warning("aone");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "aone");
+ _behaviorVariation = AI_VAR_MEDIUM;
+ _targetVariation = AI_VAR_MEDIUM;
+ _angleVariation = AI_VAR_MEDIUM;
+ _powerVariation = AI_VAR_MEDIUM;
+ break;
+
+ case SPANDO:
+ warning("S p a n d o");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "S p a n d o");
+ _behaviorVariation = AI_VAR_LARGE;
+ _targetVariation = AI_VAR_LARGE;
+ _angleVariation = AI_VAR_SMALL;
+ _powerVariation = AI_VAR_SMALL;
+ break;
+
+ case ORBNU_LUNATEK:
+ warning("Bonur J Lunatek");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "Bonur J Lunatek");
+ _behaviorVariation = AI_VAR_HUGE;
+ _targetVariation = AI_VAR_HUGE;
+ _angleVariation = AI_VAR_HUGE;
+ _powerVariation = AI_VAR_HUGE;
+ break;
+
+ case CRAWLER_CHUCKER:
+ warning("Le Chuckre des Crawlres");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "Le Chuckre des Crawlres");
+ _behaviorVariation = AI_VAR_SMALL;
+ _targetVariation = AI_VAR_MEDIUM;
+ _angleVariation = AI_VAR_MEDIUM;
+ _powerVariation = AI_VAR_LARGE;
+ break;
+
+ case ENERGY_HOG:
+ warning("Energy Hog");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "Energy Hog\n");
+ _behaviorVariation = AI_VAR_SMALL;
+ _targetVariation = AI_VAR_SMALL;
+ _angleVariation = AI_VAR_SMALL;
+ _powerVariation = AI_VAR_SMALL;
+ break;
+
+ case RANGER:
+ warning("Ranger");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "Ranger\n");
+ _behaviorVariation = AI_VAR_SMALL;
+ _targetVariation = AI_VAR_SMALL;
+ _angleVariation = AI_VAR_SMALL;
+ _powerVariation = AI_VAR_SMALL;
+ break;
+ }
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_types.h b/engines/scumm/he/moonbase/ai_types.h
new file mode 100644
index 0000000000..e2de87d653
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_types.h
@@ -0,0 +1,97 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SCUMM_HE_MOONBASE_AI_TYPES_H
+#define SCUMM_HE_MOONBASE_AI_TYPES_H
+
+namespace Scumm {
+
+enum {
+ AGI = 1,
+ AONE = 2,
+ BRUTAKAS = 3,
+ CYBALL = 4,
+ EL_GATO = 5,
+ NEEP = 6,
+ ORBNU_LUNATEK = 7,
+ PIXELAHT = 8,
+ SPANDO = 9,
+ WARCUPINE = 10
+};
+
+enum {
+ CRAWLER_CHUCKER = 11,
+ ENERGY_HOG = 12,
+ RANGER = 13
+};
+
+enum {
+ AI_VAR_NONE = -1,
+ AI_VAR_SMALL = 0,
+ AI_VAR_MEDIUM = 1,
+ AI_VAR_LARGE = 2,
+ AI_VAR_HUGE = 5
+};
+
+enum {
+ AI_VAR_BASE_BEHAVIOR = 10,
+ AI_VAR_BASE_TARGET = 10,
+ AI_VAR_BASE_ANGLE = 2,
+ AI_VAR_BASE_POWER = 5
+};
+
+class AIEntity {
+private:
+ int _id;
+ char *_nameString;
+ int _behaviorVariation;
+ int _targetVariation;
+ int _angleVariation;
+ int _powerVariation;
+
+public:
+ AIEntity(int id);
+ ~AIEntity() {
+ if (_nameString) {
+ delete _nameString;
+ _nameString = 0;
+ }
+ }
+
+ int getID() const { return _id; }
+ char *getNameString() const { return _nameString; }
+ int getBehaviorVariation() const { return _behaviorVariation; }
+ int getTargetVariation() const { return _targetVariation; }
+ int getAngleVariation() const { return _angleVariation; }
+ int getPowerVariation() const { return _powerVariation; }
+
+ void setID(int id) { _id = id; }
+ void setNameString(char *nameString) { _nameString = nameString; }
+ void setBehaviorVariation(int behaviorVariation) { _behaviorVariation = behaviorVariation; }
+ void setTargetVariation(int targetVariation) { _targetVariation = targetVariation; }
+ void setAngleVariation(int angleVariation) { _angleVariation = angleVariation; }
+ void setPowerVariation(int powerVariation) { _powerVariation = powerVariation; }
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/he/moonbase/ai_weapon.cpp b/engines/scumm/he/moonbase/ai_weapon.cpp
new file mode 100644
index 0000000000..ba50aae4d1
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_weapon.cpp
@@ -0,0 +1,88 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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/he/moonbase/ai_weapon.h"
+#include "scumm/he/moonbase/ai_main.h"
+
+namespace Scumm {
+
+Weapon::Weapon(int typeID) { //, float damage, int radius)
+ switch (typeID) {
+ default:
+ case ITEM_BOMB:
+ becomeBomb();
+ break;
+
+ case ITEM_CLUSTER:
+ becomeCluster();
+ break;
+
+ case ITEM_CRAWLER:
+ becomeCrawler();
+ break;
+
+ case ITEM_EMP:
+ becomeEMP();
+ break;
+
+ case ITEM_SPIKE:
+ becomeSpike();
+ break;
+ }
+}
+
+void Weapon::becomeBomb() {
+ _typeID = ITEM_BOMB;
+ _damage = 3;
+ _radius = 30;
+ _cost = 1;
+}
+
+void Weapon::becomeCluster() {
+ _typeID = ITEM_CLUSTER;
+ _damage = 1.5;
+ _radius = 20;
+ _cost = 1;
+}
+
+void Weapon::becomeCrawler() {
+ _typeID = ITEM_CRAWLER;
+ _damage = 4;
+ _radius = 180;
+ _cost = 7;
+}
+
+void Weapon::becomeEMP() {
+ _typeID = ITEM_EMP;
+ _damage = .1f;
+ _radius = 215;
+ _cost = 3;
+}
+
+void Weapon::becomeSpike() {
+ _typeID = ITEM_SPIKE;
+ _damage = 6;
+ _radius = 180;
+ _cost = 3;
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_weapon.h b/engines/scumm/he/moonbase/ai_weapon.h
new file mode 100644
index 0000000000..55c710ccdf
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_weapon.h
@@ -0,0 +1,59 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SCUMM_HE_MOONBASE_AI_WEAPON_H
+#define SCUMM_HE_MOONBASE_AI_WEAPON_H
+
+namespace Scumm {
+
+class Weapon {
+private:
+ int _typeID;
+ float _damage;
+ int _radius;
+ int _cost;
+
+public:
+ Weapon() {}
+ Weapon(int typeID);
+ virtual ~Weapon() {}
+
+ void setTypeID(int typeID) { _typeID = typeID; }
+ void setDamage(float damage) { _damage = damage; }
+ void setRadius(int radius) { _radius = radius; }
+ void setCost(int cost) { _cost = cost; }
+
+ int getTypeID() { return _typeID; }
+ float getDamage() { return _damage; }
+ int getRadius() { return _radius; }
+ int getCost() { return _cost; }
+
+ void becomeBomb();
+ void becomeCluster();
+ void becomeCrawler();
+ void becomeEMP();
+ void becomeSpike();
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/he/moonbase/moonbase.cpp b/engines/scumm/he/moonbase/moonbase.cpp
new file mode 100644
index 0000000000..15ababd321
--- /dev/null
+++ b/engines/scumm/he/moonbase/moonbase.cpp
@@ -0,0 +1,223 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "scumm/he/intern_he.h"
+#include "scumm/he/moonbase/moonbase.h"
+#include "scumm/he/moonbase/ai_main.h"
+
+namespace Scumm {
+
+Moonbase::Moonbase(ScummEngine_v100he *vm) : _vm(vm) {
+ initFOW();
+
+ _ai = new AI(_vm);
+}
+
+Moonbase::~Moonbase() {
+ delete _ai;
+}
+
+int Moonbase::readFromArray(int array, int y, int x) {
+ _vm->VAR(_vm->VAR_U32_ARRAY_UNK) = array;
+
+ return _vm->readArray(_vm->VAR_U32_ARRAY_UNK, y, x);
+}
+
+void Moonbase::deallocateArray(int array) {
+ _vm->VAR(_vm->VAR_U32_ARRAY_UNK) = array;
+
+ return _vm->nukeArray(_vm->VAR_U32_ARRAY_UNK);
+}
+
+int Moonbase::callScummFunction(int scriptNumber, int paramCount,...) {
+ va_list va_params;
+ va_start(va_params, paramCount);
+ int args[25];
+
+ memset(args, 0, sizeof(args));
+
+ Common::String str;
+ str = Common::String::format("callScummFunction(%d, [", scriptNumber);
+
+ for (int i = 0; i < paramCount; i++) {
+ args[i] = va_arg(va_params, int);
+
+ str += Common::String::format("%d ", args[i]);
+ }
+ str += "])";
+
+ debug(0, "%s", str.c_str());
+
+
+ va_end(va_params);
+
+ _vm->runScript(scriptNumber, 0, 1, args);
+
+ return _vm->pop();
+}
+
+
+void Moonbase::blitT14WizImage(uint8 *dst, int dstw, int dsth, int dstPitch, const Common::Rect *clipBox,
+ uint8 *wizd, int x, int y, int rawROP, int paramROP) {
+ bool premulAlpa = false;
+
+ if (rawROP == 1)
+ premulAlpa = true;
+
+ Common::Rect clippedDstRect(dstw, dsth);
+ if (clipBox) {
+ Common::Rect clip(clipBox->left, clipBox->top, clipBox->right, clipBox->bottom);
+ if (clippedDstRect.intersects(clip)) {
+ clippedDstRect.clip(clip);
+ } else {
+ return;
+ }
+ }
+
+ int width = READ_LE_UINT16(wizd + 0x8 + 0);
+ int height = READ_LE_UINT16(wizd + 0x8 + 2);
+
+ Common::Rect srcLimitsRect(width, height);
+ Common::Rect dstOperation(x, y, x + width, y + height);
+ if (!clippedDstRect.intersects(dstOperation))
+ return;
+ Common::Rect clippedRect = clippedDstRect.findIntersectingRect(dstOperation);
+
+ int cx = clippedRect.right - clippedRect.left;
+ int cy = clippedRect.bottom - clippedRect.top;
+
+ int sx = ((clippedRect.left - x) + srcLimitsRect.left);
+ int sy = ((clippedRect.top - y) + srcLimitsRect.top);
+
+ dst += clippedRect.top * dstPitch + clippedRect.left * 2;
+
+ int headerSize = READ_LE_UINT32(wizd + 0x4);
+ uint8 *dataPointer = wizd + 0x8 + headerSize;
+
+ for (int i = 0; i < sy; i++) {
+ uint16 lineSize = READ_LE_UINT16(dataPointer + 0);
+
+ dataPointer += lineSize;
+ }
+
+ for (int i = 0; i < cy; i++) {
+ uint16 lineSize = READ_LE_UINT16(dataPointer + 0);
+ uint8 *singlesOffset = READ_LE_UINT16(dataPointer + 2) + dataPointer;
+ uint8 *quadsOffset = READ_LE_UINT16(dataPointer + 4) + dataPointer;
+
+ int pixels = 0;
+ byte *dst1 = dst;
+ byte *codes = dataPointer + 6;
+
+ while (1) {
+ int code = *codes - 2;
+ codes++;
+
+ if (code <= 0) { // quad or single
+ uint8 *src;
+ int cnt;
+ if (code == 0) { // quad
+ src = quadsOffset;
+ quadsOffset += 8;
+ cnt = 4; // 4 pixels
+ } else { // single
+ src = singlesOffset;
+ singlesOffset += 2;
+ cnt = 1;
+ }
+
+ for (int c = 0; c < cnt; c++) {
+ if (pixels >= sx) {
+ if (rawROP == 1) { // MMX_PREMUL_ALPHA_COPY
+ WRITE_LE_UINT16(dst1, READ_LE_UINT16(src));
+ } else if (rawROP == 2) { // MMX_ADDITIVE
+ uint16 color = READ_LE_UINT16(src);
+ uint16 orig = READ_LE_UINT16(dst1);
+
+ uint32 r = MIN<uint32>(0x7c00, (orig & 0x7c00) + (color & 0x7c00));
+ uint32 g = MIN<uint32>(0x03e0, (orig & 0x03e0) + (color & 0x03e0));
+ uint32 b = MIN<uint32>(0x001f, (orig & 0x001f) + (color & 0x001f));
+ WRITE_LE_UINT16(dst1, (r | g | b));
+ } else if (rawROP == 5) { // MMX_CHEAP_50_50
+ uint16 color = (READ_LE_UINT16(src) >> 1) & 0x3DEF;
+ uint16 orig = (READ_LE_UINT16(dst1) >> 1) & 0x3DEF;
+ WRITE_LE_UINT16(dst1, (color + orig));
+ }
+ dst1 += 2;
+ }
+ src += 2;
+ pixels++;
+ }
+ } else { // skip
+ if ((code & 1) == 0) {
+ code >>= 1;
+
+ for (int j = 0; j < code; j++) {
+ if (pixels >= sx)
+ dst1 += 2;
+ pixels++;
+ }
+ } else { // special case
+ if (pixels >= sx) {
+ int alpha = code >> 1;
+ uint16 color = READ_LE_UINT16(singlesOffset);
+ uint32 orig = READ_LE_UINT16(dst1);
+
+ if (!premulAlpa) {
+ WRITE_LE_UINT16(dst1, color); // ENABLE_PREMUL_ALPHA = 0
+ } else {
+ if (alpha > 32) {
+ alpha -= 32;
+
+ uint32 oR = orig & 0x7c00;
+ uint32 oG = orig & 0x03e0;
+ uint32 oB = orig & 0x1f;
+ uint32 dR = ((((color & 0x7c00) - oR) * alpha) >> 5) + oR;
+ uint32 dG = ((((color & 0x3e0) - oG) * alpha) >> 5) + oG;
+ uint32 dB = ((((color & 0x1f) - oB) * alpha) >> 5) + oB;
+
+ WRITE_LE_UINT16(dst1, (dR & 0x7c00) | (dG & 0x3e0) | (dB & 0x1f));
+ } else {
+ uint32 pix = ((orig << 16) | orig) & 0x3e07c1f;
+ pix = (((pix * alpha) & 0xffffffff) >> 5) & 0x3e07c1f;
+ pix = ((pix >> 16) + pix + color) & 0xffff;
+ WRITE_LE_UINT16(dst1, pix);
+ }
+ }
+
+ dst1 += 2;
+ }
+ singlesOffset += 2;
+ pixels++;
+ }
+ }
+
+ if (pixels >= cx + sx)
+ break;
+ }
+
+ dataPointer += lineSize;
+ dst += dstPitch;
+ }
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/moonbase.h b/engines/scumm/he/moonbase/moonbase.h
new file mode 100644
index 0000000000..243d53a11d
--- /dev/null
+++ b/engines/scumm/he/moonbase/moonbase.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.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_HE_MOONBASE_MOONBASE_H
+#define SCUMM_HE_MOONBASE_MOONBASE_H
+
+#ifdef ENABLE_HE
+
+#include "common/winexe_pe.h"
+
+namespace Scumm {
+
+class AI;
+
+class Moonbase {
+public:
+ Moonbase(ScummEngine_v100he *vm);
+ ~Moonbase();
+
+ int readFromArray(int array, int y, int x);
+ void deallocateArray(int array);
+ int callScummFunction(int scriptNumber, int paramCount,...);
+
+ void blitT14WizImage(uint8 *dst, int dstw, int dsth, int dstPitch, const Common::Rect *clipBox,
+ uint8 *wizd, int srcx, int srcy, int rawROP, int paramROP);
+
+ // FOW Stuff
+ bool isFOW(int resNum, int state, uint32 conditionBits) {
+ return resNum == _fowSentinelImage && state == _fowSentinelState && conditionBits == _fowSentinelConditionBits;
+ }
+
+ void initFOW();
+ void releaseFOWResources();
+
+ bool setFOWImage(int id);
+
+ void setFOWInfo(int fowInfoArray, int downDim, int acrossDim, int viewX, int viewY, int clipX1,
+ int clipY1, int clipX2, int clipY2, int technique, int nFrame);
+
+
+ void renderFOW(uint8 *destSurface, int dstPitch, int dstType, int dstw, int dsth, int flags);
+
+private:
+ int readFOWVisibilityArray(int array, int y, int x);
+ void renderFOWState(uint8 *destSurface, int dstPitch, int dstType, int dstw, int dsth, int x, int y, int srcw, int srch, int state, int flags);
+
+public:
+ int _fowSentinelImage;
+ int _fowSentinelState;
+ uint32 _fowSentinelConditionBits;
+
+ AI *_ai;
+
+private:
+ ScummEngine_v100he *_vm;
+
+ int _fowFrameBaseNumber;
+ int _fowAnimationFrames;
+ int _fowCurrentFOWFrame;
+
+ int32 _fowTileW;
+ int32 _fowTileH;
+
+ uint8 *_fowImage;
+ int _fowClipX1;
+ int _fowClipY1;
+ int _fowClipX2;
+ int _fowClipY2;
+
+ int _fowDrawX;
+ int _fowDrawY;
+
+ int _fowVtx1;
+ int _fowVty1;
+ int _fowMvx;
+ int _fowMvy;
+ int _fowVw;
+ int _fowVh;
+
+ bool _fowBlackMode;
+
+ int _fowRenderTable[32768];
+
+ Common::PEResources _exe;
+ Common::String _fileName;
+};
+
+} // End of namespace Scumm
+
+#endif // ENABLE_HE
+
+#endif // SCUMM_HE_MOONBASE_H
diff --git a/engines/scumm/he/moonbase/moonbase_fow.cpp b/engines/scumm/he/moonbase/moonbase_fow.cpp
new file mode 100644
index 0000000000..48c2219926
--- /dev/null
+++ b/engines/scumm/he/moonbase/moonbase_fow.cpp
@@ -0,0 +1,415 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 "scumm/he/intern_he.h"
+#include "scumm/he/moonbase/moonbase.h"
+
+namespace Scumm {
+
+#define FOW_ANIM_FRAME_COUNT 38
+
+void Moonbase::initFOW() {
+ _fowSentinelImage = -1;
+ _fowSentinelState = -1;
+ _fowSentinelConditionBits = 0;
+
+ _fowFrameBaseNumber = 0;
+ _fowAnimationFrames = 1;
+ _fowCurrentFOWFrame = 0;
+
+ _fowTileW = 0;
+ _fowTileH = 0;
+
+ _fowImage = nullptr;
+ _fowClipX1 = 0;
+ _fowClipY1 = 0;
+ _fowClipX2 = 0;
+ _fowClipY2 = 0;
+
+ _fowDrawX = 0;
+ _fowDrawY = 0;
+
+ _fowVtx1 = 0;
+ _fowVty1 = 0;
+ _fowMvx = 0;
+ _fowMvy = 0;
+ _fowVw = 0;
+ _fowVh = 0;
+
+ _fowBlackMode = true;
+
+ memset(_fowRenderTable, 0, 32768);
+}
+
+void Moonbase::releaseFOWResources() {
+ if (_fowImage) {
+ free(_fowImage);
+ _fowImage = 0;
+ }
+}
+
+bool Moonbase::setFOWImage(int image) {
+ releaseFOWResources();
+
+ if (!_fowImage) {
+ Common::String fowImageFilename(ConfMan.get("MOONX_FOWImageFilename").c_str());
+
+#if 0 // TODO
+ if (!fowImageFilename.empty()) {
+ void *wiz = loadWizFromFilename(fowImageFilename);
+
+ if (wiz) {
+ captureFOWImageFromLocation(wiz, file.size());
+ free(wiz);
+ }
+ }
+#endif
+
+ if (!_fowImage && image < 0) {
+ int resId;
+
+ // PIECES BUBBLES CIRCLES SIMPLE* WEDGEY BUBBLE2
+ // WEDGE2 SPIKEY ANGLES SMOOTHED WUZZY SYS7-BEVELED
+ if (image >= -12 && image <= -1)
+ resId = 210 - image; // 211-222 range
+ else
+ resId = 214; // default, SIMPLE
+
+ if (_fileName.empty()) { // We are running for the first time
+ _fileName = _vm->generateFilename(-3);
+
+ if (!_exe.loadFromEXE(_fileName))
+ error("Cannot open file %s", _fileName.c_str());
+ }
+
+ Common::SeekableReadStream *stream = _exe.getResource(Common::kPERCData, resId);
+
+ if (stream->size()) {
+ _fowImage = (uint8 *)malloc(stream->size());
+
+ stream->read(_fowImage, stream->size());
+ }
+
+ delete stream;
+ }
+
+ if (!_fowImage && image > 0)
+ _fowImage = _vm->getResourceAddress(rtImage, image);
+
+ if (!_fowImage)
+ return false;
+ }
+
+ int nStates = _vm->_wiz->getWizImageStates(_fowImage);
+
+ if (nStates > FOW_ANIM_FRAME_COUNT) {
+ releaseFOWResources();
+ return false;
+ }
+
+ _fowAnimationFrames = (nStates + FOW_ANIM_FRAME_COUNT - 1) / FOW_ANIM_FRAME_COUNT;
+
+ _vm->_wiz->getWizImageDim(_fowImage, (nStates - 1), _fowTileW, _fowTileH);
+ _fowBlackMode = !_vm->_wiz->isWizPixelNonTransparent(_fowImage, nStates - 1, 0, 0, 0);
+
+ if (ConfMan.hasKey("EnableFOWRects"))
+ _fowBlackMode = (ConfMan.getInt("EnableFOWRects") == 1);
+
+ return true;
+}
+
+enum FOWElement {
+ FOW_EMPTY = 0,
+ FOW_SOLID = 1,
+
+ FF_L = 0x01,
+ FF_R = 0x02,
+ FF_T = 0x04,
+ FF_B = 0x08,
+ FF_T_L = 0x10,
+ FF_T_R = 0x20,
+ FF_B_L = 0x40,
+ FF_B_R = 0x80,
+ FF_Q_A = (FF_L | FF_T | FF_T_L),
+ FF_Q_B = (FF_R | FF_T | FF_T_R),
+ FF_Q_C = (FF_L | FF_B | FF_B_L),
+ FF_Q_D = (FF_R | FF_B | FF_B_R)
+};
+
+int Moonbase::readFOWVisibilityArray(int array, int y, int x) {
+ if (readFromArray(array, y, x) > 0)
+ return FOW_EMPTY;
+
+ return FOW_SOLID;
+}
+
+void Moonbase::setFOWInfo(int fowInfoArray, int downDim, int acrossDim, int viewX, int viewY, int clipX1,
+ int clipY1, int clipX2, int clipY2, int technique, int nFrame) {
+ if (!_fowImage)
+ return;
+
+ _fowDrawX = clipX1;
+ _fowDrawY = clipY1;
+
+ _fowClipX1 = clipX1;
+ _fowClipY1 = clipY1;
+ _fowClipX2 = clipX2;
+ _fowClipY2 = clipY2;
+
+ // Figure out the number of tiles are involved
+ int view_W = (clipX2 - clipX1) + 1;
+ int view_H = (clipY2 - clipY1) + 1;
+
+ int tw = _fowTileW;
+ int th = _fowTileH;
+
+ int dw = acrossDim;
+ int dh = downDim;
+
+ int dlw = dw * tw;
+ int dlh = dh * th;
+
+ _fowMvx = (0 <= viewX) ? (viewX % dlw) : (dlw - (-viewX % dlw));
+ _fowMvy = (0 <= viewY) ? (viewY % dlh) : (dlh - (-viewY % dlh));
+
+ _fowVtx1 = _fowMvx / tw;
+ _fowVty1 = _fowMvy / th;
+
+ _fowVw = (((_fowMvx + view_W + tw - 1) / tw) - _fowVtx1) + 1;
+ _fowVh = (((_fowMvy + view_H + th - 1) / th) - _fowVty1) + 1;
+
+ // Build the connectivity table
+ int t = (_fowVty1 - 1); if (t >= dh) { t = 0; } else if (t < 0) { t = (dh - 1); }
+ int m = (_fowVty1 + 0); if (m >= dh) { m = 0; } else if (m < 0) { m = (dh - 1); }
+ int b = (_fowVty1 + 1); if (b >= dh) { b = 0; } else if (b < 0) { b = (dh - 1); }
+
+ int il = (_fowVtx1 - 1); if (il >= dh) { il = 0; } else if (il < 0) { il = (dw - 1); }
+ int ic = (_fowVtx1 + 0); if (ic >= dh) { ic = 0; } else if (ic < 0) { ic = (dw - 1); }
+ int ir = (_fowVtx1 + 1); if (ir >= dh) { ir = 0; } else if (ir < 0) { ir = (dw - 1); }
+
+ int dataOffset = (_fowVw * 3);
+ int dataOffset2 = (dataOffset * 2);
+ int *pOutterRenderTableA = _fowRenderTable;
+ int *pOutterRenderTableB = pOutterRenderTableA + dataOffset;
+
+ for (int ay = 0; ay < _fowVh; ay++) {
+ int l = il;
+ int c = ic;
+ int r = ir;
+
+ int *pRenderTableA = pOutterRenderTableA;
+ int *pRenderTableB = pOutterRenderTableB;
+
+ pOutterRenderTableA += dataOffset2;
+ pOutterRenderTableB += dataOffset2;
+
+ for (int ax = 0; ax < _fowVw; ax++) {
+ int visibility = readFOWVisibilityArray(fowInfoArray, m, c);
+
+ if (visibility == FOW_EMPTY) {
+ int bits = 0;
+
+ if (readFOWVisibilityArray(fowInfoArray, t, l) != 0) bits |= FF_T_L;
+ if (readFOWVisibilityArray(fowInfoArray, t, c) != 0) bits |= FF_T;
+ if (readFOWVisibilityArray(fowInfoArray, t, r) != 0) bits |= FF_T_R;
+ if (readFOWVisibilityArray(fowInfoArray, m, l) != 0) bits |= FF_L;
+ if (readFOWVisibilityArray(fowInfoArray, m, r) != 0) bits |= FF_R;
+ if (readFOWVisibilityArray(fowInfoArray, b, l) != 0) bits |= FF_B_L;
+ if (readFOWVisibilityArray(fowInfoArray, b, c) != 0) bits |= FF_B;
+ if (readFOWVisibilityArray(fowInfoArray, b, r) != 0) bits |= FF_B_R;
+
+ if (bits) {
+ *pRenderTableA++ = 1;
+ *pRenderTableB++ = 1;
+
+ // Quadrant (A)
+ if (bits & FF_Q_A) {
+ *pRenderTableA++ = (
+ ((FF_L & bits) ? 1 : 0) |
+ ((FF_T & bits) ? 2 : 0) |
+ ((FF_T_L & bits) ? 4 : 0)
+ ) + 0;
+ } else {
+ *pRenderTableA++ = 0;
+ }
+
+ // Quadrant (B)
+ if (bits & FF_Q_B) {
+ *pRenderTableA++ = (
+ ((FF_R & bits) ? 1 : 0) |
+ ((FF_T & bits) ? 2 : 0) |
+ ((FF_T_R & bits) ? 4 : 0)
+ ) + 8;
+ } else {
+ *pRenderTableA++ = 0;
+ }
+
+ // Quadrant (C)
+ if (bits & FF_Q_C) {
+ *pRenderTableB++ = (
+ ((FF_L & bits) ? 1 : 0) |
+ ((FF_B & bits) ? 2 : 0) |
+ ((FF_B_L & bits) ? 4 : 0)
+ ) + 16;
+ } else {
+ *pRenderTableB++ = 0;
+ }
+
+ // Quadrant (D)
+ if (bits & FF_Q_D) {
+ *pRenderTableB++ = (
+ ((FF_R & bits) ? 1 : 0) |
+ ((FF_B & bits) ? 2 : 0) |
+ ((FF_B_R & bits) ? 4 : 0)
+ ) + 24;
+ } else {
+ *pRenderTableB++ = 0;
+ }
+ } else {
+ *pRenderTableA++ = 0;
+ *pRenderTableB++ = 0;
+ }
+ } else {
+ if (_fowBlackMode) {
+ *pRenderTableA++ = 2;
+ *pRenderTableB++ = 2;
+ } else {
+ *pRenderTableA++ = 1;
+ *pRenderTableA++ = 33;
+ *pRenderTableA++ = 34;
+
+ *pRenderTableB++ = 1;
+ *pRenderTableB++ = 35;
+ *pRenderTableB++ = 36;
+ }
+ }
+
+ if (++l >= dw) { l = 0; }
+ if (++c >= dw) { c = 0; }
+ if (++r >= dw) { r = 0; }
+ }
+
+ if (++t >= dh) { t = 0; }
+ if (++m >= dh) { m = 0; }
+ if (++b >= dh) { b = 0; }
+ }
+
+ _fowCurrentFOWFrame = (nFrame >= 0) ? (nFrame % _fowAnimationFrames) : ((-nFrame) % _fowAnimationFrames);
+ _fowFrameBaseNumber = (_fowCurrentFOWFrame * FOW_ANIM_FRAME_COUNT);
+}
+
+void Moonbase::renderFOWState(uint8 *destSurface, int dstPitch, int dstType, int dstw, int dsth, int x, int y, int srcw, int srch, int state, int flags) {
+ int32 spotx, spoty;
+
+ _vm->_wiz->getWizImageSpot(_fowImage, state, spotx, spoty);
+ Common::Rect r(_fowClipX1, _fowClipY1, _fowClipX2, _fowClipY2);
+
+ _vm->_wiz->drawWizImageEx(destSurface, _fowImage, 0, dstPitch, dstType, dstw, dsth, x - spotx, y - spoty, srcw, srch, state, &r, flags, 0, 0, 16, 0, 0);
+}
+
+static void blackRect_16bpp(uint8 *destSurface, int dstPitch, int dstw, int dsth, int x1, int y1, int x2, int y2) {
+ byte *dst = destSurface + dstPitch * y1 + x1 * 2;
+ int h = y2 - y1;
+ int w = ((x2 - x1) + 1) * 2;
+
+ while ( --h >= 0 ) {
+ memset(dst, 0, w);
+ dst += dstPitch;
+ }
+}
+
+void Moonbase::renderFOW(uint8 *destSurface, int dstPitch, int dstType, int dstw, int dsth, int flags) {
+ if (!_fowImage)
+ return;
+
+ const int *pOutterRenderTable = _fowRenderTable;
+ int ixPos = ((_fowVtx1 * _fowTileW) - _fowMvx) + _fowDrawX;
+ int yPos = ((_fowVty1 * _fowTileH) - _fowMvy) + _fowDrawY;
+ int dataOffset = _fowVw * 3;
+ int halfTileHeight = _fowTileH / 2;
+ int cx2 = MIN(_fowClipX2, (dstw - 1));
+ int cy2 = MIN(_fowClipY2, (dsth - 1));
+
+ for (int ry = 0; ry < _fowVh; ry++) {
+ int real_yPos = yPos;
+
+ for (int i = 0; i < 2; i++) {
+ const int *pRenderTable = pOutterRenderTable;
+ pOutterRenderTable += dataOffset;
+
+ int xPos = ixPos;
+
+ for (int rx = 0; rx < _fowVw; rx++) {
+ int nState = *pRenderTable++;
+
+ if (nState != 0) {
+ if (nState == 2) {
+ int countLeft = (_fowVw - rx);
+ int count = 0;
+
+ for (; count < countLeft; count++) {
+ if (*(pRenderTable + count) != 2)
+ break;
+
+ pRenderTable++;
+ rx++;
+ }
+ count++;
+
+ int x1 = xPos;
+ int y1 = real_yPos;
+
+ xPos += _fowTileW * count;
+ int x2 = (xPos - 1);
+ int y2 = ((y1 + halfTileHeight) - 1);
+
+ x1 = MAX(0, x1);
+ y1 = MAX(0, y1);
+ x2 = MIN(x2, cx2);
+ y2 = MIN(y2, cy2);
+
+ if ((x2 >= x1) && (y2 >= y1) && (x1 <= _fowClipX2) && (y1 <= _fowClipY2))
+ blackRect_16bpp(destSurface, dstPitch, dstw, dsth, x1, y1, x2, y2);
+ } else {
+ int subState;
+
+ if ((subState = *pRenderTable++) != 0)
+ renderFOWState(destSurface, dstPitch, dstType, dstw, dsth, xPos, yPos, _fowTileW, _fowTileH, (subState + _fowFrameBaseNumber), flags);
+
+ if ((subState = *pRenderTable++) != 0)
+ renderFOWState(destSurface, dstPitch, dstType, dstw, dsth, xPos, yPos, _fowTileW, _fowTileH, (subState + _fowFrameBaseNumber), flags);
+
+ xPos += _fowTileW;
+ }
+ } else {
+ xPos += _fowTileW;
+ }
+ }
+ real_yPos += halfTileHeight;
+ }
+ yPos += _fowTileH;
+ }
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp
index afc6633ef6..2e7b4c4bf5 100644
--- a/engines/scumm/he/script_v100he.cpp
+++ b/engines/scumm/he/script_v100he.cpp
@@ -356,38 +356,38 @@ void ScummEngine_v100he::o100_actorOps() {
// FIXME: check stack parameters
debug(0,"o100_actorOps: case 0 UNHANDLED");
break;
- case 3:
+ case 3: // SO_ANIMATION
pop();
pop();
pop();
break;
- case 4: // SO_ANIMATION_SPEED
+ case 4: // SO_ANIMATION_SPEED
a->setAnimSpeed(pop());
break;
- case 6:
+ case 6: // SO_AT
j = pop();
i = pop();
a->putActor(i, j);
break;
- case 8:
+ case 8: // SO_BACKGROUND_OFF
a->_drawToBackBuf = false;
a->_needRedraw = true;
a->_needBgReset = true;
break;
- case 9:
+ case 9: // SO_BACKGROUND_ON
a->drawActorToBackBuf(a->getPos().x, a->getPos().y);
break;
- case 14:
+ case 14: // SO_CHARSET
a->_charset = pop();
break;
- case 18:
+ case 18: // SO_CLIPPED
a->_clipOverride.bottom = pop();
a->_clipOverride.right = pop();
a->_clipOverride.top = pop();
a->_clipOverride.left = pop();
adjustRect(a->_clipOverride);
break;
- case 22:
+ case 22: // SO_CONDITION
k = getStackList(args, ARRAYSIZE(args));
for (i = 0; i < k; ++i) {
a->setUserCondition(args[i] & 0x7F, args[i] & 0x80);
@@ -399,7 +399,7 @@ void ScummEngine_v100he::o100_actorOps() {
case 27: // SO_DEFAULT
a->initActor(0);
break;
- case 32:
+ case 32: // SO_ERASE
k = pop();
a->setHEFlag(1, k);
break;
@@ -417,11 +417,11 @@ void ScummEngine_v100he::o100_actorOps() {
a->remapActorPaletteColor(i, j);
a->_needRedraw = true;
break;
- case 59:
+ case 59: // SO_PRIORITY
a->_layer = pop();
a->_needRedraw = true;
break;
- case 63:
+ case 63: // SO_ROOM_PALETTE
a->_hePaletteNum = pop();
a->_needRedraw = true;
break;
@@ -438,7 +438,7 @@ void ScummEngine_v100he::o100_actorOps() {
i = pop();
a->setActorWalkSpeed(i, j);
break;
- case 78:
+ case 78: // SO_TALKIE
{
copyScriptString(string, sizeof(string));
int slot = pop();
@@ -461,7 +461,7 @@ void ScummEngine_v100he::o100_actorOps() {
case 89: // SO_NEVER_ZCLIP
a->_forceClip = 0;
break;
- case 128:
+ case 128: // SO_ACTOR_DEFAULT_CLIPPED
_actorClipOverride.bottom = pop();
_actorClipOverride.right = pop();
_actorClipOverride.top = pop();
@@ -517,7 +517,7 @@ void ScummEngine_v100he::o100_actorOps() {
case 141: // SO_TALK_COLOR
a->_talkColor = pop();
break;
- case 142:
+ case 142: // SO_TALK_CONDITION
k = pop();
if (k == 0)
k = _rnd.getRandomNumberRng(1, 10);
@@ -549,20 +549,20 @@ void ScummEngine_v100he::o100_arrayOps() {
debug(9,"o100_arrayOps: array %d case %d", array, subOp);
switch (subOp) {
- case 35:
+ case 35: // SO_FORMATTED_STRING
decodeScriptString(string);
len = resStrLen(string);
data = defineArray(array, kStringArray, 0, 0, 0, len);
memcpy(data, string, len);
break;
- case 77: // SO_ASSIGN_STRING
+ case 77: // SO_STRING
copyScriptString(string, sizeof(string));
len = resStrLen(string);
data = defineArray(array, kStringArray, 0, 0, 0, len);
memcpy(data, string, len);
break;
- case 128: // SO_ASSIGN_2DIM_LIST
+ case 128: // SO_ASSIGN_2DIM_LIST
len = getStackList(list, ARRAYSIZE(list));
id = readVar(array);
if (id == 0)
@@ -572,7 +572,7 @@ void ScummEngine_v100he::o100_arrayOps() {
writeArray(array, c, len, list[len]);
}
break;
- case 129: // SO_ASSIGN_INT_LIST
+ case 129: // SO_ASSIGN_INT_LIST
b = pop();
c = pop();
id = readVar(array);
@@ -583,7 +583,7 @@ void ScummEngine_v100he::o100_arrayOps() {
writeArray(array, 0, b + c, pop());
}
break;
- case 130:
+ case 130: // SO_COMPLEX_ARRAY_ASSIGNMENT
len = getStackList(list, ARRAYSIZE(list));
dim1end = pop();
dim1start = pop();
@@ -607,7 +607,7 @@ void ScummEngine_v100he::o100_arrayOps() {
dim2start++;
}
break;
- case 131:
+ case 131: // SO_COMPLEX_ARRAY_COPY_OPERATION
{
int a2_dim1end = pop();
int a2_dim1start = pop();
@@ -624,44 +624,76 @@ void ScummEngine_v100he::o100_arrayOps() {
copyArray(array, a1_dim2start, a1_dim2end, a1_dim1start, a1_dim1end, array2, a2_dim2start, a2_dim2end, a2_dim1start, a2_dim1end);
}
break;
- case 132:
- // TODO: Used by room 2 script 2180 in Moonbase Commander
- fetchScriptWord();
- fetchScriptWord();
- type = pop();
- pop();
- pop();
- pop();
- pop();
- pop();
- pop();
- pop();
- pop();
- dim1end = pop();
- dim1start = pop();
- dim2end = pop();
- dim2start = pop();
- id = readVar(array);
- if (id == 0) {
- defineArray(array, kDwordArray, dim2start, dim2end, dim1start, dim1end);
- }
- switch (type) {
- case 1:
- break;
- case 2:
- break;
- case 3:
- break;
- case 4:
- break;
- case 5:
+ case 132: // SO_COMPLEX_ARRAY_MATH_OPERATION
+ {
+ // Used by room 2 script 2180 in Moonbase Commander (modify-line-of-sight)
+ int array2 = fetchScriptWord();
+ int array1 = fetchScriptWord();
+ type = pop();
+ int a1_dim1end = pop();
+ int a1_dim1start = pop();
+ int a1_dim2end = pop();
+ int a1_dim2start = pop();
+ int a2_dim1end = pop();
+ int a2_dim1start = pop();
+ int a2_dim2end = pop();
+ int a2_dim2start = pop();
+ dim1end = pop();
+ dim1start = pop();
+ dim2end = pop();
+ dim2start = pop();
+
+ int a12_num = a1_dim2end - a1_dim2start + 1;
+ int a11_num = a1_dim1end - a1_dim1start + 1;
+ int a22_num = a2_dim2end - a2_dim2start + 1;
+ int a21_num = a2_dim1end - a2_dim1start + 1;
+ int d12_num = dim2end - dim2start + 1;
+ int d11_num = dim1end - dim1start + 1;
+
+ id = readVar(array);
+ if (id == 0) {
+ defineArray(array, kDwordArray, dim2start, dim2end, dim1start, dim1end);
+ }
+ if (a12_num != a22_num || a12_num != d12_num || a11_num != a21_num || a11_num != d11_num) {
+ error("Operation size mismatch (%d vs %d)(%d vs %d)", a12_num, a22_num, a11_num, a21_num);
+ }
+
+ for (; a1_dim2start <= a1_dim2end; ++a1_dim2start, ++a2_dim2start, ++dim2start) {
+ int a2dim1 = a2_dim1start;
+ int a1dim1 = a1_dim1start;
+ int dim1 = dim1start;
+ for (; a1dim1 <= a1_dim1end; ++a1dim1, ++a2dim1, ++dim1) {
+ int val1 = readArray(array1, a1_dim2start, a1dim1);
+ int val2 = readArray(array2, a2_dim2start, a2dim1);
+ int res;
+
+ switch (type) {
+ case 1: // Addition
+ res = val2 + val1;
+ break;
+ case 2: // Subtraction
+ res = val2 - val1;
+ break;
+ case 3: // Binary AND
+ res = val2 & val1;
+ break;
+ case 4: // Binary OR
+ res = val2 | val1;
+ break;
+ case 5: // Binary XOR
+ res = val2 ^ val1;
+ break;
+ default:
+ error("o100_arrayOps: case 132 unknown type %d)", type);
+ }
+ writeArray(array, dim2start, dim1, res);
+ }
+ }
+
+ warning("STUB: o100_arrayOps: case 132 type %d", type);
break;
- default:
- error("o100_arrayOps: case 132 unknown type %d)", type);
}
- debug(0, "o100_arrayOps: case 132 type %d", type);
- break;
- case 133:
+ case 133: // SO_RANGE_ARRAY_ASSIGNMENT
b = pop();
c = pop();
dim1end = pop();
@@ -910,10 +942,10 @@ void ScummEngine_v100he::o100_setSpriteGroupInfo() {
byte subOp = fetchScriptByte();
switch (subOp) {
- case 0:
+ case 0: // SO_INIT
_curSpriteGroupId = pop();
break;
- case 6:
+ case 6: // SO_MOVE
value2 = pop();
value1 = pop();
if (!_curSpriteGroupId)
@@ -921,7 +953,7 @@ void ScummEngine_v100he::o100_setSpriteGroupInfo() {
_sprite->setGroupPosition(_curSpriteGroupId, value1, value2);
break;
- case 18:
+ case 18: // SO_CLIPPED
value4 = pop();
value3 = pop();
value2 = pop();
@@ -931,10 +963,10 @@ void ScummEngine_v100he::o100_setSpriteGroupInfo() {
_sprite->setGroupBounds(_curSpriteGroupId, value1, value2, value3, value4);
break;
- case 38:
+ case 38: // SO_GROUP
type = pop() - 1;
switch (type) {
- case 0:
+ case 0: // SPRGRPOP_MOVE
value2 = pop();
value1 = pop();
if (!_curSpriteGroupId)
@@ -942,48 +974,48 @@ void ScummEngine_v100he::o100_setSpriteGroupInfo() {
_sprite->moveGroupMembers(_curSpriteGroupId, value1, value2);
break;
- case 1:
+ case 1: // SPRGRPOP_ORDER
value1 = pop();
if (!_curSpriteGroupId)
break;
_sprite->setGroupMembersPriority(_curSpriteGroupId, value1);
break;
- case 2:
+ case 2: // SPRGRPOP_NEW_GROUP
value1 = pop();
if (!_curSpriteGroupId)
break;
_sprite->setGroupMembersGroup(_curSpriteGroupId, value1);
break;
- case 3:
+ case 3: // SPRGRPOP_UPDATE_TYPE
value1 = pop();
if (!_curSpriteGroupId)
break;
_sprite->setGroupMembersUpdateType(_curSpriteGroupId, value1);
break;
- case 4:
+ case 4: // SPRGRPOP_NEW
if (!_curSpriteGroupId)
break;
_sprite->setGroupMembersResetSprite(_curSpriteGroupId);
break;
- case 5:
+ case 5: // SPRGRPOP_ANIMATION_SPEED
value1 = pop();
if (!_curSpriteGroupId)
break;
_sprite->setGroupMembersAnimationSpeed(_curSpriteGroupId, value1);
break;
- case 6:
+ case 6: // SPRGRPOP_ANIMATION_TYPE
value1 = pop();
if (!_curSpriteGroupId)
break;
_sprite->setGroupMembersAutoAnimFlag(_curSpriteGroupId, value1);
break;
- case 7:
+ case 7: // SPRGRPOP_SHADOW
value1 = pop();
if (!_curSpriteGroupId)
break;
@@ -994,14 +1026,14 @@ void ScummEngine_v100he::o100_setSpriteGroupInfo() {
error("o100_setSpriteGroupInfo subOp 38: Unknown case %d", subOp);
}
break;
- case 40:
+ case 40: // SO_IMAGE
value1 = pop();
if (!_curSpriteGroupId)
break;
_sprite->setGroupImage(_curSpriteGroupId, value1);
break;
- case 49:
+ case 49: // SO_AT
value2 = pop();
value1 = pop();
if (!_curSpriteGroupId)
@@ -1009,51 +1041,51 @@ void ScummEngine_v100he::o100_setSpriteGroupInfo() {
_sprite->moveGroup(_curSpriteGroupId, value1, value2);
break;
- case 52:
+ case 52: // SO_NAME
copyScriptString(string, sizeof(string));
break;
- case 53:
+ case 53: // SO_NEW
if (!_curSpriteGroupId)
break;
_sprite->resetGroup(_curSpriteGroupId);
break;
- case 54:
+ case 54: // SO_NEW_GENERAL_PROPERTY
// dummy case
pop();
pop();
break;
- case 59:
+ case 59: // SO_PRIORITY
value1 = pop();
if (!_curSpriteGroupId)
break;
_sprite->setGroupPriority(_curSpriteGroupId, value1);
break;
- case 60:
+ case 60: // SO_PROPERTY
type = pop();
value1 = pop();
if (!_curSpriteGroupId)
break;
switch (type) {
- case 0:
+ case 0: // SPRGRPPROP_XMUL
_sprite->setGroupXMul(_curSpriteGroupId, value1);
break;
- case 1:
+ case 1: // SPRGRPPROP_XDIV
_sprite->setGroupXDiv(_curSpriteGroupId, value1);
break;
- case 2:
+ case 2: // SPRGRPPROP_YMUL
_sprite->setGroupYMul(_curSpriteGroupId, value1);
break;
- case 3:
+ case 3: // SPRGRPPROP_YDIV
_sprite->setGroupYDiv(_curSpriteGroupId, value1);
break;
default:
error("o100_setSpriteGroupInfo subOp 60: Unknown case %d", subOp);
}
break;
- case 89:
+ case 89: // SO_NEVER_ZCLIP
if (!_curSpriteGroupId)
break;
@@ -1110,6 +1142,7 @@ void ScummEngine_v100he::o100_resourceRoutines() {
break;
case 128:
// TODO: Clear Heap
+ warning("STUB: o100_resourceRoutines: clear Heap");
break;
case 129:
// Dummy case
@@ -1310,36 +1343,36 @@ void ScummEngine_v100he::o100_wizImageOps() {
if (_wizParams.img.resNum)
_wiz->processWizImage(&_wizParams);
break;
- case 128:
- _wizParams.field_239D = pop();
- _wizParams.field_2399 = pop();
- _wizParams.field_23A5 = pop();
- _wizParams.field_23A1 = pop();
- copyScriptString(_wizParams.string2, sizeof(_wizParams.string2));
+ case 128: // Font create
_wizParams.processMode = 15;
+ _wizParams.fontProperties.bgColor = pop();
+ _wizParams.fontProperties.fgColor = pop();
+ _wizParams.fontProperties.size = pop();
+ _wizParams.fontProperties.style = pop();
+ copyScriptString(_wizParams.fontProperties.fontName, sizeof(_wizParams.fontProperties.fontName));
break;
case 129:
_wizParams.processMode = 14;
break;
- case 130:
+ case 130: // Font render
_wizParams.processMode = 16;
- _wizParams.field_23AD = pop();
- _wizParams.field_23A9 = pop();
- copyScriptString(_wizParams.string1, sizeof(_wizParams.string1));
+ _wizParams.fontProperties.yPos = pop();
+ _wizParams.fontProperties.xPos = pop();
+ copyScriptString(_wizParams.fontProperties.string, sizeof(_wizParams.fontProperties.string));
break;
case 131:
_wizParams.processMode = 13;
break;
- case 133:
+ case 133: // Render ellipse
_wizParams.processMode = 17;
- _wizParams.field_23CD = pop();
- _wizParams.field_23C9 = pop();
- _wizParams.field_23C5 = pop();
- _wizParams.field_23C1 = pop();
- _wizParams.field_23BD = pop();
- _wizParams.field_23B9 = pop();
- _wizParams.field_23B5 = pop();
- _wizParams.field_23B1 = pop();
+ _wizParams.ellipseProperties.color = pop();
+ _wizParams.ellipseProperties.lod = pop();
+ _wizParams.ellipseProperties.ky = pop();
+ _wizParams.ellipseProperties.kx = pop();
+ _wizParams.ellipseProperties.qy = pop();
+ _wizParams.ellipseProperties.qx = pop();
+ _wizParams.ellipseProperties.py = pop();
+ _wizParams.ellipseProperties.px = pop();
break;
case 134:
_wizParams.processFlags |= kWPFFillColor | kWPFClipBox2;
@@ -1584,13 +1617,13 @@ void ScummEngine_v100he::o100_roomOps() {
setPalColor(d, a, b, c);
break;
- case 129:
+ case 129: // SO_OBJECT_ORDER
b = pop();
a = pop();
swapObjects(a, b);
break;
- case 130:
+ case 130: // SO_ROOM_COPY_PALETTE
a = pop();
b = pop();
if (_game.features & GF_16BIT_COLOR)
@@ -1625,7 +1658,7 @@ void ScummEngine_v100he::o100_roomOps() {
setCurrentPalette(a);
break;
- case 135:
+ case 135: // SO_ROOM_PALETTE_IN_ROOM
b = pop();
a = pop();
setRoomPalette(a, b);
@@ -1637,7 +1670,7 @@ void ScummEngine_v100he::o100_roomOps() {
_saveLoadFlag = pop();
break;
- case 137:
+ case 137: // SO_ROOM_SAVEGAME_BY_NAME
byte buffer[256];
copyScriptString((byte *)buffer, sizeof(buffer));
@@ -1781,14 +1814,14 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
byte subOp = fetchScriptByte();
switch (subOp) {
- case 0:
+ case 0: // SO_INIT
_curMaxSpriteId = pop();
_curSpriteId = pop();
if (_curSpriteId > _curMaxSpriteId)
SWAP(_curSpriteId, _curMaxSpriteId);
break;
- case 2:
+ case 2: // SO_ANGLE
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1799,7 +1832,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteAngle(spriteId, args[0]);
break;
- case 3:
+ case 3: // SO_ANIMATION
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1810,7 +1843,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteFlagAutoAnim(spriteId, args[0]);
break;
- case 4:
+ case 4: // SO_ANIMATION_SPEED
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1821,7 +1854,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteAnimSpeed(spriteId, args[0]);
break;
- case 6:
+ case 6: // SO_AT
args[1] = pop();
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
@@ -1833,7 +1866,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpritePosition(spriteId, args[0], args[1]);
break;
- case 7:
+ case 7: // SO_AT_IMAGE
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1844,7 +1877,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteSourceImage(spriteId, args[0]);
break;
- case 16:
+ case 16: // SO_CLASS
n = getStackList(args, ARRAYSIZE(args));
if (_curSpriteId != 0 && _curMaxSpriteId != 0 && n != 0) {
int *p = &args[n - 1];
@@ -1867,7 +1900,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
} while (--n);
}
break;
- case 32:
+ case 32: // SO_ERASE
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1878,7 +1911,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteFlagEraseType(spriteId, args[0]);
break;
- case 38:
+ case 38: // SO_GROUP
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1889,7 +1922,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteGroup(spriteId, args[0]);
break;
- case 40:
+ case 40: // SO_IMAGE
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1900,7 +1933,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteImage(spriteId, args[0]);
break;
- case 48:
+ case 48: // SO_MASK
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1911,7 +1944,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteMaskImage(spriteId, args[0]);
break;
- case 49:
+ case 49: // SO_MOVE
args[1] = pop();
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
@@ -1923,10 +1956,10 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->moveSprite(spriteId, args[0], args[1]);
break;
- case 52:
+ case 52: // SO_NAME
copyScriptString(string, sizeof(string));
break;
- case 53:
+ case 53: // SO_NEW
if (_curSpriteId > _curMaxSpriteId)
break;
spriteId = _curSpriteId;
@@ -1936,7 +1969,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->resetSprite(spriteId);
break;
- case 54:
+ case 54: // SO_NEW_GENERAL_PROPERTY
args[1] = pop();
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
@@ -1948,7 +1981,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteGeneralProperty(spriteId, args[0], args[1]);
break;
- case 57:
+ case 57: // SO_PALETTE
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1959,7 +1992,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpritePalette(spriteId, args[0]);
break;
- case 59:
+ case 59: // SO_PRIORITY
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1970,7 +2003,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpritePriority(spriteId, args[0]);
break;
- case 60:
+ case 60: // SO_PROPERTY
args[1] = pop();
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
@@ -1997,13 +2030,14 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
_sprite->setSpriteFlagRemapPalette(spriteId, args[0]);
break;
default:
+ warning("Unknown sprite property %d for sprite %d", args[0], spriteId);
break;
}
break;
- case 61:
+ case 61: // SO_RESTART
_sprite->resetTables(true);
break;
- case 65:
+ case 65: // SO_SCALE
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -2014,7 +2048,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteScale(spriteId, args[0]);
break;
- case 70:
+ case 70: // SO_SHADOW
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -2025,7 +2059,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteShadow(spriteId, args[0]);
break;
- case 73:
+ case 73: // SO_STATE
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -2036,7 +2070,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteImageState(spriteId, args[0]);
break;
- case 74:
+ case 74: // SO_STEP_DIST
args[1] = pop();
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
@@ -2048,7 +2082,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteDist(spriteId, args[0], args[1]);
break;
- case 75:
+ case 75: // SO_STEP_DIST_X
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -2061,7 +2095,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
_sprite->setSpriteDist(spriteId, args[0], tmp[1]);
}
break;
- case 76:
+ case 76: // SO_STEP_DIST_Y
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -2074,7 +2108,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
_sprite->setSpriteDist(spriteId, tmp[0], args[0]);
}
break;
- case 82:
+ case 82: // SO_UPDATE
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -2085,7 +2119,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteFlagUpdateType(spriteId, args[0]);
break;
- case 83:
+ case 83: // SO_VARIABLE
args[1] = pop();
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
@@ -2097,7 +2131,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteUserValue(spriteId, args[0], args[1]);
break;
- case 88:
+ case 88: // SO_IMAGE_ZCLIP
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -2106,9 +2140,9 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
spriteId++;
for (; spriteId <= _curMaxSpriteId; spriteId++)
- _sprite->setSpriteField84(spriteId, args[0]);
+ _sprite->setSpriteZBuffer(spriteId, args[0]);
break;
- case 89:
+ case 89: // SO_NEVER_ZCLIP
if (_curSpriteId > _curMaxSpriteId)
break;
spriteId = _curSpriteId;
@@ -2116,7 +2150,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
spriteId++;
for (; spriteId <= _curMaxSpriteId; spriteId++)
- _sprite->setSpriteField84(spriteId, 0);
+ _sprite->setSpriteZBuffer(spriteId, 0);
break;
default:
error("o100_setSpriteInfo: Unknown case %d", subOp);
@@ -2235,40 +2269,43 @@ void ScummEngine_v100he::o100_videoOps() {
byte subOp = fetchScriptByte();
switch (subOp) {
- case 0:
+ case 0: // SO_INIT
memset(_videoParams.filename, 0, sizeof(_videoParams.filename));
_videoParams.status = 0;
_videoParams.flags = 0;
- _videoParams.unk2 = pop();
+ _videoParams.number = pop();
_videoParams.wizResNum = 0;
+
+ if (_videoParams.number != 1 && _videoParams.number != -1)
+ warning("o100_videoOps: number: %d", _videoParams.number);
break;
- case 19:
+ case 19: // SO_CLOSE
_videoParams.status = 19;
break;
- case 40:
+ case 40: // SO_IMAGE
_videoParams.wizResNum = pop();
if (_videoParams.wizResNum)
_videoParams.flags |= 2;
break;
- case 47:
+ case 47: // SO_LOAD
copyScriptString(_videoParams.filename, sizeof(_videoParams.filename));
_videoParams.status = 47;
break;
- case 67:
+ case 67: // SO_SET_FLAGS
_videoParams.flags |= pop();
break;
- case 92:
- if (_videoParams.status == 47) {
+ case 92: // SO_END
+ if (_videoParams.status == 47) { // SO_LOAD
// Start video
if (_videoParams.flags == 0)
_videoParams.flags = 4;
- if (_videoParams.flags == 2) {
+ if (_videoParams.flags & 2) {
VAR(119) = _moviePlay->load(convertFilePath(_videoParams.filename), _videoParams.flags, _videoParams.wizResNum);
} else {
VAR(119) = _moviePlay->load(convertFilePath(_videoParams.filename), _videoParams.flags);
}
- } else if (_videoParams.status == 19) {
+ } else if (_videoParams.status == 19) { // SO_CLOSE
// Stop video
_moviePlay->close();
}
@@ -2448,49 +2485,52 @@ void ScummEngine_v100he::o100_getSpriteGroupInfo() {
byte subOp = fetchScriptByte();
+ warning("o100_getSpriteGroupInfo, subop %d", subOp);
+
switch (subOp) {
- case 5:
+ case 5: // SO_ARRAY
spriteGroupId = pop();
if (spriteGroupId)
push(getGroupSpriteArray(spriteGroupId));
else
push(0);
break;
- case 40:
+ case 40: // SO_IMAGE
spriteGroupId = pop();
if (spriteGroupId)
push(_sprite->getGroupDstResNum(spriteGroupId));
else
push(0);
break;
- case 54:
+ case 54: // SO_NEW_GENERAL_PROPERTY
// TODO: U32 related
pop();
pop();
push(0);
+ warning("STUB: o100_getSpriteGroupInfo, subop 54");
break;
- case 59:
+ case 59: // SO_PRIORITY
spriteGroupId = pop();
if (spriteGroupId)
push(_sprite->getGroupPriority(spriteGroupId));
else
push(0);
break;
- case 60:
+ case 60: // SO_PROPERTY
type = pop();
spriteGroupId = pop();
if (spriteGroupId) {
switch (type) {
- case 0:
+ case 0: // SPRGRPPROP_XMUL
push(_sprite->getGroupXMul(spriteGroupId));
break;
- case 1:
+ case 1: // SPRGRPPROP_XDIV
push(_sprite->getGroupXDiv(spriteGroupId));
break;
- case 2:
+ case 2: // SPRGRPPROP_YMUL
push(_sprite->getGroupYMul(spriteGroupId));
break;
- case 3:
+ case 3: // SPRGRPPROP_YDIV
push(_sprite->getGroupYDiv(spriteGroupId));
break;
default:
@@ -2500,7 +2540,7 @@ void ScummEngine_v100he::o100_getSpriteGroupInfo() {
push(0);
}
break;
- case 85:
+ case 85: // SO_XPOS
spriteGroupId = pop();
if (spriteGroupId) {
_sprite->getGroupPosition(spriteGroupId, tx, ty);
@@ -2509,7 +2549,7 @@ void ScummEngine_v100he::o100_getSpriteGroupInfo() {
push(0);
}
break;
- case 86:
+ case 86: // SO_YPOS
spriteGroupId = pop();
if (spriteGroupId) {
_sprite->getGroupPosition(spriteGroupId, tx, ty);
diff --git a/engines/scumm/he/script_v70he.cpp b/engines/scumm/he/script_v70he.cpp
index a911487738..b91943c685 100644
--- a/engines/scumm/he/script_v70he.cpp
+++ b/engines/scumm/he/script_v70he.cpp
@@ -71,6 +71,7 @@ void ScummEngine_v70he::o70_startSound() {
value = pop();
_heSndSoundId = pop();
_sound->addSoundToQueue(_heSndSoundId, 0, 0, 8);
+ break;
case 56:
_heSndFlags |= 16;
break;
diff --git a/engines/scumm/he/script_v72he.cpp b/engines/scumm/he/script_v72he.cpp
index 31b4887d10..d32eb766cb 100644
--- a/engines/scumm/he/script_v72he.cpp
+++ b/engines/scumm/he/script_v72he.cpp
@@ -119,7 +119,7 @@ byte *ScummEngine_v72he::defineArray(int array, int type, int dim2start, int dim
id = findFreeArrayId();
- debug(9,"defineArray (array %d, dim2start %d, dim2end %d dim1start %d dim1end %d", id, dim2start, dim2end, dim1start, dim1end);
+ debug(9, "defineArray (array %d, dim2start %d, dim2end %d dim1start %d dim1end %d", id, dim2start, dim2end, dim1start, dim1end);
if (array & 0x80000000) {
error("Can't define bit variable as array pointer");
@@ -699,13 +699,13 @@ void ScummEngine_v72he::o72_roomOps() {
setCurrentPalette(a);
break;
- case 220:
+ case 220: // SO_ROOM_COPY_PALETTE
a = pop();
b = pop();
copyPalColor(a, b);
break;
- case 221:
+ case 221: // SO_ROOM_SAVEGAME_BY_NAME
byte buffer[256];
copyScriptString((byte *)buffer, sizeof(buffer));
@@ -718,13 +718,13 @@ void ScummEngine_v72he::o72_roomOps() {
_saveTemporaryState = true;
break;
- case 234:
+ case 234: // SO_OBJECT_ORDER
b = pop();
a = pop();
swapObjects(a, b);
break;
- case 236:
+ case 236: // SO_ROOM_PALETTE_IN_ROOM
b = pop();
a = pop();
setRoomPalette(a, b);
@@ -752,43 +752,43 @@ void ScummEngine_v72he::o72_actorOps() {
return;
switch (subOp) {
- case 21: // HE 80+
+ case 21: // SO_CONDITION (HE 80+)
k = getStackList(args, ARRAYSIZE(args));
for (i = 0; i < k; ++i) {
a->setUserCondition(args[i] & 0x7F, args[i] & 0x80);
}
break;
- case 24: // HE 80+
+ case 24: // SO_TALK_CONDITION (HE 80+)
k = pop();
if (k == 0)
k = _rnd.getRandomNumberRng(1, 10);
a->_heNoTalkAnimation = 1;
a->setTalkCondition(k);
break;
- case 43: // HE 90+
+ case 43: // SO_PRIORITY (HE 90+)
a->_layer = pop();
a->_needRedraw = true;
break;
- case 64:
+ case 64: // SO_ACTOR_DEFAULT_CLIPPED
_actorClipOverride.bottom = pop();
_actorClipOverride.right = pop();
_actorClipOverride.top = pop();
_actorClipOverride.left = pop();
adjustRect(_actorClipOverride);
break;
- case 65: // HE 98+
+ case 65: // SO_AT (HE 98+)
j = pop();
i = pop();
a->putActor(i, j);
break;
- case 67: // HE 99+
+ case 67: // SO_CLIPPED (HE 99+)
a->_clipOverride.bottom = pop();
a->_clipOverride.right = pop();
a->_clipOverride.top = pop();
a->_clipOverride.left = pop();
adjustRect(a->_clipOverride);
break;
- case 68: // HE 90+
+ case 68: // // SO_ERASE (HE 90+)
k = pop();
a->setHEFlag(1, k);
break;
@@ -887,10 +887,10 @@ void ScummEngine_v72he::o72_actorOps() {
a->_talkPosY = pop();
a->_talkPosX = pop();
break;
- case 156: // HE 72+
+ case 156: // SO_CHARSET (HE 72+)
a->_charset = pop();
break;
- case 175: // HE 99+
+ case 175: // SO_ROOM_PALETTE (HE 99+)
a->_hePaletteNum = pop();
a->_needRedraw = true;
break;
@@ -907,15 +907,15 @@ void ScummEngine_v72he::o72_actorOps() {
case 217: // SO_ACTOR_NEW
a->initActor(2);
break;
- case 218:
+ case 218: // SO_BACKGROUND_ON
a->drawActorToBackBuf(a->getPos().x, a->getPos().y);
break;
- case 219:
+ case 219: // SO_BACKGROUND_OFF
a->_drawToBackBuf = false;
a->_needRedraw = true;
a->_needBgReset = true;
break;
- case 225:
+ case 225: // SO_TALKIE
{
copyScriptString(string, sizeof(string));
int slot = pop();
@@ -1077,7 +1077,7 @@ void ScummEngine_v72he::o72_arrayOps() {
memcpy(data, string, len);
break;
- case 126:
+ case 126: // SO_COMPLEX_ARRAY_ASSIGNMENT
len = getStackList(list, ARRAYSIZE(list));
dim1end = pop();
dim1start = pop();
@@ -1101,7 +1101,7 @@ void ScummEngine_v72he::o72_arrayOps() {
dim2start++;
}
break;
- case 127:
+ case 127: // SO_COMPLEX_ARRAY_COPY_OPERATION
{
int a2_dim1end = pop();
int a2_dim1start = pop();
@@ -1118,7 +1118,7 @@ void ScummEngine_v72he::o72_arrayOps() {
copyArray(array, a1_dim2start, a1_dim2end, a1_dim1start, a1_dim1end, array2, a2_dim2start, a2_dim2end, a2_dim1start, a2_dim1end);
}
break;
- case 128:
+ case 128: // SO_RANGE_ARRAY_ASSIGNMENT
b = pop();
c = pop();
dim1end = pop();
@@ -1149,7 +1149,7 @@ void ScummEngine_v72he::o72_arrayOps() {
dim2start++;
}
break;
- case 194:
+ case 194: // SO_FORMATTED_STRING
decodeScriptString(string);
len = resStrLen(string);
data = defineArray(array, kStringArray, 0, 0, 0, len);
diff --git a/engines/scumm/he/script_v90he.cpp b/engines/scumm/he/script_v90he.cpp
index f65d2f6077..f63973e3f1 100644
--- a/engines/scumm/he/script_v90he.cpp
+++ b/engines/scumm/he/script_v90he.cpp
@@ -285,29 +285,29 @@ void ScummEngine_v90he::o90_wizImageOps() {
_wizParams.processMode = 13;
break;
case 142: // HE99+
- _wizParams.field_239D = pop();
- _wizParams.field_2399 = pop();
- _wizParams.field_23A5 = pop();
- _wizParams.field_23A1 = pop();
- copyScriptString(_wizParams.string2, sizeof(_wizParams.string2));
_wizParams.processMode = 15;
+ _wizParams.fontProperties.bgColor = pop();
+ _wizParams.fontProperties.fgColor = pop();
+ _wizParams.fontProperties.size = pop();
+ _wizParams.fontProperties.style = pop();
+ copyScriptString(_wizParams.fontProperties.fontName, sizeof(_wizParams.fontProperties.fontName));
break;
case 143: // HE99+
_wizParams.processMode = 16;
- _wizParams.field_23AD = pop();
- _wizParams.field_23A9 = pop();
- copyScriptString(_wizParams.string1, sizeof(_wizParams.string1));
+ _wizParams.fontProperties.yPos = pop();
+ _wizParams.fontProperties.xPos = pop();
+ copyScriptString(_wizParams.fontProperties.string, sizeof(_wizParams.fontProperties.string));
break;
case 189: // HE99+
_wizParams.processMode = 17;
- _wizParams.field_23CD = pop();
- _wizParams.field_23C9 = pop();
- _wizParams.field_23C5 = pop();
- _wizParams.field_23C1 = pop();
- _wizParams.field_23BD = pop();
- _wizParams.field_23B9 = pop();
- _wizParams.field_23B5 = pop();
- _wizParams.field_23B1 = pop();
+ _wizParams.ellipseProperties.color = pop();
+ _wizParams.ellipseProperties.lod = pop();
+ _wizParams.ellipseProperties.ky = pop();
+ _wizParams.ellipseProperties.kx = pop();
+ _wizParams.ellipseProperties.qy = pop();
+ _wizParams.ellipseProperties.qx = pop();
+ _wizParams.ellipseProperties.py = pop();
+ _wizParams.ellipseProperties.px = pop();
break;
case 196: // HE99+
_wizParams.processMode = 14;
@@ -1412,7 +1412,7 @@ void ScummEngine_v90he::o90_videoOps() {
memset(_videoParams.filename, 0, sizeof(_videoParams.filename));
_videoParams.status = 0;
_videoParams.flags = 0;
- _videoParams.unk2 = pop();
+ _videoParams.number = pop();
_videoParams.wizResNum = 0;
break;
case 14:
diff --git a/engines/scumm/he/sound_he.cpp b/engines/scumm/he/sound_he.cpp
index 9a456b86c0..8670116c68 100644
--- a/engines/scumm/he/sound_he.cpp
+++ b/engines/scumm/he/sound_he.cpp
@@ -51,10 +51,12 @@ SoundHE::SoundHE(ScummEngine *parent, Audio::Mixer *mixer)
_heMusicTracks(0) {
memset(_heChannel, 0, sizeof(_heChannel));
+ _heSoundChannels = new Audio::SoundHandle[8]();
}
SoundHE::~SoundHE() {
free(_heMusic);
+ delete[] _heSoundChannels;
}
void SoundHE::addSoundToQueue(int sound, int heOffset, int heChannel, int heFlags) {
@@ -470,6 +472,10 @@ void SoundHE::processSoundOpcodes(int sound, byte *codePtr, int *soundVars) {
if (arg == 2) {
val = getSoundVar(sound, val);
}
+ if (!val) {
+ val = 1; // Safeguard for division by zero
+ warning("Incorrect value 0 for processSoundOpcodes() kludge DIV");
+ }
val = getSoundVar(sound, var) / val;
setSoundVar(sound, var, val);
break;
diff --git a/engines/scumm/he/sound_he.h b/engines/scumm/he/sound_he.h
index 323858a7c9..e0324d0753 100644
--- a/engines/scumm/he/sound_he.h
+++ b/engines/scumm/he/sound_he.h
@@ -44,7 +44,7 @@ protected:
HEMusic *_heMusic;
int16 _heMusicTracks;
- Audio::SoundHandle _heSoundChannels[8];
+ Audio::SoundHandle *_heSoundChannels;
public: // Used by createSound()
struct {
diff --git a/engines/scumm/he/sprite_he.cpp b/engines/scumm/he/sprite_he.cpp
index 245a986531..e3f04dfcf0 100644
--- a/engines/scumm/he/sprite_he.cpp
+++ b/engines/scumm/he/sprite_he.cpp
@@ -386,7 +386,7 @@ int Sprite::getSpriteGeneralProperty(int spriteId, int type) {
case 0x7B:
return _spriteTable[spriteId].imgFlags;
case 0x7D:
- return _spriteTable[spriteId].field_90;
+ return _spriteTable[spriteId].conditionBits;
case 0x7E:
return _spriteTable[spriteId].animProgress;
default:
@@ -739,26 +739,24 @@ void Sprite::setSpriteResetClass(int spriteId) {
_spriteTable[spriteId].classFlags = 0;
}
-void Sprite::setSpriteField84(int spriteId, int value) {
+void Sprite::setSpriteZBuffer(int spriteId, int value) {
assertRange(1, spriteId, _varNumSprites, "sprite");
- _spriteTable[spriteId].field_84 = value;
+ _spriteTable[spriteId].zbufferImage = value;
}
void Sprite::setSpriteGeneralProperty(int spriteId, int type, int value) {
- debug(0, "setSpriteGeneralProperty: spriteId %d type 0x%x", spriteId, type);
+ debug(6, "setSpriteGeneralProperty: spriteId %d type 0x%x value 0x%x", spriteId, type, value);
assertRange(1, spriteId, _varNumSprites, "sprite");
int32 delay;
- // XXX U32 related check
-
switch (type) {
case 0x7B:
_spriteTable[spriteId].imgFlags = value;
_spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw;
break;
case 0x7D:
- _spriteTable[spriteId].field_90 = value;
+ _spriteTable[spriteId].conditionBits = value;
_spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw;
break;
case 0x7E:
@@ -797,9 +795,9 @@ void Sprite::resetSprite(int spriteId) {
_spriteTable[spriteId].sourceImage = 0;
_spriteTable[spriteId].maskImage = 0;
_spriteTable[spriteId].priority = 0;
- _spriteTable[spriteId].field_84 = 0;
+ _spriteTable[spriteId].zbufferImage = 0;
_spriteTable[spriteId].imgFlags = 0;
- _spriteTable[spriteId].field_90 = 0;
+ _spriteTable[spriteId].conditionBits = 0;
if (_vm->_game.heversion >= 100) {
_spriteTable[spriteId].flags &= ~kSFMarkDirty;
@@ -816,7 +814,7 @@ void Sprite::setSpriteImage(int spriteId, int imageNum) {
origResWizStates = _spriteTable[spriteId].imageStateCount;
_spriteTable[spriteId].image = imageNum;
- _spriteTable[spriteId].field_74 = 0;
+ _spriteTable[spriteId].animIndex = 0;
_spriteTable[spriteId].imageState = 0;
if (_spriteTable[spriteId].image) {
@@ -1292,7 +1290,7 @@ void Sprite::processImages(bool arg) {
wiz.spriteId = spi->id;
wiz.spriteGroup = spi->group;
- wiz.field_23EA = spi->field_90;
+ wiz.conditionBits = spi->conditionBits;
spi->curImageState = wiz.img.state = imageState;
spi->curImage = wiz.img.resNum = image;
wiz.processFlags = kWPFNewState | kWPFSetPos;
@@ -1339,9 +1337,9 @@ void Sprite::processImages(bool arg) {
}
if (spr_flags & kSFRemapPalette)
wiz.img.flags |= kWIFRemapPalette;
- if (spi->field_84) {
+ if (spi->zbufferImage) {
wiz.processFlags |= 0x200000;
- wiz.img.field_390 = spi->field_84;
+ wiz.img.zbuffer = spi->zbufferImage;
wiz.img.zorder = spi->priority;
}
if (spi->sourceImage) {
@@ -1419,14 +1417,14 @@ void Sprite::saveOrLoadSpriteData(Serializer *s) {
MKLINE(SpriteInfo, curAngle, sleInt32, VER(48)),
MKLINE(SpriteInfo, curScale, sleInt32, VER(48)),
MKLINE(SpriteInfo, curImgFlags, sleInt32, VER(48)),
- MKLINE(SpriteInfo, field_74, sleInt32, VER(48)),
+ MKLINE(SpriteInfo, animIndex, sleInt32, VER(48)),
MKLINE(SpriteInfo, animSpeed, sleInt32, VER(48)),
MKLINE(SpriteInfo, sourceImage, sleInt32, VER(48)),
MKLINE(SpriteInfo, maskImage, sleInt32, VER(48)),
- MKLINE(SpriteInfo, field_84, sleInt32, VER(48)),
+ MKLINE(SpriteInfo, zbufferImage, sleInt32, VER(48)),
MKLINE(SpriteInfo, classFlags, sleInt32, VER(48)),
MKLINE(SpriteInfo, imgFlags, sleInt32, VER(48)),
- MKLINE(SpriteInfo, field_90, sleInt32, VER(48)),
+ MKLINE(SpriteInfo, conditionBits, sleInt32, VER(48)),
MKEND()
};
diff --git a/engines/scumm/he/sprite_he.h b/engines/scumm/he/sprite_he.h
index e31ccbf790..3ea6bb9f84 100644
--- a/engines/scumm/he/sprite_he.h
+++ b/engines/scumm/he/sprite_he.h
@@ -72,14 +72,14 @@ struct SpriteInfo {
int32 curAngle;
int32 curScale;
int32 curImgFlags;
- int32 field_74;
+ int32 animIndex;
int32 animSpeed;
int32 sourceImage;
int32 maskImage;
- int32 field_84;
+ int32 zbufferImage;
int32 classFlags;
int32 imgFlags;
- int32 field_90;
+ int32 conditionBits;
};
struct SpriteGroup {
@@ -182,7 +182,7 @@ public:
void setSpriteAnimSpeed(int spriteId, int value);
void setSpriteSetClass(int spriteId, int classId, int toggle);
void setSpriteResetClass(int spriteId);
- void setSpriteField84(int spriteId, int value);
+ void setSpriteZBuffer(int spriteId, int value);
void setSpriteGeneralProperty(int spriteId, int type, int value);
void moveGroupMembers(int spriteGroupId, int value1, int value2);
diff --git a/engines/scumm/he/wiz_he.cpp b/engines/scumm/he/wiz_he.cpp
index 9a59609651..d730cb2894 100644
--- a/engines/scumm/he/wiz_he.cpp
+++ b/engines/scumm/he/wiz_he.cpp
@@ -31,6 +31,7 @@
#include "scumm/scumm.h"
#include "scumm/util.h"
#include "scumm/he/wiz_he.h"
+#include "scumm/he/moonbase/moonbase.h"
namespace Scumm {
@@ -976,7 +977,7 @@ void Wiz::decompressRawWizImage(uint8 *dst, int dstPitch, int dstType, const uin
}
}
-int Wiz::isWizPixelNonTransparent(const uint8 *data, int x, int y, int w, int h, uint8 bitDepth) {
+int Wiz::isPixelNonTransparent(const uint8 *data, int x, int y, int w, int h, uint8 bitDepth) {
if (x < 0 || x >= w || y < 0 || y >= h) {
return 0;
}
@@ -1422,19 +1423,19 @@ void Wiz::displayWizImage(WizImage *pwi) {
wi->state = pwi->state;
wi->flags = pwi->flags;
wi->shadow = 0;
- wi->field_390 = 0;
+ wi->zbuffer = 0;
wi->palette = 0;
++_imagesNum;
} else if (pwi->flags & kWIFIsPolygon) {
drawWizPolygon(pwi->resNum, pwi->state, pwi->x1, pwi->flags, 0, 0, 0);
} else {
const Common::Rect *r = NULL;
- drawWizImage(pwi->resNum, pwi->state, 0, 0, pwi->x1, pwi->y1, 0, 0, 0, r, pwi->flags, 0, _vm->getHEPaletteSlot(0));
+ drawWizImage(pwi->resNum, pwi->state, 0, 0, pwi->x1, pwi->y1, 0, 0, 0, r, pwi->flags, 0, _vm->getHEPaletteSlot(0), 0);
}
}
-uint8 *Wiz::drawWizImage(int resNum, int state, int maskNum, int maskState, int x1, int y1, int zorder, int shadow, int field_390, const Common::Rect *clipBox, int flags, int dstResNum, const uint8 *palPtr) {
- debug(3, "drawWizImage(resNum %d, state %d maskNum %d maskState %d x1 %d y1 %d flags 0x%X zorder %d shadow %d field_390 %d dstResNum %d)", resNum, state, maskNum, maskState, x1, y1, flags, zorder, shadow, field_390, dstResNum);
+uint8 *Wiz::drawWizImage(int resNum, int state, int maskNum, int maskState, int x1, int y1, int zorder, int shadow, int zbuffer, const Common::Rect *clipBox, int flags, int dstResNum, const uint8 *palPtr, uint32 conditionBits) {
+ debug(7, "drawWizImage(resNum %d, state %d maskNum %d maskState %d x1 %d y1 %d flags 0x%X zorder %d shadow %d zbuffer %d dstResNum %d conditionBits: 0x%x)", resNum, state, maskNum, maskState, x1, y1, flags, zorder, shadow, zbuffer, dstResNum, conditionBits);
uint8 *dataPtr;
uint8 *dst = NULL;
@@ -1454,10 +1455,7 @@ uint8 *Wiz::drawWizImage(int resNum, int state, int maskNum, int maskState, int
uint32 comp = READ_LE_UINT32(wizh + 0x0);
uint32 width = READ_LE_UINT32(wizh + 0x4);
uint32 height = READ_LE_UINT32(wizh + 0x8);
- debug(3, "wiz_header.comp = %d wiz_header.w = %d wiz_header.h = %d", comp, width, height);
-
- uint8 *wizd = _vm->findWrappedBlock(MKTAG('W','I','Z','D'), dataPtr, state, 0);
- assert(wizd);
+ debug(7, "wiz_header.comp = %d wiz_header.w = %d wiz_header.h = %d", comp, width, height);
uint8 *mask = NULL;
if (maskNum) {
@@ -1574,58 +1572,259 @@ uint8 *Wiz::drawWizImage(int resNum, int state, int maskNum, int maskState, int
transColor = (trns == NULL) ? _vm->VAR(_vm->VAR_WIZ_TCOLOR) : -1;
}
+ if (_vm->_game.id == GID_MOONBASE &&
+ ((ScummEngine_v100he *)_vm)->_moonbase->isFOW(resNum, state, conditionBits)) {
+ ((ScummEngine_v100he *)_vm)->_moonbase->renderFOW(dst, dstPitch, dstType, cw, ch, flags);
+ x1 = 0;
+ y1 = 0;
+ width = rScreen.width();
+ height = rScreen.height();
+ } else {
+ drawWizImageEx(dst, dataPtr, mask, dstPitch, dstType, cw, ch, x1, y1, width, height,
+ state, &rScreen, flags, palPtr, transColor, _vm->_bytesPerPixel, xmapPtr, conditionBits);
+ }
+
+ if (!(flags & kWIFBlitToMemBuffer) && dstResNum == 0) {
+ Common::Rect rImage(x1, y1, x1 + width, y1 + height);
+ if (rImage.intersects(rScreen)) {
+ rImage.clip(rScreen);
+ if (!(flags & kWIFBlitToFrontVideoBuffer) && (flags & (kWIFBlitToFrontVideoBuffer | kWIFMarkBufferDirty))) {
+ ++rImage.bottom;
+ _vm->markRectAsDirty(kMainVirtScreen, rImage);
+ } else {
+ _vm->restoreBackgroundHE(rImage);
+ }
+ }
+ }
+
+ return dst;
+}
+
+void Wiz::drawWizImageEx(uint8 *dst, uint8 *dataPtr, uint8 *maskPtr, int dstPitch, int dstType,
+ int dstw, int dsth, int srcx, int srcy, int srcw, int srch, int state, const Common::Rect *rect,
+ int flags, const uint8 *palPtr, int transColor, uint8 bitDepth, const uint8 *xmapPtr, uint32 conditionBits) {
+ uint8 *wizh = _vm->findWrappedBlock(MKTAG('W','I','Z','H'), dataPtr, state, 0);
+ assert(wizh);
+ uint32 comp = READ_LE_UINT32(wizh + 0x0);
+ uint32 width = READ_LE_UINT32(wizh + 0x4);
+ uint32 height = READ_LE_UINT32(wizh + 0x8);
+ debug(7, "wiz_header.comp = %d wiz_header.w = %d wiz_header.h = %d", comp, width, height);
+
+ uint8 *wizd = _vm->findWrappedBlock(MKTAG('W','I','Z','D'), dataPtr, state, 0);
+ assert(wizd);
+
switch (comp) {
case 0:
- copyRawWizImage(dst, wizd, dstPitch, dstType, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr, transColor, _vm->_bytesPerPixel);
+ copyRawWizImage(dst, wizd, dstPitch, dstType, dstw, dsth, srcx, srcy, srcw, srch, rect, flags, palPtr, transColor, bitDepth);
break;
case 1:
- if (flags & 0x80) {
+ if (flags & kWIFZPlaneOn) {
dst = _vm->getMaskBuffer(0, 0, 1);
dstPitch /= _vm->_bytesPerPixel;
- copyWizImageWithMask(dst, wizd, dstPitch, cw, ch, x1, y1, width, height, &rScreen, 0, 2);
- } else if (flags & 0x100) {
+ copyWizImageWithMask(dst, wizd, dstPitch, dstw, dsth, srcx, srcy, srcw, srch, rect, 0, 2);
+ } else if (flags & kWIFZPlaneOff) {
dst = _vm->getMaskBuffer(0, 0, 1);
dstPitch /= _vm->_bytesPerPixel;
- copyWizImageWithMask(dst, wizd, dstPitch, cw, ch, x1, y1, width, height, &rScreen, 0, 1);
+ copyWizImageWithMask(dst, wizd, dstPitch, dstw, dsth, srcx, srcy, srcw, srch, rect, 0, 1);
} else {
- copyWizImage(dst, wizd, dstPitch, dstType, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr, xmapPtr, _vm->_bytesPerPixel);
+ copyWizImage(dst, wizd, dstPitch, dstType, dstw, dsth, srcx, srcy, srcw, srch, rect, flags, palPtr, xmapPtr, bitDepth);
}
break;
#ifdef USE_RGB_COLOR
case 2:
- if (maskNum) {
- copyMaskWizImage(dst, wizd, mask, dstPitch, dstType, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr);
+ if (maskPtr) {
+ copyMaskWizImage(dst, wizd, maskPtr, dstPitch, dstType, dstw, dsth, srcx, srcy, srcw, srch, rect, flags, palPtr);
} else {
- copyRaw16BitWizImage(dst, wizd, dstPitch, dstType, cw, ch, x1, y1, width, height, &rScreen, flags, transColor);
+ copyRaw16BitWizImage(dst, wizd, dstPitch, dstType, dstw, dsth, srcx, srcy, srcw, srch, rect, flags, transColor);
}
break;
case 4:
- // TODO: Unknown image type
+ copyCompositeWizImage(dst, dataPtr, wizd, maskPtr, dstPitch, dstType, dstw, dsth, srcx, srcy, srcw, srch, state, rect, flags, palPtr, transColor, bitDepth, xmapPtr, conditionBits);
break;
case 5:
- copy16BitWizImage(dst, wizd, dstPitch, dstType, cw, ch, x1, y1, width, height, &rScreen, flags, xmapPtr);
+ copy16BitWizImage(dst, wizd, dstPitch, dstType, dstw, dsth, srcx, srcy, srcw, srch, rect, flags, xmapPtr);
+ break;
+ case 9:
+ copy555WizImage(dst, wizd, dstPitch, dstType, dstw, dsth, srcx, srcy, rect, conditionBits);
break;
#endif
default:
- error("drawWizImage: Unhandled wiz compression type %d", comp);
+ error("drawWizImageEx: Unhandled wiz compression type %d", comp);
}
+}
- if (!(flags & kWIFBlitToMemBuffer) && dstResNum == 0) {
- Common::Rect rImage(x1, y1, x1 + width, y1 + height);
- if (rImage.intersects(rScreen)) {
- rImage.clip(rScreen);
- if (!(flags & kWIFBlitToFrontVideoBuffer) && (flags & (kWIFBlitToFrontVideoBuffer | kWIFMarkBufferDirty))) {
- ++rImage.bottom;
- _vm->markRectAsDirty(kMainVirtScreen, rImage);
- } else {
- _vm->restoreBackgroundHE(rImage);
+#ifdef USE_RGB_COLOR
+
+void Wiz::copyCompositeWizImage(uint8 *dst, uint8 *wizPtr, uint8 *compositeInfoBlockPtr, uint8 *maskPtr, int dstPitch, int dstType,
+ int dstw, int dsth, int srcx, int srcy, int srcw, int srch, int state, const Common::Rect *clipBox,
+ int flags, const uint8 *palPtr, int transColor, uint8 bitDepth, const uint8 *xmapPtr, uint32 conditionBits) {
+
+ uint8 *nestedBlockHeader = _vm->heFindResource(MKTAG('N','E','S','T'), wizPtr);
+ assert(nestedBlockHeader);
+
+ uint8 *nestedWizHeader = _vm->heFindResource(MKTAG('M','U','L','T'), nestedBlockHeader);
+ assert(nestedWizHeader);
+
+ uint16 layerCount = READ_LE_UINT16(compositeInfoBlockPtr);
+ compositeInfoBlockPtr += 2;
+
+ uint16 defaultSubConditionBits = (conditionBits & kWMSBReservedBits);
+
+ conditionBits &= ~kWMSBReservedBits;
+
+ for (uint layerCounter = 0; layerCounter < layerCount; layerCounter++) {
+ int cmdSize = READ_LE_UINT16(compositeInfoBlockPtr);
+ uint8 *cmdPtr = compositeInfoBlockPtr + 2;
+
+ compositeInfoBlockPtr += (cmdSize + 2);
+ uint32 layerCmdDataBits = READ_LE_UINT32(cmdPtr);
+ cmdPtr += 4;
+
+ uint32 subConditionBits;
+
+ if (layerCmdDataBits & kWCFConditionBits) {
+ uint32 layerConditionBits = READ_LE_UINT32(cmdPtr);
+ cmdPtr += 4;
+
+ subConditionBits = (layerConditionBits & kWMSBReservedBits);
+ layerConditionBits &= ~kWMSBReservedBits;
+
+ if (subConditionBits == 0)
+ subConditionBits = defaultSubConditionBits;
+
+ uint32 conditionType = (layerConditionBits & kWSPCCTBits);
+ layerConditionBits &= ~kWSPCCTBits;
+
+ switch (conditionType) {
+ case kWSPCCTAnd:
+ if (layerConditionBits != (layerConditionBits & conditionBits))
+ continue;
+ break;
+
+ case kWSPCCTNot:
+ if (layerConditionBits & conditionBits)
+ continue;
+ break;
+
+ case kWSPCCTOr:
+ default:
+ if (!(layerConditionBits & conditionBits))
+ continue;
+ break;
}
+ } else {
+ subConditionBits = defaultSubConditionBits;
}
+
+ uint16 subState;
+ if (layerCmdDataBits & kWCFSubState) {
+ subState = READ_LE_UINT16(cmdPtr);
+ cmdPtr += 2;
+ } else {
+ subState = 0;
+ }
+
+ int16 xPos;
+ if (layerCmdDataBits & kWCFXDelta) {
+ xPos = (int16)READ_LE_UINT16(cmdPtr);
+ cmdPtr += 2;
+ } else {
+ xPos = 0;
+ }
+
+ int16 yPos;
+ if (layerCmdDataBits & kWCFYDelta) {
+ yPos = (int16)READ_LE_UINT16(cmdPtr);
+ cmdPtr += 2;
+ } else {
+ yPos = 0;
+ }
+
+ uint32 drawFlags;
+ if (layerCmdDataBits & kWCFDrawFlags) {
+ drawFlags = READ_LE_UINT32(cmdPtr);
+ cmdPtr += 4;
+ } else {
+ drawFlags = flags;
+ }
+
+ uint srcw1 = 0, srch1 = 0;
+ if (drawFlags & (kWIFFlipX | kWIFFlipY)) {
+ uint8 *wizh = _vm->findWrappedBlock(MKTAG('W','I','Z','H'), wizPtr, subState, 0);
+ assert(wizh);
+ srcw1 = READ_LE_UINT32(wizh + 0x4);
+ srch1 = READ_LE_UINT32(wizh + 0x8);
+ }
+
+ if (drawFlags & kWIFFlipX)
+ xPos = (srcw - (xPos + srcw1));
+
+ if (drawFlags & kWIFFlipY)
+ yPos = (srch - (yPos + srch1));
+
+ if (layerCmdDataBits & kWCFSubConditionBits) {
+ subConditionBits = READ_LE_UINT32(cmdPtr);
+ cmdPtr += 4;
+ }
+
+ drawWizImageEx(dst, nestedWizHeader, maskPtr, dstPitch, dstType, dstw, dsth, srcx + xPos, srcy + yPos, srcw, srch,
+ subState, clipBox, drawFlags, palPtr, transColor, bitDepth, xmapPtr, subConditionBits);
+ }
+}
+
+void Wiz::copy555WizImage(uint8 *dst, uint8 *wizd, int dstPitch, int dstType,
+ int dstw, int dsth, int srcx, int srcy, const Common::Rect *clipBox, uint32 conditionBits) {
+
+ int rawROP = conditionBits & kWMSBRopMask;
+ int paramROP = (conditionBits & kWMSBReservedBits) >> kWMSBRopParamRShift;
+
+ switch (rawROP) {
+ default:
+ case 1:
+ rawROP = 1;
+ // MMX_PREMUL_ALPHA_COPY
+ break;
+
+ case 2:
+ //warning("T14: MMX_ADDITIVE");
+ break;
+
+ case 3:
+ warning("T14: MMX_SUBTRACTIVE");
+ break;
+
+ case 4:
+ warning("T14: MMX_CONSTANT_ALPHA");
+ break;
+
+ case 5:
+ //warning("T14: MMX_CHEAP_50_50");
+ break;
+
+ case 6:
+ warning("T14: COPY");
+ break;
+
+ case 7:
+ warning("T14: CHEAP_50_50");
+ break;
+ }
+
+
+ uint32 compID = READ_LE_UINT32(wizd);
+
+ if (compID == 0x12340102) {
+ ((ScummEngine_v100he *)_vm)->_moonbase->blitT14WizImage(dst, dstw, dsth, dstPitch, clipBox, wizd, srcx, srcy, rawROP, paramROP);
+ } else if (compID == 0x12340802) {
+ warning("Distorion codec");
+ } else if (compID == 0x12340902) {
+ error("Unsupported Distortion");
}
- return dst;
}
+#endif
+
struct PolygonDrawData {
struct PolygonArea {
int32 xmin;
@@ -1747,7 +1946,7 @@ void Wiz::captureWizPolygon(int resNum, int maskNum, int maskState, int id1, int
assert(maskNum);
const Common::Rect *r = NULL;
- const uint8 *src = drawWizImage(maskNum, maskState, 0, 0, 0, 0, 0, 0, 0, r, kWIFBlitToMemBuffer, 0, 0);
+ const uint8 *src = drawWizImage(maskNum, maskState, 0, 0, 0, 0, 0, 0, 0, r, kWIFBlitToMemBuffer, 0, 0, 0);
getWizImageDim(maskNum, maskState, srcw, srch);
dstw = wp->bound.width();
@@ -1815,7 +2014,7 @@ void Wiz::drawWizPolygonTransform(int resNum, int state, Common::Point *wp, int
debug(0, "drawWizPolygonTransform() unhandled flag 0x800000");
}
- srcWizBuf = drawWizImage(resNum, state, 0, 0, 0, 0, 0, shadow, 0, r, flags, 0, _vm->getHEPaletteSlot(palette));
+ srcWizBuf = drawWizImage(resNum, state, 0, 0, 0, 0, 0, shadow, 0, r, flags, 0, _vm->getHEPaletteSlot(palette), 0);
} else {
assert(_vm->_bytesPerPixel == 1);
uint8 *dataPtr = _vm->getResourceAddress(rtImage, resNum);
@@ -1826,7 +2025,7 @@ void Wiz::drawWizPolygonTransform(int resNum, int state, Common::Point *wp, int
}
} else {
if (getWizImageData(resNum, state, 0) != 0) {
- srcWizBuf = drawWizImage(resNum, state, 0, 0, 0, 0, 0, shadow, 0, r, kWIFBlitToMemBuffer, 0, _vm->getHEPaletteSlot(palette));
+ srcWizBuf = drawWizImage(resNum, state, 0, 0, 0, 0, 0, shadow, 0, r, kWIFBlitToMemBuffer, 0, _vm->getHEPaletteSlot(palette), 0);
} else {
uint8 *dataPtr = _vm->getResourceAddress(rtImage, resNum);
assert(dataPtr);
@@ -2001,7 +2200,7 @@ void Wiz::flushWizBuffer() {
drawWizPolygon(pwi->resNum, pwi->state, pwi->x1, pwi->flags, pwi->shadow, 0, pwi->palette);
} else {
const Common::Rect *r = NULL;
- drawWizImage(pwi->resNum, pwi->state, 0, 0, pwi->x1, pwi->y1, pwi->zorder, pwi->shadow, pwi->field_390, r, pwi->flags, 0, _vm->getHEPaletteSlot(pwi->palette));
+ drawWizImage(pwi->resNum, pwi->state, 0, 0, pwi->x1, pwi->y1, pwi->zorder, pwi->shadow, pwi->zbuffer, r, pwi->flags, 0, _vm->getHEPaletteSlot(pwi->palette), 0);
}
}
_imagesNum = 0;
@@ -2023,7 +2222,7 @@ void Wiz::loadWizCursor(int resId, int palette) {
const Common::Rect *r = NULL;
_cursorImage = true;
- uint8 *cursor = drawWizImage(resId, 0, 0, 0, 0, 0, 0, 0, 0, r, kWIFBlitToMemBuffer, 0, _vm->getHEPaletteSlot(palette));
+ uint8 *cursor = drawWizImage(resId, 0, 0, 0, 0, 0, 0, 0, 0, r, kWIFBlitToMemBuffer, 0, _vm->getHEPaletteSlot(palette), 0);
_cursorImage = false;
int32 cw, ch;
@@ -2073,10 +2272,10 @@ void Wiz::displayWizComplexImage(const WizParameters *params) {
if (params->processFlags & kWPFShadow) {
shadow = params->img.shadow;
}
- int field_390 = 0;
- if (params->processFlags & 0x200000) {
- field_390 = params->img.field_390;
- debug(0, "displayWizComplexImage() unhandled flag 0x200000");
+ int zbuffer = 0;
+ if (params->processFlags & kWPFZBuffer) {
+ zbuffer = params->img.zbuffer;
+ debug(0, "displayWizComplexImage() unhandled flag kWPFZBuffer");
}
const Common::Rect *r = NULL;
if (params->processFlags & kWPFClipBox) {
@@ -2104,19 +2303,19 @@ void Wiz::displayWizComplexImage(const WizParameters *params) {
pwi->state = state;
pwi->flags = flags;
pwi->shadow = shadow;
- pwi->field_390 = field_390;
+ pwi->zbuffer = zbuffer;
pwi->palette = palette;
++_imagesNum;
} else {
if (sourceImage != 0) {
- drawWizImage(params->sourceImage, 0, params->img.resNum, state, po_x, po_y, params->img.zorder, shadow, field_390, r, flags, dstResNum, _vm->getHEPaletteSlot(palette));
+ drawWizImage(params->sourceImage, 0, params->img.resNum, state, po_x, po_y, params->img.zorder, shadow, zbuffer, r, flags, dstResNum, _vm->getHEPaletteSlot(palette), 0);
} else if (params->processFlags & (kWPFScaled | kWPFRotate)) {
drawWizComplexPolygon(params->img.resNum, state, po_x, po_y, shadow, rotationAngle, scale, r, flags, dstResNum, palette);
} else {
if (flags & kWIFIsPolygon) {
drawWizPolygon(params->img.resNum, state, po_x, flags, shadow, dstResNum, palette);
} else {
- drawWizImage(params->img.resNum, state, 0, 0, po_x, po_y, params->img.zorder, shadow, field_390, r, flags, dstResNum, _vm->getHEPaletteSlot(palette));
+ drawWizImage(params->img.resNum, state, 0, 0, po_x, po_y, params->img.zorder, shadow, zbuffer, r, flags, dstResNum, _vm->getHEPaletteSlot(palette), params->conditionBits);
}
}
}
@@ -2501,6 +2700,10 @@ void Wiz::processWizImage(const WizParameters *params) {
void Wiz::getWizImageDim(int resNum, int state, int32 &w, int32 &h) {
uint8 *dataPtr = _vm->getResourceAddress(rtImage, resNum);
assert(dataPtr);
+ getWizImageDim(dataPtr, state, w, h);
+}
+
+void Wiz::getWizImageDim(uint8 *dataPtr, int state, int32 &w, int32 &h) {
uint8 *wizh = _vm->findWrappedBlock(MKTAG('W','I','Z','H'), dataPtr, state, 0);
assert(wizh);
w = READ_LE_UINT32(wizh + 0x4);
@@ -2510,6 +2713,10 @@ void Wiz::getWizImageDim(int resNum, int state, int32 &w, int32 &h) {
void Wiz::getWizImageSpot(int resId, int state, int32 &x, int32 &y) {
uint8 *dataPtr = _vm->getResourceAddress(rtImage, resId);
assert(dataPtr);
+ getWizImageSpot(dataPtr, state, x, y);
+}
+
+void Wiz::getWizImageSpot(uint8 *dataPtr, int state, int32 &x, int32 &y) {
uint8 *spotPtr = _vm->findWrappedBlock(MKTAG('S','P','O','T'), dataPtr, state, 0);
if (spotPtr) {
x = READ_LE_UINT32(spotPtr + 0);
@@ -2547,6 +2754,11 @@ int Wiz::getWizImageData(int resNum, int state, int type) {
int Wiz::getWizImageStates(int resNum) {
const uint8 *dataPtr = _vm->getResourceAddress(rtImage, resNum);
assert(dataPtr);
+
+ return getWizImageStates(dataPtr);
+}
+
+int Wiz::getWizImageStates(const uint8 *dataPtr) {
if (READ_BE_UINT32(dataPtr) == MKTAG('M','U','L','T')) {
const byte *offs, *wrap;
@@ -2565,9 +2777,14 @@ int Wiz::getWizImageStates(int resNum) {
}
int Wiz::isWizPixelNonTransparent(int resNum, int state, int x, int y, int flags) {
- int ret = 0;
uint8 *data = _vm->getResourceAddress(rtImage, resNum);
assert(data);
+
+ return isWizPixelNonTransparent(data, state, x, y, flags);
+}
+
+int Wiz::isWizPixelNonTransparent(uint8 *data, int state, int x, int y, int flags) {
+ int ret = 0;
uint8 *wizh = _vm->findWrappedBlock(MKTAG('W','I','Z','H'), data, state, 0);
assert(wizh);
int c = READ_LE_UINT32(wizh + 0x0);
@@ -2591,19 +2808,20 @@ int Wiz::isWizPixelNonTransparent(int resNum, int state, int x, int y, int flags
}
break;
case 1:
- ret = isWizPixelNonTransparent(wizd, x, y, w, h, 1);
+ ret = isPixelNonTransparent(wizd, x, y, w, h, 1);
break;
#ifdef USE_RGB_COLOR
case 2:
ret = getRawWizPixelColor(wizd, x, y, w, h, 2, _vm->VAR(_vm->VAR_WIZ_TCOLOR)) != _vm->VAR(_vm->VAR_WIZ_TCOLOR) ? 1 : 0;
break;
- case 4:
- // TODO: Unknown image type
- ret = 1;
- debug(0, "isWizPixelNonTransparent: Unhandled wiz compression type %d", c);
+ case 4: {
+ uint16 color = 0xffff;
+ copyCompositeWizImage((byte *)&color, data, wizd, 0, 2, kDstMemory, 1, 1, -x, -y, w, h, state, 0, 0, 0, 0, 2, 0, 0);
+ ret = color != 0xffff;
break;
+ }
case 5:
- ret = isWizPixelNonTransparent(wizd, x, y, w, h, 2);
+ ret = isPixelNonTransparent(wizd, x, y, w, h, 2);
break;
#endif
default:
@@ -2641,8 +2859,7 @@ uint16 Wiz::getWizPixelColor(int resNum, int state, int x, int y) {
color = getRawWizPixelColor(wizd, x, y, w, h, 2, _vm->VAR(_vm->VAR_WIZ_TCOLOR));
break;
case 4:
- // TODO: Unknown image type
- debug(0, "getWizPixelColor: Unhandled wiz compression type %d", c);
+ copyCompositeWizImage((byte *)&color, data, wizd, 0, 2, kDstMemory, 1, 1, -x, -y, w, h, state, 0, 0, 0, 0, 2, 0, 0);
break;
case 5:
color = getWizPixelColor(wizd, x, y, w, h, 2, _vm->VAR(_vm->VAR_WIZ_TCOLOR));
diff --git a/engines/scumm/he/wiz_he.h b/engines/scumm/he/wiz_he.h
index 8db438a074..692ad76db5 100644
--- a/engines/scumm/he/wiz_he.h
+++ b/engines/scumm/he/wiz_he.h
@@ -43,10 +43,32 @@ struct WizImage {
int state;
int flags;
int shadow;
- int field_390;
+ int zbuffer;
int palette;
};
+struct FontProperties {
+ byte string[4096];
+ byte fontName[4096];
+ int fgColor;
+ int bgColor;
+ int style;
+ int size;
+ int xPos;
+ int yPos;
+};
+
+struct EllipseProperties {
+ int px;
+ int py;
+ int qx;
+ int qy;
+ int kx;
+ int ky;
+ int lod;
+ int color;
+};
+
struct WizParameters {
int field_0;
byte filename[260];
@@ -77,27 +99,13 @@ struct WizParameters {
int remapNum;
int dstResNum;
uint16 fillColor;
- byte string1[4096];
- byte string2[4096];
- int field_2399;
- int field_239D;
- int field_23A1;
- int field_23A5;
- int field_23A9;
- int field_23AD;
- int field_23B1;
- int field_23B5;
- int field_23B9;
- int field_23BD;
- int field_23C1;
- int field_23C5;
- int field_23C9;
- int field_23CD;
+ FontProperties fontProperties;
+ EllipseProperties ellipseProperties;
Common::Rect box2;
- int field_23DE;
+ int blendFlags;
int spriteId;
int spriteGroup;
- int field_23EA;
+ int conditionBits;
WizImage img;
};
@@ -109,6 +117,9 @@ enum WizImageFlags {
kWIFMarkBufferDirty = 0x10,
kWIFBlitToMemBuffer = 0x20,
kWIFIsPolygon = 0x40,
+ kWIFZPlaneOn = 0x80,
+ kWIFZPlaneOff = 0x100,
+ kWIFUseShadow = 0x200,
kWIFFlipX = 0x400,
kWIFFlipY = 0x800
};
@@ -130,7 +141,31 @@ enum WizProcessFlags {
kWPFFillColor = 0x20000,
kWPFClipBox2 = 0x40000,
kWPFMaskImg = 0x80000,
- kWPFParams = 0x100000
+ kWPFParams = 0x100000,
+ kWPFZBuffer = 0x200000
+};
+
+enum WizCompositeFlags {
+ kWCFConditionBits = 0x01,
+ kWCFSubState = 0x02,
+ kWCFXDelta = 0x04,
+ kWCFYDelta = 0x08,
+ kWCFDrawFlags = 0x10,
+ kWCFSubConditionBits = 0x20
+};
+
+enum WizSpcConditionTypes {
+ kWSPCCTBits = 0xc0000000,
+ kWSPCCTOr = 0x00000000,
+ kWSPCCTAnd = 0x40000000,
+ kWSPCCTNot = 0x80000000
+};
+
+enum WizMoonSystemBits {
+ kWMSBRopMask = 0xff,
+ kWMSBRopParamMask = 0xff00,
+ kWMSBReservedBits = (kWMSBRopMask | kWMSBRopParamMask),
+ kWMSBRopParamRShift = 8
};
enum {
@@ -185,14 +220,19 @@ public:
void remapWizImagePal(const WizParameters *params);
void getWizImageDim(int resNum, int state, int32 &w, int32 &h);
+ void getWizImageDim(uint8 *dataPtr, int state, int32 &w, int32 &h);
int getWizImageStates(int resnum);
+ int getWizImageStates(const uint8 *ptr);
int isWizPixelNonTransparent(int resnum, int state, int x, int y, int flags);
+ int isWizPixelNonTransparent(uint8 *data, int state, int x, int y, int flags);
+ int isPixelNonTransparent(const uint8 *data, int x, int y, int w, int h, uint8 bitdepth);
uint16 getWizPixelColor(int resnum, int state, int x, int y);
int getWizImageData(int resNum, int state, int type);
void flushWizBuffer();
void getWizImageSpot(int resId, int state, int32 &x, int32 &y);
+ void getWizImageSpot(uint8 *data, int state, int32 &x, int32 &y);
void loadWizCursor(int resId, int palette);
void captureWizImage(int resNum, const Common::Rect& r, bool frontBuffer, int compType);
@@ -202,7 +242,8 @@ public:
void displayWizImage(WizImage *pwi);
void processWizImage(const WizParameters *params);
- uint8 *drawWizImage(int resNum, int state, int maskNum, int maskState, int x1, int y1, int zorder, int shadow, int field_390, const Common::Rect *clipBox, int flags, int dstResNum, const uint8 *palPtr);
+ uint8 *drawWizImage(int resNum, int state, int maskNum, int maskState, int x1, int y1, int zorder, int shadow, int zbuffer, const Common::Rect *clipBox, int flags, int dstResNum, const uint8 *palPtr, uint32 conditionBits);
+ void drawWizImageEx(uint8 *dst, uint8 *src, uint8 *mask, int dstPitch, int dstType, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, int state, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor, uint8 bitDepth, const uint8 *xmapPtr, uint32 conditionBits);
void drawWizPolygon(int resNum, int state, int id, int flags, int shadow, int dstResNum, int palette);
void drawWizComplexPolygon(int resNum, int state, int po_x, int po_y, int shadow, int angle, int zoom, const Common::Rect *r, int flags, int dstResNum, int palette);
void drawWizPolygonTransform(int resNum, int state, Common::Point *wp, int flags, int shadow, int dstResNum, int palette);
@@ -210,6 +251,12 @@ public:
#ifdef USE_RGB_COLOR
static void copyMaskWizImage(uint8 *dst, const uint8 *src, const uint8 *mask, int dstPitch, int dstType, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr);
+
+ void copyCompositeWizImage(uint8 *dst, uint8 *wizPtr, uint8 *wizd, uint8 *maskPtr, int dstPitch, int dstType,
+ int dstw, int dsth, int srcx, int srcy, int srcw, int srch, int state, const Common::Rect *clipBox,
+ int flags, const uint8 *palPtr, int transColor, uint8 bitDepth, const uint8 *xmapPtr, uint32 conditionBits);
+ void copy555WizImage(uint8 *dst, uint8 *wizd, int dstPitch, int dstType,
+ int dstw, int dsth, int srcx, int srcy, const Common::Rect *clipBox, uint32 conditionBits);
#endif
static void copyAuxImage(uint8 *dst1, uint8 *dst2, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, uint8 bitdepth);
@@ -230,7 +277,6 @@ public:
template<int type> static void write8BitColor(uint8 *dst, const uint8 *src, int dstType, const uint8 *palPtr, const uint8 *xmapPtr, uint8 bitDepth);
static void writeColor(uint8 *dstPtr, int dstType, uint16 color);
- int isWizPixelNonTransparent(const uint8 *data, int x, int y, int w, int h, uint8 bitdepth);
uint16 getWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint8 bitDepth, uint16 color);
uint16 getRawWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint8 bitDepth, uint16 color);
void computeWizHistogram(uint32 *histogram, const uint8 *data, const Common::Rect& rCapt);
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index 12047635a0..6ef7e4d7f4 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -24,6 +24,7 @@
#include "common/events.h"
#include "common/system.h"
#include "common/translation.h"
+#include "audio/mixer.h"
#include "scumm/debugger.h"
#include "scumm/dialogs.h"
diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk
index 416a8f7ef9..04611ba1b1 100644
--- a/engines/scumm/module.mk
+++ b/engines/scumm/module.mk
@@ -136,9 +136,19 @@ MODULE_OBJS += \
he/logic/basketball.o \
he/logic/football.o \
he/logic/funshop.o \
- he/logic/moonbase.o \
+ he/logic/moonbase_logic.o \
he/logic/puttrace.o \
- he/logic/soccer.o
+ he/logic/soccer.o \
+ he/moonbase/ai_defenseunit.o \
+ he/moonbase/ai_main.o \
+ he/moonbase/ai_node.o \
+ he/moonbase/ai_targetacquisition.o \
+ he/moonbase/ai_traveller.o \
+ he/moonbase/ai_tree.o \
+ he/moonbase/ai_types.o \
+ he/moonbase/ai_weapon.o \
+ he/moonbase/moonbase.o \
+ he/moonbase/moonbase_fow.o
endif
# This module can be built as a plugin
diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h
index e986ae4b47..68e4887b00 100644
--- a/engines/scumm/scumm-md5.h
+++ b/engines/scumm/scumm-md5.h
@@ -1,5 +1,5 @@
/*
- This file was generated by the md5table tool on Mon Mar 28 09:52:54 2016
+ This file was generated by the md5table tool on Sat Apr 30 14:24:41 2016
DO NOT EDIT MANUALLY!
*/
@@ -532,6 +532,7 @@ static const MD5Table md5table[] = {
{ "bf8b52fdd9a69c67f34e8e9fec72661c", "farm", "HE 71", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows },
{ "bfdf584b01503f0762baded581f6a0a2", "SoccerMLS", "", "", -1, Common::EN_ANY, Common::kPlatformWindows },
{ "c0039ad982999c92d0de81910d640fa0", "freddi", "HE 71", "", 26159, Common::NL_NLD, Common::kPlatformWindows },
+ { "c0c9de81fb965e6cbe77f6e5631ca705", "monkey", "SE Talkie", "Unofficial SE Talkie v1.02", 9135, Common::EN_ANY, Common::kPlatformDOS },
{ "c13225cb1bbd3bc9fe578301696d8021", "monkey", "SEGA", "", -1, Common::EN_ANY, Common::kPlatformSegaCD },
{ "c20848f53c2d48bfacdc840993843765", "freddi2", "HE 80", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown },
{ "c225bec1b6c0798a2b8c89ac226dc793", "pajama", "HE 101", "", -1, Common::EN_ANY, Common::kPlatformWii },
@@ -672,6 +673,7 @@ static const MD5Table md5table[] = {
{ "f3c5d9bf3f091bd1f18dc1013fba5396", "atlantis", "Steam", "Steam", 638976, Common::EN_ANY, Common::kPlatformWindows },
{ "f3d55aea441e260e9e9c7d2a187097e0", "puttzoo", "", "Demo", 14337, Common::EN_ANY, Common::kPlatformWindows },
{ "f40a7f495f59188ca57a9d1d50301bb6", "puttputt", "HE 60", "Demo", -1, Common::EN_ANY, Common::kPlatformMacintosh },
+ { "f4d20ab4ce19743a646cb48bd93aee72", "monkey2", "SE Talkie", "Unofficial SE Talkie v0.2", 10835, Common::EN_ANY, Common::kPlatformDOS },
{ "f5228b0cc1c19e6ea8268ba2eeb61f60", "freddi", "HE 73", "Demo", -1, Common::FR_FRA, Common::kPlatformWindows },
{ "f73883f13b5a302749a5bad31d909780", "tentacle", "", "CD", -1, Common::DE_DEU, Common::kPlatformMacintosh },
{ "f7635a0e2ab82c9a0f9ace5f232a488f", "catalog", "HE 72", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows },
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index e7118616ba..d5727f2a7c 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -66,6 +66,7 @@
#include "scumm/players/player_v5m.h"
#include "scumm/resource.h"
#include "scumm/he/resource_he.h"
+#include "scumm/he/moonbase/moonbase.h"
#include "scumm/scumm_v0.h"
#include "scumm/scumm_v8.h"
#include "scumm/sound.h"
@@ -733,7 +734,7 @@ ScummEngine_v0::ScummEngine_v0(OSystem *syst, const DetectorResult &dr)
VAR_ACTIVE_VERB = 0xFF;
if (strcmp(dr.fp.pattern, "maniacdemo.d64") == 0 )
- _game.features |= GF_DEMO;
+ _game.features |= GF_DEMO;
}
ScummEngine_v6::ScummEngine_v6(OSystem *syst, const DetectorResult &dr)
@@ -874,7 +875,7 @@ ScummEngine_v90he::ScummEngine_v90he(OSystem *syst, const DetectorResult &dr)
memset(_videoParams.filename, 0, sizeof(_videoParams.filename));
_videoParams.status = 0;
_videoParams.flags = 0;
- _videoParams.unk2 = 0;
+ _videoParams.number = 0;
_videoParams.wizResNum = 0;
VAR_NUM_SPRITE_GROUPS = 0xFF;
@@ -897,6 +898,25 @@ ScummEngine_v90he::~ScummEngine_v90he() {
}
}
+ScummEngine_v100he::ScummEngine_v100he(OSystem *syst, const DetectorResult &dr) : ScummEngine_v99he(syst, dr) {
+ /* Moonbase stuff */
+ _moonbase = 0;
+
+ if (_game.id == GID_MOONBASE)
+ _moonbase = new Moonbase(this);
+
+ VAR_U32_USER_VAR_A = 0xFF;
+ VAR_U32_USER_VAR_B = 0xFF;
+ VAR_U32_USER_VAR_C = 0xFF;
+ VAR_U32_USER_VAR_D = 0xFF;
+ VAR_U32_USER_VAR_E = 0xFF;
+ VAR_U32_USER_VAR_F = 0xFF;
+}
+
+ScummEngine_v100he::~ScummEngine_v100he() {
+ delete _moonbase;
+}
+
ScummEngine_vCUPhe::ScummEngine_vCUPhe(OSystem *syst, const DetectorResult &dr) : Engine(syst){
_syst = syst;
_game = dr.game;
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 6e0adc3ff3..f9758aec33 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef SCUMM_H
-#define SCUMM_H
+#ifndef SCUMM_SCUMM_H
+#define SCUMM_SCUMM_H
#include "engines/engine.h"
@@ -704,6 +704,7 @@ protected:
virtual int readVar(uint var);
virtual void writeVar(uint var, int value);
+protected:
void beginCutscene(int *args);
void endCutscene();
void abortCutscene();
diff --git a/engines/scumm/scumm_v2.h b/engines/scumm/scumm_v2.h
index e438008c1e..2a9e7a96e6 100644
--- a/engines/scumm/scumm_v2.h
+++ b/engines/scumm/scumm_v2.h
@@ -77,9 +77,11 @@ protected:
void getResultPosIndirect();
virtual void getResultPos();
+
virtual int readVar(uint var);
virtual void writeVar(uint var, int value);
+protected:
virtual int getActiveObject();
void ifStateCommon(byte type);
void ifNotStateCommon(byte type);
diff --git a/engines/scumm/scumm_v6.h b/engines/scumm/scumm_v6.h
index 73268f6f33..83b9f2f4f8 100644
--- a/engines/scumm/scumm_v6.h
+++ b/engines/scumm/scumm_v6.h
@@ -119,7 +119,10 @@ protected:
ArrayHeader *getArray(int array);
byte *defineArray(int array, int type, int dim2, int dim1);
int findFreeArrayId();
+public: // FIXME. TODO
void nukeArray(int array);
+
+protected:
virtual int readArray(int array, int index, int base);
virtual void writeArray(int array, int index, int base, int value);
void shuffleArray(int num, int minIdx, int maxIdx);
diff --git a/engines/scumm/smush/smush_player.cpp b/engines/scumm/smush/smush_player.cpp
index 2ca2579b54..42ee0115c7 100644
--- a/engines/scumm/smush/smush_player.cpp
+++ b/engines/scumm/smush/smush_player.cpp
@@ -25,6 +25,8 @@
#include "common/system.h"
#include "common/util.h"
+#include "audio/mixer.h"
+
#include "graphics/cursorman.h"
#include "graphics/palette.h"
@@ -242,9 +244,15 @@ SmushPlayer::SmushPlayer(ScummEngine_v7 *scumm) {
_paused = false;
_pauseStartTime = 0;
_pauseTime = 0;
+
+
+ _IACTchannel = new Audio::SoundHandle();
+ _compressedFileSoundHandle = new Audio::SoundHandle();
}
SmushPlayer::~SmushPlayer() {
+ delete _IACTchannel;
+ delete _compressedFileSoundHandle;
}
void SmushPlayer::init(int32 speed) {
@@ -271,8 +279,8 @@ void SmushPlayer::init(int32 speed) {
vs->pitch = vs->w;
_vm->_gdi->_numStrips = vs->w / 8;
- _vm->_mixer->stopHandle(_compressedFileSoundHandle);
- _vm->_mixer->stopHandle(_IACTchannel);
+ _vm->_mixer->stopHandle(*_compressedFileSoundHandle);
+ _vm->_mixer->stopHandle(*_IACTchannel);
_IACTpos = 0;
_vm->_smixer->stop();
}
@@ -470,7 +478,7 @@ void SmushPlayer::handleIACT(int32 subSize, Common::SeekableReadStream &b) {
if (!_IACTstream) {
_IACTstream = Audio::makeQueuingAudioStream(22050, true);
- _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_IACTchannel, _IACTstream);
+ _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, _IACTchannel, _IACTstream);
}
_IACTstream->queueBuffer(output_data, 0x1000, DisposeAfterUse::YES, Audio::FLAG_STEREO | Audio::FLAG_16BITS);
@@ -1091,7 +1099,7 @@ void SmushPlayer::seekSan(const char *file, int32 pos, int32 contFrame) {
}
void SmushPlayer::tryCmpFile(const char *filename) {
- _vm->_mixer->stopHandle(_compressedFileSoundHandle);
+ _vm->_mixer->stopHandle(*_compressedFileSoundHandle);
_compressedFileMode = false;
const char *i = strrchr(filename, '.');
@@ -1110,7 +1118,7 @@ void SmushPlayer::tryCmpFile(const char *filename) {
strcpy(fname + (i - filename), ".ogg");
if (file->open(fname)) {
_compressedFileMode = true;
- _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_compressedFileSoundHandle, Audio::makeVorbisStream(file, DisposeAfterUse::YES));
+ _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, _compressedFileSoundHandle, Audio::makeVorbisStream(file, DisposeAfterUse::YES));
return;
}
#endif
@@ -1119,7 +1127,7 @@ void SmushPlayer::tryCmpFile(const char *filename) {
strcpy(fname + (i - filename), ".mp3");
if (file->open(fname)) {
_compressedFileMode = true;
- _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_compressedFileSoundHandle, Audio::makeMP3Stream(file, DisposeAfterUse::YES));
+ _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, _compressedFileSoundHandle, Audio::makeMP3Stream(file, DisposeAfterUse::YES));
return;
}
#endif
@@ -1185,12 +1193,12 @@ void SmushPlayer::play(const char *filename, int32 speed, int32 offset, int32 st
// the sound. Synt to time instead.
now = _vm->_system->getMillis() - _pauseTime;
elapsed = now - _startTime;
- } else if (_vm->_mixer->isSoundHandleActive(_compressedFileSoundHandle)) {
+ } else if (_vm->_mixer->isSoundHandleActive(*_compressedFileSoundHandle)) {
// Compressed SMUSH files.
- elapsed = _vm->_mixer->getSoundElapsedTime(_compressedFileSoundHandle);
- } else if (_vm->_mixer->isSoundHandleActive(_IACTchannel)) {
+ elapsed = _vm->_mixer->getSoundElapsedTime(*_compressedFileSoundHandle);
+ } else if (_vm->_mixer->isSoundHandleActive(*_IACTchannel)) {
// Curse of Monkey Island SMUSH files.
- elapsed = _vm->_mixer->getSoundElapsedTime(_IACTchannel);
+ elapsed = _vm->_mixer->getSoundElapsedTime(*_IACTchannel);
} else {
// For other SMUSH files, we don't necessarily have any
// one channel to sync against, so we have to use
@@ -1245,8 +1253,8 @@ void SmushPlayer::play(const char *filename, int32 speed, int32 offset, int32 st
break;
if (_vm->shouldQuit() || _vm->_saveLoadFlag || _vm->_smushVideoShouldFinish) {
_smixer->stop();
- _vm->_mixer->stopHandle(_compressedFileSoundHandle);
- _vm->_mixer->stopHandle(_IACTchannel);
+ _vm->_mixer->stopHandle(*_compressedFileSoundHandle);
+ _vm->_mixer->stopHandle(*_IACTchannel);
_IACTpos = 0;
break;
}
diff --git a/engines/scumm/smush/smush_player.h b/engines/scumm/smush/smush_player.h
index b0d6e6a9f0..f1dffef7c7 100644
--- a/engines/scumm/smush/smush_player.h
+++ b/engines/scumm/smush/smush_player.h
@@ -24,9 +24,9 @@
#define SCUMM_SMUSH_PLAYER_H
#include "common/util.h"
-#include "scumm/sound.h"
namespace Audio {
+class SoundHandle;
class QueuingAudioStream;
}
@@ -65,10 +65,10 @@ private:
bool _skipNext;
uint32 _frame;
- Audio::SoundHandle _IACTchannel;
+ Audio::SoundHandle *_IACTchannel;
Audio::QueuingAudioStream *_IACTstream;
- Audio::SoundHandle _compressedFileSoundHandle;
+ Audio::SoundHandle *_compressedFileSoundHandle;
bool _compressedFileMode;
byte _IACToutput[4096];
int32 _IACTpos;
diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp
index f66452e99c..33b7c3108d 100644
--- a/engines/scumm/sound.cpp
+++ b/engines/scumm/sound.cpp
@@ -97,12 +97,17 @@ Sound::Sound(ScummEngine *parent, Audio::Mixer *mixer)
_loomSteamCD.balance = 0;
_isLoomSteam = _vm->_game.id == GID_LOOM && Common::File::exists("CDDA.SOU");
+
+ _loomSteamCDAudioHandle = new Audio::SoundHandle();
+ _talkChannelHandle = new Audio::SoundHandle();
}
Sound::~Sound() {
stopCDTimer();
stopCD();
free(_offsetTable);
+ delete _loomSteamCDAudioHandle;
+ delete _talkChannelHandle;
}
void Sound::addSoundToQueue(int sound, int heOffset, int heChannel, int heFlags) {
@@ -425,7 +430,7 @@ void Sound::processSfxQueues() {
if (_talk_sound_mode & 1)
startTalkSound(_talk_sound_a1, _talk_sound_b1, 1);
if (_talk_sound_mode & 2)
- startTalkSound(_talk_sound_a2, _talk_sound_b2, 2, &_talkChannelHandle);
+ startTalkSound(_talk_sound_a2, _talk_sound_b2, 2, _talkChannelHandle);
_talk_sound_mode = 0;
}
@@ -439,7 +444,7 @@ void Sound::processSfxQueues() {
} else if (_vm->_game.heversion >= 60) {
finished = !isSoundRunning(1);
} else {
- finished = !_mixer->isSoundHandleActive(_talkChannelHandle);
+ finished = !_mixer->isSoundHandleActive(*_talkChannelHandle);
}
if ((uint) act < 0x80 && ((_vm->_game.version == 8) || (_vm->_game.version <= 7 && !_vm->_string[0].no_talk_anim))) {
@@ -675,7 +680,7 @@ void Sound::stopTalkSound() {
} else if (_vm->_game.heversion >= 60) {
stopSound(1);
} else {
- _mixer->stopHandle(_talkChannelHandle);
+ _mixer->stopHandle(*_talkChannelHandle);
}
_sfxMode &= ~2;
}
@@ -1060,7 +1065,7 @@ void Sound::playCDTrackInternal(int track, int numLoops, int startFrame, int dur
g_system->getAudioCDManager()->play(track, numLoops, startFrame, duration);
} else {
// Stop any currently playing track
- _mixer->stopHandle(_loomSteamCDAudioHandle);
+ _mixer->stopHandle(*_loomSteamCDAudioHandle);
Common::File *cddaFile = new Common::File();
if (cddaFile->open("CDDA.SOU")) {
@@ -1068,7 +1073,7 @@ void Sound::playCDTrackInternal(int track, int numLoops, int startFrame, int dur
Audio::Timestamp end = Audio::Timestamp(0, startFrame + duration, 75);
Audio::SeekableAudioStream *stream = makeCDDAStream(cddaFile, DisposeAfterUse::YES);
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_loomSteamCDAudioHandle,
+ _mixer->playStream(Audio::Mixer::kMusicSoundType, _loomSteamCDAudioHandle,
Audio::makeLoopingAudioStream(stream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops));
} else {
delete cddaFile;
@@ -1080,14 +1085,14 @@ void Sound::stopCD() {
if (!_isLoomSteam)
g_system->getAudioCDManager()->stop();
else
- _mixer->stopHandle(_loomSteamCDAudioHandle);
+ _mixer->stopHandle(*_loomSteamCDAudioHandle);
}
int Sound::pollCD() const {
if (!_isLoomSteam)
return g_system->getAudioCDManager()->isPlaying();
else
- return _mixer->isSoundHandleActive(_loomSteamCDAudioHandle);
+ return _mixer->isSoundHandleActive(*_loomSteamCDAudioHandle);
}
void Sound::updateCD() {
@@ -1100,7 +1105,7 @@ AudioCDManager::Status Sound::getCDStatus() {
return g_system->getAudioCDManager()->getStatus();
else {
AudioCDManager::Status info = _loomSteamCD;
- info.playing = _mixer->isSoundHandleActive(_loomSteamCDAudioHandle);
+ info.playing = _mixer->isSoundHandleActive(*_loomSteamCDAudioHandle);
return info;
}
}
diff --git a/engines/scumm/sound.h b/engines/scumm/sound.h
index 8c11c7b5b2..7fdb16371c 100644
--- a/engines/scumm/sound.h
+++ b/engines/scumm/sound.h
@@ -26,10 +26,14 @@
#include "common/scummsys.h"
#include "common/str.h"
#include "audio/mididrv.h"
-#include "audio/mixer.h"
#include "backends/audiocd/audiocd.h"
#include "scumm/saveload.h"
+namespace Audio {
+class Mixer;
+class SoundHandle;
+}
+
namespace Scumm {
class ScummEngine;
@@ -81,12 +85,12 @@ protected:
int16 _currentCDSound;
int16 _currentMusic;
- Audio::SoundHandle _loomSteamCDAudioHandle;
+ Audio::SoundHandle *_loomSteamCDAudioHandle;
bool _isLoomSteam;
AudioCDManager::Status _loomSteamCD;
public:
- Audio::SoundHandle _talkChannelHandle; // Handle of mixer channel actor is talking on
+ Audio::SoundHandle *_talkChannelHandle; // Handle of mixer channel actor is talking on
bool _soundsPaused;
byte _sfxMode;
diff --git a/engines/scumm/string.cpp b/engines/scumm/string.cpp
index 3049fbcf62..e6054918fa 100644
--- a/engines/scumm/string.cpp
+++ b/engines/scumm/string.cpp
@@ -23,6 +23,7 @@
#include "common/config-manager.h"
+#include "audio/mixer.h"
#include "scumm/actor.h"
#include "scumm/charset.h"
@@ -662,7 +663,7 @@ void ScummEngine::CHARSET_1() {
// Special case for HE games
} else if (_game.id == GID_LOOM && !ConfMan.getBool("subtitles") && (_sound->pollCD())) {
// Special case for Loom (CD), since it only uses CD audio.for sound
- } else if (!ConfMan.getBool("subtitles") && (!_haveActorSpeechMsg || _mixer->isSoundHandleActive(_sound->_talkChannelHandle))) {
+ } else if (!ConfMan.getBool("subtitles") && (!_haveActorSpeechMsg || _mixer->isSoundHandleActive(*_sound->_talkChannelHandle))) {
// Subtitles are turned off, and there is a voice version
// of this message -> don't print it.
} else {
diff --git a/engines/scumm/vars.cpp b/engines/scumm/vars.cpp
index a6be5c3f3a..e5ba4a68ee 100644
--- a/engines/scumm/vars.cpp
+++ b/engines/scumm/vars.cpp
@@ -341,6 +341,19 @@ void ScummEngine_v90he::setupScummVars() {
VAR_NUM_UNK = 131;
}
}
+
+void ScummEngine_v100he::setupScummVars() {
+ ScummEngine_v90he::setupScummVars();
+
+ if (_game.id == GID_MOONBASE) {
+ VAR_U32_USER_VAR_A = 108;
+ VAR_U32_USER_VAR_B = 109;
+ VAR_U32_USER_VAR_C = 110;
+ VAR_U32_USER_VAR_D = 111;
+ VAR_U32_USER_VAR_E = 112;
+ VAR_U32_USER_VAR_F = 113;
+ }
+}
#endif
#ifdef ENABLE_SCUMM_7_8
diff --git a/engines/sherlock/fonts.cpp b/engines/sherlock/fonts.cpp
index 5a14881f1c..dc7ecd521e 100644
--- a/engines/sherlock/fonts.cpp
+++ b/engines/sherlock/fonts.cpp
@@ -195,7 +195,7 @@ inline byte Fonts::translateChar(byte c) {
}
}
-void Fonts::writeString(Surface *surface, const Common::String &str,
+void Fonts::writeString(BaseSurface *surface, const Common::String &str,
const Common::Point &pt, int overrideColor) {
Common::Point charPos = pt;
diff --git a/engines/sherlock/fonts.h b/engines/sherlock/fonts.h
index 3594d466c2..6c805447b3 100644
--- a/engines/sherlock/fonts.h
+++ b/engines/sherlock/fonts.h
@@ -31,7 +31,7 @@ namespace Sherlock {
class SherlockEngine;
class ImageFile;
-class Surface;
+class BaseSurface;
class Fonts {
private:
@@ -44,7 +44,7 @@ protected:
static int _widestChar;
static uint16 _charCount;
- static void writeString(Surface *surface, const Common::String &str,
+ static void writeString(BaseSurface *surface, const Common::String &str,
const Common::Point &pt, int overrideColor = 0);
static inline byte translateChar(byte c);
diff --git a/engines/sherlock/image_file.cpp b/engines/sherlock/image_file.cpp
index 1247a7f8d0..c53e537bb8 100644
--- a/engines/sherlock/image_file.cpp
+++ b/engines/sherlock/image_file.cpp
@@ -302,12 +302,6 @@ ImageFile3DO::ImageFile3DO(Common::SeekableReadStream &stream, bool isRoomData)
}
}
-ImageFile3DO::~ImageFile3DO() {
- // already done in ImageFile destructor
- //for (uint idx = 0; idx < size(); ++idx)
- // (*this)[idx]._frame.free();
-}
-
void ImageFile3DO::load(Common::SeekableReadStream &stream, bool isRoomData) {
uint32 headerId = 0;
@@ -380,7 +374,7 @@ void ImageFile3DO::loadAnimationFile(Common::SeekableReadStream &stream) {
if (streamLeft < celDataSize)
error("load3DOAnimationFile: expected cel data, not enough bytes");
- //
+ //
// Load data for frame and decompress it
byte *data = new byte[celDataSize];
stream.read(data, celDataSize);
@@ -683,7 +677,7 @@ void ImageFile3DO::load3DOCelRoomData(Common::SeekableReadStream &stream) {
if (ccbFlags & 0x200) // bit 9
ccbFlags_compressed = true;
-
+
// PRE0 first 3 bits define how many bits per encoded pixel are used
ccbPRE0_bitsPerPixel = imagefile3DO_cel_bitsPerPixelLookupTable[ccbPRE0 & 0x07];
if (!ccbPRE0_bitsPerPixel)
@@ -713,7 +707,7 @@ void ImageFile3DO::load3DOCelRoomData(Common::SeekableReadStream &stream) {
stream.read(celDataPtr, celDataSize);
streamLeft -= celDataSize;
-
+
// Set up frame
{
ImageFrame imageFrame;
diff --git a/engines/sherlock/image_file.h b/engines/sherlock/image_file.h
index 778332b726..0ae7cc1dcb 100644
--- a/engines/sherlock/image_file.h
+++ b/engines/sherlock/image_file.h
@@ -95,7 +95,7 @@ public:
ImageFile();
ImageFile(const Common::String &name, bool skipPal = false, bool animImages = false);
ImageFile(Common::SeekableReadStream &stream, bool skipPal = false);
- ~ImageFile();
+ virtual ~ImageFile();
static void setVm(SherlockEngine *vm);
};
@@ -155,7 +155,6 @@ private:
public:
ImageFile3DO(const Common::String &name, ImageFile3DOType imageFile3DOType);
ImageFile3DO(Common::SeekableReadStream &stream, bool isRoomData = false);
- ~ImageFile3DO();
static void setVm(SherlockEngine *vm);
};
diff --git a/engines/sherlock/scalpel/scalpel_inventory.cpp b/engines/sherlock/scalpel/scalpel_inventory.cpp
index 6eb8c2c05c..07659b41f2 100644
--- a/engines/sherlock/scalpel/scalpel_inventory.cpp
+++ b/engines/sherlock/scalpel/scalpel_inventory.cpp
@@ -109,7 +109,7 @@ void ScalpelInventory::drawInventory(InvNewMode mode) {
_invMode = (InvMode)((int)mode);
if (mode != PLAIN_INVENTORY) {
- assert(mode < sizeof(_hotkeysIndexed));
+ assert((uint)mode < sizeof(_hotkeysIndexed));
ui._oldKey = _hotkeysIndexed[mode];
} else {
ui._oldKey = -1;
diff --git a/engines/sherlock/screen.cpp b/engines/sherlock/screen.cpp
index d96310abb3..a829ab22e6 100644
--- a/engines/sherlock/screen.cpp
+++ b/engines/sherlock/screen.cpp
@@ -40,7 +40,9 @@ Screen *Screen::init(SherlockEngine *vm) {
return new Scalpel::ScalpelScreen(vm);
}
-Screen::Screen(SherlockEngine *vm) : Graphics::Screen(), _vm(vm) {
+Screen::Screen(SherlockEngine *vm) : BaseSurface(), _vm(vm),
+ _backBuffer1(vm->getGameID() == GType_RoseTattoo ? 640 : 320, vm->getGameID() == GType_RoseTattoo ? 480 : 200),
+ _backBuffer2(vm->getGameID() == GType_RoseTattoo ? 640 : 320, vm->getGameID() == GType_RoseTattoo ? 480 : 200) {
_transitionSeed = 1;
_fadeStyle = false;
Common::fill(&_cMap[0], &_cMap[PALETTE_SIZE], 0);
@@ -55,6 +57,7 @@ Screen::Screen(SherlockEngine *vm) : Graphics::Screen(), _vm(vm) {
_oldFadePercent = 0;
_flushScreen = false;
+ create(_backBuffer1.w, _backBuffer1.h);
_backBuffer.create(_backBuffer1, _backBuffer1.getBounds());
}
diff --git a/engines/sherlock/screen.h b/engines/sherlock/screen.h
index f05a4f0a90..fb44c6dde2 100644
--- a/engines/sherlock/screen.h
+++ b/engines/sherlock/screen.h
@@ -25,7 +25,6 @@
#include "common/list.h"
#include "common/rect.h"
-#include "graphics/screen.h"
#include "sherlock/image_file.h"
#include "sherlock/surface.h"
#include "sherlock/resources.h"
@@ -39,7 +38,7 @@ namespace Sherlock {
class SherlockEngine;
-class Screen : virtual public Graphics::Screen, virtual public Surface {
+class Screen : public BaseSurface {
private:
uint32 _transitionSeed;
diff --git a/engines/sherlock/sherlock.h b/engines/sherlock/sherlock.h
index d3b2d0cac8..0b4333ea3a 100644
--- a/engines/sherlock/sherlock.h
+++ b/engines/sherlock/sherlock.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef SHERLOCK_HOLMES_H
-#define SHERLOCK_HOLMES_H
+#ifndef SHERLOCK_SHERLOCK_H
+#define SHERLOCK_SHERLOCK_H
#include "common/scummsys.h"
#include "common/array.h"
diff --git a/engines/sherlock/surface.cpp b/engines/sherlock/surface.cpp
index 47b7d4a780..93bc001149 100644
--- a/engines/sherlock/surface.cpp
+++ b/engines/sherlock/surface.cpp
@@ -25,19 +25,20 @@
namespace Sherlock {
-Surface::Surface() : Graphics::ManagedSurface(), Fonts() {
+BaseSurface::BaseSurface() : Graphics::Screen(0, 0), Fonts() {
+ free(); // Free the 0x0 surface allocated by Graphics::Screen
}
-Surface::Surface(int width, int height) : Graphics::ManagedSurface(width, height),
+BaseSurface::BaseSurface(int width, int height) : Graphics::Screen(width, height),
Fonts() {
create(width, height);
}
-void Surface::writeString(const Common::String &str, const Common::Point &pt, uint overrideColor) {
+void BaseSurface::writeString(const Common::String &str, const Common::Point &pt, uint overrideColor) {
Fonts::writeString(this, str, pt, overrideColor);
}
-void Surface::writeFancyString(const Common::String &str, const Common::Point &pt, uint overrideColor1, uint overrideColor2) {
+void BaseSurface::writeFancyString(const Common::String &str, const Common::Point &pt, uint overrideColor1, uint overrideColor2) {
writeString(str, Common::Point(pt.x, pt.y), overrideColor1);
writeString(str, Common::Point(pt.x + 1, pt.y), overrideColor1);
writeString(str, Common::Point(pt.x + 2, pt.y), overrideColor1);
@@ -49,19 +50,19 @@ void Surface::writeFancyString(const Common::String &str, const Common::Point &p
writeString(str, Common::Point(pt.x + 1, pt.y + 1), overrideColor2);
}
-void Surface::SHtransBlitFrom(const ImageFrame &src, const Common::Point &pt,
+void BaseSurface::SHtransBlitFrom(const ImageFrame &src, const Common::Point &pt,
bool flipped, int overrideColor, int scaleVal) {
Common::Point drawPt(pt.x + src.sDrawXOffset(scaleVal), pt.y + src.sDrawYOffset(scaleVal));
SHtransBlitFrom(src._frame, drawPt, flipped, overrideColor, scaleVal);
}
-void Surface::SHtransBlitFrom(const Graphics::Surface &src, const Common::Point &pt,
+void BaseSurface::SHtransBlitFrom(const Graphics::Surface &src, const Common::Point &pt,
bool flipped, int overrideColor, int scaleVal) {
Common::Rect srcRect(0, 0, src.w, src.h);
Common::Rect destRect(pt.x, pt.y, pt.x + src.w * SCALE_THRESHOLD / scaleVal,
pt.y + src.h * SCALE_THRESHOLD / scaleVal);
- Graphics::ManagedSurface::transBlitFrom(src, srcRect, destRect, TRANSPARENCY,
+ Graphics::Screen::transBlitFrom(src, srcRect, destRect, TRANSPARENCY,
flipped, overrideColor);
}
diff --git a/engines/sherlock/surface.h b/engines/sherlock/surface.h
index 7f946b467f..807fbeb1d1 100644
--- a/engines/sherlock/surface.h
+++ b/engines/sherlock/surface.h
@@ -25,7 +25,7 @@
#include "common/rect.h"
#include "common/platform.h"
-#include "graphics/managed_surface.h"
+#include "graphics/screen.h"
#include "sherlock/fonts.h"
#include "sherlock/image_file.h"
@@ -35,21 +35,21 @@ namespace Sherlock {
#define TRANSPARENCY 255
/**
- * Implements a descendent surface that combines both a managed surface and the font
+ * Implements a base surface that combines both a managed surface and the font
* drawing code. It also introduces a series of drawing method stubs that the 3DO
* Serrated Scalpel screen overrides to implement sprite doubling
*/
-class Surface: virtual public Graphics::ManagedSurface, public Fonts {
+class BaseSurface: public Graphics::Screen, public Fonts {
public:
/**
* Constructor
*/
- Surface();
-
+ BaseSurface();
+
/**
* Constructor
*/
- Surface(int width, int height);
+ BaseSurface(int width, int height);
/**
* Draws a surface on this surface
@@ -95,7 +95,7 @@ public:
* Return the width of the surface
*/
virtual uint16 width() const { return this->w; }
-
+
/**
* Return the height of the surface
*/
@@ -105,13 +105,25 @@ public:
* Draws the given string into the back buffer using the images stored in _font
*/
void writeString(const Common::String &str, const Common::Point &pt, uint overrideColor);
-
+
/**
* Draws a fancy version of the given string at the given position
*/
void writeFancyString(const Common::String &str, const Common::Point &pt, uint overrideColor1, uint overrideColor2);
};
+class Surface : public BaseSurface {
+protected:
+ /**
+ * Override the addDirtyRect from Graphics::Screen, since for standard
+ * surfaces we don't need dirty rects to be tracked
+ */
+ virtual void addDirtyRect(const Common::Rect &r) {}
+public:
+ Surface() : BaseSurface() {}
+ Surface(int w, int h) : BaseSurface(w, h) {}
+};
+
} // End of namespace Sherlock
#endif
diff --git a/engines/sherlock/tattoo/tattoo_fixed_text.h b/engines/sherlock/tattoo/tattoo_fixed_text.h
index 7dbe13bbb3..eb636cdada 100644
--- a/engines/sherlock/tattoo/tattoo_fixed_text.h
+++ b/engines/sherlock/tattoo/tattoo_fixed_text.h
@@ -233,7 +233,7 @@ public:
virtual const Common::String getActionMessage(FixedTextActionId actionId, int messageIndex);
};
-} // End of namespace Scalpel
+} // End of namespace Tattoo
} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/tattoo_journal.cpp b/engines/sherlock/tattoo/tattoo_journal.cpp
index 8e1a61d36e..4d4f37f8d5 100644
--- a/engines/sherlock/tattoo/tattoo_journal.cpp
+++ b/engines/sherlock/tattoo/tattoo_journal.cpp
@@ -50,7 +50,7 @@ void TattooJournal::show() {
Screen &screen = *_vm->_screen;
TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
byte palette[PALETTE_SIZE];
-
+
Common::Point oldScroll = screen._currentScroll;
screen._currentScroll = Common::Point(0, 0);
@@ -66,7 +66,7 @@ void TattooJournal::show() {
// Set screen to black, and set background
screen._backBuffer1.SHblitFrom((*_journalImages)[0], Common::Point(0, 0));
- screen.empty();
+ screen.clear();
screen.setPalette(palette);
if (_journal.empty()) {
@@ -87,12 +87,12 @@ void TattooJournal::show() {
handleKeyboardEvents();
highlightJournalControls(true);
-
+
handleButtons();
if (_wait)
events.wait(2);
-
+
} while (!_vm->shouldQuit() && !_exitJournal);
// Clear events
@@ -275,7 +275,7 @@ void TattooJournal::handleButtons() {
if (frameCounter >= _scrollingTimer) {
// Set next scrolling time
_scrollingTimer = frameCounter + 6;
-
+
// Handle different scrolling actions
switch (_selector) {
case JH_SCROLL_LEFT:
@@ -355,13 +355,13 @@ void TattooJournal::handleButtons() {
_savedIndex = _index;
_savedSub = _sub;
_savedPage = _page;
-
+
bool drawResult = drawJournal(dir + 2, 1000 * LINES_PER_PAGE);
if (!drawResult) {
_index = _savedIndex;
_sub = _savedSub;
_page = _savedPage;
-
+
drawFrame();
drawJournal(0, 0);
notFound = true;
@@ -539,7 +539,7 @@ void TattooJournal::drawControls(int mode) {
_oldSelector = 100;
switch (mode) {
- case 0:
+ case 0:
highlightJournalControls(false);
break;
case 1:
@@ -548,7 +548,7 @@ void TattooJournal::drawControls(int mode) {
default:
break;
}
-
+
_oldSelector = savedSelector;
}
@@ -558,7 +558,7 @@ void TattooJournal::highlightJournalControls(bool slamIt) {
Common::Point mousePos = events.mousePos();
Common::Rect r(JOURNAL_BAR_WIDTH, BUTTON_SIZE + screen.fontHeight() + 13);
r.moveTo((SHERLOCK_SCREEN_WIDTH - r.width()) / 2, SHERLOCK_SCREEN_HEIGHT - r.height());
-
+
if ((events._pressed || events._released) && _selector == JH_THUMBNAIL) {
if (events._released)
_selector = JH_NONE;
@@ -576,7 +576,7 @@ void TattooJournal::highlightJournalControls(bool slamIt) {
_selector = JH_NONE;
if (bounds.contains(mousePos))
_selector = (mousePos.x - r.left) / (r.width() / 3);
-
+
else if (events._pressed && mousePos.y >= (r.top + screen.fontHeight() + 10)
&& mousePos.y < (r.top + screen.fontHeight() + 10 + BUTTON_SIZE)) {
if (mousePos.x >= r.left && mousePos.x < (r.left + BUTTON_SIZE))
@@ -628,7 +628,7 @@ void TattooJournal::highlightJournalControls(bool slamIt) {
color = (_selector == JH_SAVE) ? COMMAND_HIGHLIGHTED : INFO_TOP;
else
color = INFO_BOTTOM;
- screen.gPrint(Common::Point(xp - screen.stringWidth(FIXED(SaveJournal)) / 2, r.top + 5),
+ screen.gPrint(Common::Point(xp - screen.stringWidth(FIXED(SaveJournal)) / 2, r.top + 5),
color, "%s", FIXED(SaveJournal));
// Draw the horizontal scrollbar
@@ -701,7 +701,7 @@ void TattooJournal::drawScrollBar() {
raised = _selector != JH_SCROLL_LEFT;
screen._backBuffer1.fillRect(Common::Rect(r.left, r.top + screen.fontHeight() + 12, r.left + BUTTON_SIZE,
r.top + screen.fontHeight() + BUTTON_SIZE + 9), INFO_MIDDLE);
- ui.drawDialogRect(screen._backBuffer1, Common::Rect(r.left + 3, r.top + screen.fontHeight() + 10, r.left + 3 + BUTTON_SIZE,
+ ui.drawDialogRect(screen._backBuffer1, Common::Rect(r.left + 3, r.top + screen.fontHeight() + 10, r.left + 3 + BUTTON_SIZE,
r.top + screen.fontHeight() + 10 + BUTTON_SIZE), raised);
color = (_page > 1) ? INFO_BOTTOM + 2 : INFO_BOTTOM;
@@ -716,15 +716,15 @@ void TattooJournal::drawScrollBar() {
// Draw the Scroll Right button
raised = _selector != JH_SCROLL_RIGHT;
- screen._backBuffer1.fillRect(Common::Rect(r.right - BUTTON_SIZE - 1, r.top + screen.fontHeight() + 12,
+ screen._backBuffer1.fillRect(Common::Rect(r.right - BUTTON_SIZE - 1, r.top + screen.fontHeight() + 12,
r.right - 5, r.top + screen.fontHeight() + BUTTON_SIZE + 9), INFO_MIDDLE);
ui.drawDialogRect(screen._backBuffer1, Common::Rect(r.right - BUTTON_SIZE - 3, r.top + screen.fontHeight() + 10, r.right - 3,
r.top + screen.fontHeight() + BUTTON_SIZE + 9), raised);
color = _down ? INFO_BOTTOM + 2 : INFO_BOTTOM;
- screen._backBuffer1.vLine(r.right - 1 - BUTTON_SIZE + BUTTON_SIZE / 2, r.top + screen.fontHeight() + 10 + BUTTON_SIZE / 2,
+ screen._backBuffer1.vLine(r.right - 1 - BUTTON_SIZE + BUTTON_SIZE / 2, r.top + screen.fontHeight() + 10 + BUTTON_SIZE / 2,
r.top + screen.fontHeight() + 10 + BUTTON_SIZE / 2, color);
- screen._backBuffer1.vLine(r.right - 2 - BUTTON_SIZE + BUTTON_SIZE / 2, r.top + screen.fontHeight() + 9 + BUTTON_SIZE / 2,
+ screen._backBuffer1.vLine(r.right - 2 - BUTTON_SIZE + BUTTON_SIZE / 2, r.top + screen.fontHeight() + 9 + BUTTON_SIZE / 2,
r.top + screen.fontHeight() + 11 + BUTTON_SIZE / 2, color);
screen._backBuffer1.vLine(r.right - 3 - BUTTON_SIZE + BUTTON_SIZE / 2, r.top + screen.fontHeight() + 8 + BUTTON_SIZE / 2,
r.top + screen.fontHeight() + 12 + BUTTON_SIZE / 2, color);
@@ -776,14 +776,14 @@ int TattooJournal::getFindName(bool printError) {
drawControls(1);
disableControls();
-
+
// Backup the area under the text entry
Surface bgSurface(r.width() - 6, screen.fontHeight());
- bgSurface.SHblitFrom(screen._backBuffer1, Common::Point(0, 0), Common::Rect(r.left + 3, cursorY,
+ bgSurface.SHblitFrom(screen._backBuffer1, Common::Point(0, 0), Common::Rect(r.left + 3, cursorY,
r.right - 3, cursorY + screen.fontHeight()));
if (printError) {
- screen.gPrint(Common::Point(r.left + (r.width() - screen.stringWidth(FIXED(TextNotFound))) / 2, cursorY),
+ screen.gPrint(Common::Point(r.left + (r.width() - screen.stringWidth(FIXED(TextNotFound))) / 2, cursorY),
INFO_TOP, "%s", FIXED(TextNotFound));
} else {
// If there was a name already entered, copy it to name and display it
@@ -977,7 +977,7 @@ void TattooJournal::saveJournal() {
int line = 0;
// Copy all of the talk files entries into one big string
- do {
+ do {
if (_lines[line].hasPrefix("@")) {
text += Common::String(_lines[line].c_str() + 1);
if ((line + 1) < (int)_lines.size() && _lines[line + 1].hasPrefix("@"))
@@ -992,7 +992,7 @@ void TattooJournal::saveJournal() {
// which show up as a blank line with the next line starting
// with a '@'. We have to add a line break here because the '@' handler
// previously assumes that they're always following a blank line
-
+
if ((_lines[line].empty() || _lines[line] == " ")
&& (line + 1) < (int)_lines.size() && _lines[line + 1].hasPrefix("@"))
text += "\n";
@@ -1005,7 +1005,7 @@ void TattooJournal::saveJournal() {
do {
if (text.size() > 80) {
const char *msgP = text.c_str() + 80;
-
+
if (Common::String(text.c_str(), msgP).contains("\n")) {
// The 80 characters contain a carriage return,
// so we can print out that line
@@ -1013,7 +1013,7 @@ void TattooJournal::saveJournal() {
file->writeString(Common::String(text.c_str(), cr));
text = Common::String(cr + 1);
} else {
- // Move backwards to find a word break
+ // Move backwards to find a word break
while (*msgP != ' ')
--msgP;
diff --git a/engines/sherlock/tattoo/tattoo_people.h b/engines/sherlock/tattoo/tattoo_people.h
index e0d53c67dd..c844d86e19 100644
--- a/engines/sherlock/tattoo/tattoo_people.h
+++ b/engines/sherlock/tattoo/tattoo_people.h
@@ -273,9 +273,8 @@ public:
virtual void setListenSequence(int speaker, int sequenceNum = 1);
};
-} // End of namespace Scalpel
+} // End of namespace Tattoo
} // End of namespace Sherlock
-
#endif
diff --git a/engines/sky/control.cpp b/engines/sky/control.cpp
index dfdd765120..9f4b6c21c6 100644
--- a/engines/sky/control.cpp
+++ b/engines/sky/control.cpp
@@ -167,7 +167,7 @@ ControlStatus::~ControlStatus() {
void ControlStatus::setToText(const char *newText) {
char tmpLine[256];
- strcpy(tmpLine, newText);
+ Common::strlcpy(tmpLine, newText, 256);
if (_textData) {
_statusText->flushForRedraw();
free(_textData);
@@ -324,7 +324,11 @@ void Control::initPanel() {
}
void Control::buttonControl(ConResource *pButton) {
- char autoSave[] = "Restore Autosave";
+ char autoSave[50] = "Restore Autosave";
+
+ if (Common::parseLanguage(ConfMan.get("language")) == Common::RU_RUS)
+ strncpy(autoSave, "Zarpyzit/ abtocoxpahehie", 50);
+
if (pButton == NULL) {
free(_textSprite);
_textSprite = NULL;
@@ -398,7 +402,8 @@ void Control::animClick(ConResource *pButton) {
void Control::drawMainPanel() {
memset(_screenBuf, 0, GAME_SCREEN_WIDTH * FULL_SCREEN_HEIGHT);
_system->copyRectToScreen(_screenBuf, GAME_SCREEN_WIDTH, 0, 0, GAME_SCREEN_WIDTH, FULL_SCREEN_HEIGHT);
- _controlPanel->drawToScreen(NO_MASK);
+ if (_controlPanel)
+ _controlPanel->drawToScreen(NO_MASK);
_exitButton->drawToScreen(NO_MASK);
_savePanButton->drawToScreen(NO_MASK);
_restorePanButton->drawToScreen(NO_MASK);
@@ -525,8 +530,13 @@ void Control::doControlPanel() {
}
uint16 Control::handleClick(ConResource *pButton) {
- char quitDos[] = "Quit to DOS?";
- char restart[] = "Restart?";
+ char quitDos[50] = "Quit to DOS?";
+ char restart[50] = "Restart?";
+
+ if (Common::parseLanguage(ConfMan.get("language")) == Common::RU_RUS) {
+ strncpy(quitDos, "B[uti b DOC?", 50);
+ strncpy(restart, "Hobaq irpa?", 50);
+ }
switch (pButton->_onClick) {
case DO_NOTHING:
@@ -1562,8 +1572,13 @@ void Control::showGameQuitMsg() {
screenData = _skyScreen->giveCurrent();
- _skyText->displayText(_quitTexts[SkyEngine::_systemVars.language * 2 + 0], textBuf1, true, 320, 255);
- _skyText->displayText(_quitTexts[SkyEngine::_systemVars.language * 2 + 1], textBuf2, true, 320, 255);
+ if (Common::parseLanguage(ConfMan.get("language")) == Common::RU_RUS) {
+ _skyText->displayText(_quitTexts[8 * 2 + 0], textBuf1, true, 320, 255);
+ _skyText->displayText(_quitTexts[8 * 2 + 1], textBuf2, true, 320, 255);
+ } else {
+ _skyText->displayText(_quitTexts[SkyEngine::_systemVars.language * 2 + 0], textBuf1, true, 320, 255);
+ _skyText->displayText(_quitTexts[SkyEngine::_systemVars.language * 2 + 1], textBuf2, true, 320, 255);
+ }
uint8 *curLine1 = textBuf1 + sizeof(DataFileHeader);
uint8 *curLine2 = textBuf2 + sizeof(DataFileHeader);
uint8 *targetLine = screenData + GAME_SCREEN_WIDTH * 80;
@@ -1584,7 +1599,7 @@ void Control::showGameQuitMsg() {
free(textBuf2);
}
-char Control::_quitTexts[16][35] = {
+char Control::_quitTexts[18][35] = {
"Game over player one",
"BE VIGILANT",
"Das Spiel ist aus.",
@@ -1600,7 +1615,9 @@ char Control::_quitTexts[16][35] = {
"Fim de jogo para o jogador um",
"BE VIGILANT",
"Game over player one",
- "BE VIGILANT"
+ "BE VIGILANT",
+ "Irpa okohseha, irpok 1",
+ "JYD\x96 JDITELEH"
};
uint8 Control::_crossImg[594] = {
diff --git a/engines/sky/control.h b/engines/sky/control.h
index 44591f299d..2089c74363 100644
--- a/engines/sky/control.h
+++ b/engines/sky/control.h
@@ -292,7 +292,7 @@ private:
ControlStatus *_statusBar;
- static char _quitTexts[16][35];
+ static char _quitTexts[18][35];
static uint8 _crossImg[594];
};
diff --git a/engines/sky/sky.h b/engines/sky/sky.h
index 56833004ac..374302b8d3 100644
--- a/engines/sky/sky.h
+++ b/engines/sky/sky.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef SKY_H
-#define SKY_H
+#ifndef SKY_SKY_H
+#define SKY_SKY_H
#include "common/error.h"
diff --git a/engines/sky/skydefs.h b/engines/sky/skydefs.h
index 167b7dade2..ed07a5e2cd 100644
--- a/engines/sky/skydefs.h
+++ b/engines/sky/skydefs.h
@@ -45,6 +45,7 @@ namespace Sky {
#define SKY_ITALIAN 5
#define SKY_PORTUGUESE 6
#define SKY_SPANISH 7
+#define SKY_RUSSIAN 8
#define ST_COLLISION_BIT 5
diff --git a/engines/sword1/resman.cpp b/engines/sword1/resman.cpp
index 0a0324a67c..2f8b37d21c 100644
--- a/engines/sword1/resman.cpp
+++ b/engines/sword1/resman.cpp
@@ -327,13 +327,12 @@ Common::File *ResMan::resFile(uint32 id) {
Clu *closeClu = _openCluStart;
_openCluStart = _openCluStart->nextOpen;
- if (closeClu) {
- if (closeClu->file)
- closeClu->file->close();
- delete closeClu->file;
- closeClu->file = NULL;
- closeClu->nextOpen = NULL;
- }
+ if (closeClu->file)
+ closeClu->file->close();
+ delete closeClu->file;
+ closeClu->file = NULL;
+ closeClu->nextOpen = NULL;
+
_openClus--;
}
}
diff --git a/engines/sword1/sword1.h b/engines/sword1/sword1.h
index eb24ef70fa..8dab522fd0 100644
--- a/engines/sword1/sword1.h
+++ b/engines/sword1/sword1.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef SWORD1_H
-#define SWORD1_H
+#ifndef SWORD1_SWORD1_H
+#define SWORD1_SWORD1_H
#include "engines/engine.h"
#include "common/error.h"
@@ -150,4 +150,4 @@ private:
} // End of namespace Sword1
-#endif //BSSWORD1_H
+#endif // SWORD1_SWORD1_H
diff --git a/engines/sword2/screen.cpp b/engines/sword2/screen.cpp
index 0cb951fdfc..40baf67e46 100644
--- a/engines/sword2/screen.cpp
+++ b/engines/sword2/screen.cpp
@@ -1296,7 +1296,7 @@ void Screen::setPsxScrCache(byte *psxScrCache, uint8 level) {
}
byte *Screen::getPsxScrCache(uint8 level) {
- if (level > 3) {
+ if (level > 2) {
level = 0;
}
@@ -1307,7 +1307,7 @@ byte *Screen::getPsxScrCache(uint8 level) {
}
bool Screen::getPsxScrCacheStatus(uint8 level) {
- if (level > 3) {
+ if (level > 2) {
level = 0;
}
diff --git a/engines/sword2/sword2.h b/engines/sword2/sword2.h
index ef5c2b215e..65d1a955fb 100644
--- a/engines/sword2/sword2.h
+++ b/engines/sword2/sword2.h
@@ -22,8 +22,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef SWORD2_H
-#define SWORD2_H
+#ifndef SWORD2_SWORD2_H
+#define SWORD2_SWORD2_H
#define FRAMES_PER_SECOND 12
diff --git a/engines/sword25/gfx/image/vectorimage.cpp b/engines/sword25/gfx/image/vectorimage.cpp
index a678fdccad..5d35a4f47e 100644
--- a/engines/sword25/gfx/image/vectorimage.cpp
+++ b/engines/sword25/gfx/image/vectorimage.cpp
@@ -217,6 +217,7 @@ Common::Rect CalculateBoundingBox(const VectorImageElement &vectorImageElement)
VectorImage::VectorImage(const byte *pFileData, uint fileSize, bool &success, const Common::String &fname) : _pixelData(0), _fname(fname) {
success = false;
+ _bgColor = 0;
// Create bitstream object
// In the following the file data will be readout of the bitstream object.
diff --git a/engines/sword25/gfx/renderobject.cpp b/engines/sword25/gfx/renderobject.cpp
index c109e49aa8..92d39c252d 100644
--- a/engines/sword25/gfx/renderobject.cpp
+++ b/engines/sword25/gfx/renderobject.cpp
@@ -71,19 +71,18 @@ RenderObject::RenderObject(RenderObjectPtr<RenderObject> parentPtr, TYPES type,
_version(++_nextGlobalVersion),
_isSolid(false) {
- // Renderobject registrieren, abhängig vom Handle-Parameter entweder mit beliebigem oder vorgegebenen Handle.
if (handle == 0)
_handle = RenderObjectRegistry::instance().registerObject(this);
else
_handle = RenderObjectRegistry::instance().registerObject(this, handle);
if (_handle == 0)
- return;
+ error("Failed to initialize RenderObject()");
updateAbsolutePos();
- // Dieses Objekt zu den Kindern der Elternobjektes hinzufügen, falls nicht Wurzel (ParentPtr ungültig) und dem
- // selben RenderObjektManager zuweisen.
+ // Add this item to the children of the parent object, if not root (ParentPtr is invalid),
+ // assign to the same RenderObjectManager.
if (_parentPtr.isValid()) {
_managerPtr = _parentPtr->getManager();
_parentPtr->addObject(this->getHandle());
@@ -100,24 +99,22 @@ RenderObject::RenderObject(RenderObjectPtr<RenderObject> parentPtr, TYPES type,
}
RenderObject::~RenderObject() {
- // Objekt aus dem Elternobjekt entfernen.
+ // Remove object from its parent.
if (_parentPtr.isValid())
_parentPtr->detatchChildren(this->getHandle());
deleteAllChildren();
- // Objekt deregistrieren.
RenderObjectRegistry::instance().deregisterObject(this);
}
void RenderObject::preRender(RenderObjectQueue *renderQueue) {
- // Objektänderungen validieren
validateObject();
if (!_visible)
return;
- // Falls notwendig, wird die Renderreihenfolge der Kinderobjekte aktualisiert.
+ // If necessary, update the children rendering order of the updated objects.
if (_childChanged) {
sortRenderObjects();
_childChanged = false;
@@ -149,7 +146,7 @@ bool RenderObject::render(RectangleList *updateRects, const Common::Array<int> &
if (needRender)
doRender(updateRects);
- // Dann müssen die Kinder gezeichnet werden
+ // Draw all children
RENDEROBJECT_ITER it = _children.begin();
for (; it != _children.end(); ++it)
if (!(*it)->render(updateRects, updateRectsMinZ))
@@ -159,7 +156,6 @@ bool RenderObject::render(RectangleList *updateRects, const Common::Array<int> &
}
void RenderObject::validateObject() {
- // Die Veränderungen in den Objektvariablen aufheben
_oldBbox = _bbox;
_oldVisible = _visible;
_oldX = _x;
@@ -169,15 +165,14 @@ void RenderObject::validateObject() {
}
bool RenderObject::updateObjectState() {
- // Falls sich das Objekt verändert hat, muss der interne Zustand neu berechnet werden und evtl. Update-Regions für den nächsten Frame
- // registriert werden.
+ // If the object has changed, the internal state must be recalculated and possibly
+ // update Regions be registered for the next frame.
if ((calcBoundingBox() != _oldBbox) ||
(_visible != _oldVisible) ||
(_x != _oldX) ||
(_y != _oldY) ||
(_z != _oldZ) ||
_refreshForced) {
- // Renderrang des Objektes neu bestimmen, da sich dieser verändert haben könnte
if (_parentPtr.isValid())
_parentPtr->signalChildChange();
@@ -200,12 +195,10 @@ bool RenderObject::updateObjectState() {
}
void RenderObject::updateBoxes() {
- // Bounding-Box aktualisieren
_bbox = calcBoundingBox();
}
Common::Rect RenderObject::calcBoundingBox() const {
- // Die Bounding-Box mit der Objektgröße initialisieren.
Common::Rect bbox(0, 0, _width, _height);
// Die absolute Position der Bounding-Box berechnen.
@@ -247,8 +240,6 @@ int32 RenderObject::calcAbsoluteZ() const {
}
void RenderObject::deleteAllChildren() {
- // Es ist nicht notwendig die Liste zu iterieren, da jedes Kind für sich DetatchChildren an diesem Objekt aufruft und sich somit
- // selber entfernt. Daher muss immer nur ein beliebiges Element (hier das letzte) gelöscht werden, bis die Liste leer ist.
while (!_children.empty()) {
RenderObjectPtr<RenderObject> curPtr = _children.back();
curPtr.erase();
@@ -261,10 +252,10 @@ bool RenderObject::addObject(RenderObjectPtr<RenderObject> pObject) {
return false;
}
- // Objekt in die Kinderliste einfügen.
+ // Insert Object in the children list.
_children.push_back(pObject);
- // Sicherstellen, dass vor dem nächsten Rendern die Renderreihenfolge aktualisiert wird.
+ // Make sure that before the next render the channel order is updated.
if (_parentPtr.isValid())
_parentPtr->signalChildChange();
diff --git a/engines/sword25/package/packagemanager.cpp b/engines/sword25/package/packagemanager.cpp
index 457dda6268..87bedcc9c1 100644
--- a/engines/sword25/package/packagemanager.cpp
+++ b/engines/sword25/package/packagemanager.cpp
@@ -82,7 +82,7 @@ Common::String PackageManager::ensureSpeechLang(const Common::String &fileName)
return fileName;
Common::String newFileName = "/speech/en";
- int fileIdx = 9;
+ uint fileIdx = 9;
while (fileIdx < fileName.size() && fileName[fileIdx] != '/')
++fileIdx;
if (fileIdx < fileName.size())
diff --git a/engines/sword25/sword25.h b/engines/sword25/sword25.h
index 72391cf9d8..c08f20e3b3 100644
--- a/engines/sword25/sword25.h
+++ b/engines/sword25/sword25.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef SWORD25_H
-#define SWORD25_H
+#ifndef SWORD25_SWORD25_H
+#define SWORD25_SWORD25_H
#include "common/scummsys.h"
#include "engines/engine.h"
diff --git a/engines/teenagent/music.cpp b/engines/teenagent/music.cpp
index 5d66c3c90c..795b8f7312 100644
--- a/engines/teenagent/music.cpp
+++ b/engines/teenagent/music.cpp
@@ -36,7 +36,7 @@ static const uint32 noteToPeriod[3][12] = {
{214, 201, 189, 179, 170, 160, 151, 143, 135, 127, 120, 113}
};
-MusicPlayer::MusicPlayer(TeenAgentEngine *vm) : Paula(false, 44100, 5000), _vm(vm), _id(0) {
+MusicPlayer::MusicPlayer(TeenAgentEngine *vm) : Paula(false, 44100, 5000), _vm(vm), _id(0), _currRow(0) {
}
MusicPlayer::~MusicPlayer() {
@@ -55,7 +55,7 @@ bool MusicPlayer::load(int id) {
Common::StackLock lock(_mutex);
// Load the samples
- sampleCount = stream->readByte();
+ byte sampleCount = stream->readByte();
debugC(0, kDebugMusic, "sampleCount = %d", sampleCount);
diff --git a/engines/teenagent/music.h b/engines/teenagent/music.h
index e1630cc845..4b1b683a30 100644
--- a/engines/teenagent/music.h
+++ b/engines/teenagent/music.h
@@ -74,7 +74,6 @@ private:
size = 0;
}
} _samples[256];
- byte sampleCount;
Common::Array<Row> _rows;
uint _currRow;
diff --git a/engines/teenagent/objects.h b/engines/teenagent/objects.h
index f923ae52ab..1f8a82a66e 100644
--- a/engines/teenagent/objects.h
+++ b/engines/teenagent/objects.h
@@ -165,7 +165,7 @@ struct Object {
//19
Common::String name, description;
- Object(): _base(NULL) {}
+ Object(): _base(NULL) { id = 0; actorOrientation = 0; enabled = 0; }
void dump(int level = 0) const;
void setName(const Common::String &newName);
void load(byte *addr);
@@ -205,7 +205,7 @@ struct Walkbox {
Rect rect;
byte sideHint[4];
- Walkbox() : _base(NULL) {}
+ Walkbox() : _base(NULL) { memset(this, 0, sizeof(Walkbox)); }
void dump(int level = 0) const;
void load(byte *src);
void save() const;
diff --git a/engines/teenagent/scene.cpp b/engines/teenagent/scene.cpp
index 6e1cef31bc..c250269844 100644
--- a/engines/teenagent/scene.cpp
+++ b/engines/teenagent/scene.cpp
@@ -71,6 +71,9 @@ Scene::Scene(TeenAgentEngine *vm) : _vm(vm), intro(false), _id(0), ons(0),
varia.close();
loadObjectData();
+
+ _onsCount = 0;
+ _messageColor = 0;
}
Scene::~Scene() {
@@ -314,7 +317,7 @@ void Scene::loadOns() {
uint16 addr = _vm->res->dseg.get_word(dsAddr_onsAnimationTablePtr + (_id - 1) * 2);
debugC(0, kDebugScene, "ons index: %04x", addr);
- onsCount = 0;
+ _onsCount = 0;
byte b;
byte onId[16];
while ((b = _vm->res->dseg.get_byte(addr)) != 0xff) {
@@ -323,15 +326,15 @@ void Scene::loadOns() {
if (b == 0)
continue;
- onId[onsCount++] = b;
+ onId[_onsCount++] = b;
}
delete[] ons;
ons = NULL;
- if (onsCount > 0) {
- ons = new Surface[onsCount];
- for (uint32 i = 0; i < onsCount; ++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);
@@ -498,7 +501,7 @@ bool Scene::processEvent(const Common::Event &event) {
events.clear();
sounds.clear();
currentEvent.clear();
- messageColor = textColorMark;
+ _messageColor = textColorMark;
for (int i = 0; i < 4; ++i)
customAnimation[i].free();
_vm->playMusic(4);
@@ -651,7 +654,7 @@ bool Scene::render(bool tickGame, bool tickMark, uint32 messageDelta) {
bool gotAnyAnimation = false;
if (ons != NULL && debugFeatures.feature[DebugFeatures::kShowOns]) {
- for (uint32 i = 0; i < onsCount; ++i) {
+ for (uint32 i = 0; i < _onsCount; ++i) {
Surface *s = ons + i;
if (s != NULL)
s->render(surface);
@@ -821,7 +824,7 @@ bool Scene::render(bool tickGame, bool tickMark, uint32 messageDelta) {
}
if (visible) {
- _vm->res->font7.render(surface, messagePos.x, messagePos.y, message, messageColor);
+ _vm->res->font7.render(surface, messagePos.x, messagePos.y, message, _messageColor);
busy = true;
}
}
@@ -1005,7 +1008,7 @@ bool Scene::processEventQueue() {
warning("no animation in slot %u", messageSlot);
}
messagePos = messagePosition(message, p);
- messageColor = currentEvent.color;
+ _messageColor = currentEvent.color;
if (messageFirstFrame)
currentEvent.clear(); // async message, clearing event
@@ -1153,7 +1156,7 @@ bool Scene::processEventQueue() {
}
if (events.empty()) {
- messageColor = textColorMark;
+ _messageColor = textColorMark;
hideActor = false;
}
@@ -1232,7 +1235,7 @@ void Scene::displayMessage(const Common::String &str, byte color, const Common::
debugC(0, kDebugScene, "displayMessage: %s", str.c_str());
message = str;
messagePos = (pos.x | pos.y) ? pos : messagePosition(str, position);
- messageColor = color;
+ _messageColor = color;
messageTimer = messageDuration(message);
}
@@ -1251,7 +1254,7 @@ void Scene::clear() {
void Scene::clearMessage() {
message.clear();
messageTimer = 0;
- messageColor = textColorMark;
+ _messageColor = textColorMark;
messageFirstFrame = 0;
messageLastFrame = 0;
messageAnimation = NULL;
diff --git a/engines/teenagent/scene.h b/engines/teenagent/scene.h
index 07b304ed97..40f910a3aa 100644
--- a/engines/teenagent/scene.h
+++ b/engines/teenagent/scene.h
@@ -194,7 +194,7 @@ private:
SurfaceList on;
bool onEnabled;
Surface *ons;
- uint32 onsCount;
+ uint32 _onsCount;
Animation actorAnimation, animation[4], customAnimation[4];
Common::Rect actorAnimationPosition, animationPosition[4];
@@ -214,7 +214,7 @@ private:
Common::String message;
Common::Point messagePos;
- byte messageColor;
+ byte _messageColor;
uint messageTimer;
byte messageFirstFrame;
byte messageLastFrame;
diff --git a/engines/teenagent/teenagent.cpp b/engines/teenagent/teenagent.cpp
index 4dc785754c..2d10b82f51 100644
--- a/engines/teenagent/teenagent.cpp
+++ b/engines/teenagent/teenagent.cpp
@@ -71,6 +71,13 @@ TeenAgentEngine::TeenAgentEngine(OSystem *system, const ADGameDescription *gd)
res = new Resources();
console = 0;
+ scene = 0;
+ inventory = 0;
+ _sceneBusy = false;
+ _dstObject = 0;
+ _musicStream = 0;
+ _markDelay = 0;
+ _gameDelay = 0;
}
TeenAgentEngine::~TeenAgentEngine() {
diff --git a/engines/teenagent/teenagent.h b/engines/teenagent/teenagent.h
index 234bfb1c57..438f06d189 100644
--- a/engines/teenagent/teenagent.h
+++ b/engines/teenagent/teenagent.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef TEENAGENT_ENGINE_H
-#define TEENAGENT_ENGINE_H
+#ifndef TEENAGENT_TEENAGENT_H
+#define TEENAGENT_TEENAGENT_H
#include "engines/engine.h"
diff --git a/engines/testbed/testbed.h b/engines/testbed/testbed.h
index 0f70e1191f..5ea05feba2 100644
--- a/engines/testbed/testbed.h
+++ b/engines/testbed/testbed.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef TESTBED_H
-#define TESTBED_H
+#ifndef TESTBED_TESTBED_H
+#define TESTBED_TESTBED_H
#include "common/array.h"
@@ -72,4 +72,4 @@ private:
} // End of namespace Testbed
-#endif // TESTBED_H
+#endif // TESTBED_TESTBED_H
diff --git a/engines/tinsel/bmv.cpp b/engines/tinsel/bmv.cpp
index 22c3798fc6..cfe97e6ec1 100644
--- a/engines/tinsel/bmv.cpp
+++ b/engines/tinsel/bmv.cpp
@@ -567,8 +567,8 @@ void BMVPlayer::PlayBMV(CORO_PARAM, SCNHANDLE hFileStem, int myEscape) {
assert(!bMovieOn);
- strcpy(szMovieFile, (char *)LockMem(hFileStem));
- strcat(szMovieFile, BMOVIE_EXTENSION);
+ Common::strlcpy(szMovieFile, (char *)LockMem(hFileStem), 14);
+ Common::strlcat(szMovieFile, BMOVIE_EXTENSION, 14);
assert(strlen(szMovieFile) <= 12);
diff --git a/engines/tinsel/detection.cpp b/engines/tinsel/detection.cpp
index 2fde6e788a..c44f1f4ef3 100644
--- a/engines/tinsel/detection.cpp
+++ b/engines/tinsel/detection.cpp
@@ -235,7 +235,7 @@ const ADGameDescription *TinselMetaEngine::fallbackDetect(const FileMap &allFile
for (fileDesc = g->desc.filesDescriptions; fileDesc->fileName; fileDesc++) {
// Get the next filename, stripping off any '1' suffix character
char tempFilename[50];
- strcpy(tempFilename, fileDesc->fileName);
+ Common::strlcpy(tempFilename, fileDesc->fileName, 50);
char *pOne = strchr(tempFilename, '1');
if (pOne) {
do {
@@ -275,7 +275,7 @@ const ADGameDescription *TinselMetaEngine::fallbackDetect(const FileMap &allFile
for (fileDesc = g->desc.filesDescriptions; fileDesc->fileName; fileDesc++) {
// Get the next filename, stripping off any '1' suffix character
char tempFilename[50];
- strcpy(tempFilename, fileDesc->fileName);
+ Common::strlcpy(tempFilename, fileDesc->fileName, 50);
char *pOne = strchr(tempFilename, '1');
if (pOne) {
do {
diff --git a/engines/tinsel/dialogs.cpp b/engines/tinsel/dialogs.cpp
index a84dad942c..b5d090ec15 100644
--- a/engines/tinsel/dialogs.cpp
+++ b/engines/tinsel/dialogs.cpp
@@ -1671,10 +1671,10 @@ static void Select(int i, bool force) {
#else
// Current description with cursor appended
if (cd.box[i].boxText != NULL) {
- strcpy(g_sedit, cd.box[i].boxText);
- strcat(g_sedit, sCursor);
+ Common::strlcpy(g_sedit, cd.box[i].boxText, SG_DESC_LEN+2);
+ Common::strlcat(g_sedit, sCursor, SG_DESC_LEN+2);
} else {
- strcpy(g_sedit, sCursor);
+ Common::strlcpy(g_sedit, sCursor, SG_DESC_LEN+2);
}
#endif
@@ -3676,13 +3676,13 @@ extern void HideConversation(bool bHide) {
ConstructInventory(FULL);
else {
// Move it all back on-screen
- for (i = 0; g_objArray[i] && i < MAX_WCOMP; i++) {
+ for (i = 0; i < MAX_WCOMP && g_objArray[i]; i++) {
MultiAdjustXY(g_objArray[i], -2 * SCREEN_WIDTH, 0);
}
// Don't flash if items changed. If they have, will be redrawn anyway.
if (TinselV2 || !g_ItemsChanged) {
- for (i = 0; g_iconArray[i] && i < MAX_ICONS; i++) {
+ for (i = 0; i < MAX_ICONS && g_iconArray[i]; i++) {
MultiAdjustXY(g_iconArray[i], -2*SCREEN_WIDTH, 0);
}
}
@@ -3739,10 +3739,10 @@ extern void HideConversation(bool bHide) {
deltay = g_InvD[INV_CONV].inventoryY - deltay;
// Move it all
- for (i = 0; g_objArray[i] && i < MAX_WCOMP; i++) {
+ for (i = 0; i < MAX_WCOMP && g_objArray[i]; i++) {
MultiMoveRelXY(g_objArray[i], x - center, deltay);
}
- for (i = 0; g_iconArray[i] && i < MAX_ICONS; i++) {
+ for (i = 0; i < MAX_ICONS && g_iconArray[i]; i++) {
MultiMoveRelXY(g_iconArray[i], x - center, deltay);
}
g_InvD[INV_CONV].inventoryX += x - center;
@@ -3771,10 +3771,10 @@ extern void HideConversation(bool bHide) {
y = 0;
if (x || y) {
- for (i = 0; g_objArray[i] && i < MAX_WCOMP; i++) {
+ for (i = 0; i < MAX_WCOMP && g_objArray[i]; i++) {
MultiMoveRelXY(g_objArray[i], x, y);
}
- for (i = 0; g_iconArray[i] && i < MAX_ICONS; i++) {
+ for (i = 0; i < MAX_ICONS && g_iconArray[i]; i++) {
MultiMoveRelXY(g_iconArray[i], x, y);
}
g_InvD[INV_CONV].inventoryX += x;
@@ -3786,10 +3786,10 @@ extern void HideConversation(bool bHide) {
*/
if (MultiLowest(g_RectObject) > SCREEN_BOX_HEIGHT2 - SysVar(SV_CONV_MINY)) {
y = (SCREEN_BOX_HEIGHT2 - SysVar(SV_CONV_MINY)) - MultiLowest(g_RectObject);
- for (i = 0; g_objArray[i] && i < MAX_WCOMP; i++) {
+ for (i = 0; i < MAX_WCOMP && g_objArray[i]; i++) {
MultiMoveRelXY(g_objArray[i], 0, y);
}
- for (i = 0; g_iconArray[i] && i < MAX_ICONS; i++) {
+ for (i = 0; i < MAX_ICONS && g_iconArray[i]; i++) {
MultiMoveRelXY(g_iconArray[i], 0, y);
}
g_InvD[INV_CONV].inventoryY += y;
@@ -4617,9 +4617,9 @@ extern void Xmovement(int x) {
GetAniPosition(g_objArray[0], &g_InvD[g_ino].inventoryX, &aniY);
g_InvD[g_ino].inventoryX +=x;
MultiSetAniX(g_objArray[0], g_InvD[g_ino].inventoryX);
- for (i = 1; g_objArray[i] && i < MAX_WCOMP; i++)
+ for (i = 1; i < MAX_WCOMP && g_objArray[i]; i++)
MultiMoveRelXY(g_objArray[i], x, 0);
- for (i = 0; g_iconArray[i] && i < MAX_ICONS; i++)
+ for (i = 0; i < MAX_ICONS && g_iconArray[i]; i++)
MultiMoveRelXY(g_iconArray[i], x, 0);
break;
@@ -4665,9 +4665,9 @@ extern void Ymovement(int y) {
GetAniPosition(g_objArray[0], &aniX, &g_InvD[g_ino].inventoryY);
g_InvD[g_ino].inventoryY +=y;
MultiSetAniY(g_objArray[0], g_InvD[g_ino].inventoryY);
- for (i = 1; g_objArray[i] && i < MAX_WCOMP; i++)
+ for (i = 1; i < MAX_WCOMP && g_objArray[i]; i++)
MultiMoveRelXY(g_objArray[i], 0, y);
- for (i = 0; g_iconArray[i] && i < MAX_ICONS; i++)
+ for (i = 0; i < MAX_ICONS && g_iconArray[i]; i++)
MultiMoveRelXY(g_iconArray[i], 0, y);
break;
diff --git a/engines/tinsel/handle.cpp b/engines/tinsel/handle.cpp
index 62d244e449..9ffd477c4a 100644
--- a/engines/tinsel/handle.cpp
+++ b/engines/tinsel/handle.cpp
@@ -258,7 +258,7 @@ void LoadExtraGraphData(SCNHANDLE start, SCNHANDLE next) {
}
void SetCdPlaySceneDetails(int fileNum, const char *fileName) {
- strcpy(g_szCdPlayFile, fileName);
+ Common::strlcpy(g_szCdPlayFile, fileName, 100);
}
void SetCdPlayHandle(int fileNum) {
diff --git a/engines/tinsel/saveload.cpp b/engines/tinsel/saveload.cpp
index 88cd80b78a..226cbb51c0 100644
--- a/engines/tinsel/saveload.cpp
+++ b/engines/tinsel/saveload.cpp
@@ -563,7 +563,7 @@ static void DoSave() {
while (1) {
Common::String fname = _vm->getSavegameFilename(ano);
- strcpy(tmpName, fname.c_str());
+ Common::strlcpy(tmpName, fname.c_str(), FNAMELEN);
for (i = 0; i < g_numSfiles; i++)
if (!strcmp(g_savedFiles[i].name, tmpName))
diff --git a/engines/tinsel/tinsel.h b/engines/tinsel/tinsel.h
index c83bc80ead..9e4ce61b04 100644
--- a/engines/tinsel/tinsel.h
+++ b/engines/tinsel/tinsel.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef TINSEL_H
-#define TINSEL_H
+#ifndef TINSEL_TINSEL_H
+#define TINSEL_TINSEL_H
#include "common/scummsys.h"
#include "common/system.h"
@@ -251,4 +251,4 @@ void CdHasChanged();
} // End of namespace Tinsel
-#endif /* TINSEL_H */
+#endif /* TINSEL_TINSEL_H */
diff --git a/engines/toltecs/movie.cpp b/engines/toltecs/movie.cpp
index b64903ec6d..b26408fadc 100644
--- a/engines/toltecs/movie.cpp
+++ b/engines/toltecs/movie.cpp
@@ -45,7 +45,7 @@ enum ChunkTypes {
kChunkStopSubtitles = 8
};
-MoviePlayer::MoviePlayer(ToltecsEngine *vm) : _vm(vm), _isPlaying(false), _lastPrefetchOfs(0), _framesPerSoundChunk(0), _endPos(0) {
+MoviePlayer::MoviePlayer(ToltecsEngine *vm) : _vm(vm), _isPlaying(false), _lastPrefetchOfs(0), _framesPerSoundChunk(0), _endPos(0), _audioStream(0) {
}
MoviePlayer::~MoviePlayer() {
diff --git a/engines/toltecs/resource.cpp b/engines/toltecs/resource.cpp
index 468ae0272f..6dbb9c2843 100644
--- a/engines/toltecs/resource.cpp
+++ b/engines/toltecs/resource.cpp
@@ -31,6 +31,7 @@ namespace Toltecs {
/* ArchiveReader */
ArchiveReader::ArchiveReader() {
+ _offsets = 0;
}
ArchiveReader::~ArchiveReader() {
diff --git a/engines/toltecs/sprite.cpp b/engines/toltecs/sprite.cpp
index f29f64dcfe..be4be5d9e3 100644
--- a/engines/toltecs/sprite.cpp
+++ b/engines/toltecs/sprite.cpp
@@ -84,6 +84,7 @@ public:
_yerror = _sprite->yerror;
_origHeight = _sprite->origHeight;
_scalerStatus = 0;
+ _xerror = 0;
}
SpriteReaderStatus readPacket(PixelPacket &packet) {
SpriteReaderStatus status = kSrsPixelsLeft;
@@ -135,6 +136,8 @@ public:
_yerror = _sprite->yerror;
_origHeight = _sprite->origHeight;
_scalerStatus = 0;
+ _sourcep = 0;
+ _xerror = 0;
}
SpriteReaderStatus readPacket(PixelPacket &packet) {
SpriteReaderStatus status;
diff --git a/engines/toltecs/toltecs.h b/engines/toltecs/toltecs.h
index 7a04f6e8da..ece82f4a1a 100644
--- a/engines/toltecs/toltecs.h
+++ b/engines/toltecs/toltecs.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef TOLTECS_H
-#define TOLTECS_H
+#ifndef TOLTECS_TOLTECS_H
+#define TOLTECS_TOLTECS_H
#include "common/scummsys.h"
#include "common/endian.h"
@@ -231,4 +231,4 @@ public:
} // End of namespace Toltecs
-#endif /* TOLTECS_H */
+#endif /* TOLTECS_TOLTECS_H */
diff --git a/engines/tony/gfxcore.cpp b/engines/tony/gfxcore.cpp
index 2a32926c53..27145d7c4b 100644
--- a/engines/tony/gfxcore.cpp
+++ b/engines/tony/gfxcore.cpp
@@ -1733,13 +1733,6 @@ void RMGfxSourceBuffer8AA::drawAA(RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *pri
g /= 5;
b /= 5;
- if (r > 0x1f)
- r = 0x1f;
- if (g > 0x3f)
- g = 0x3f;
- if (b > 0x1f)
- b = 0x1f;
-
mybuf[0] = (r << 11) | (g << 5) | b;
}
}
@@ -1774,13 +1767,6 @@ void RMGfxSourceBuffer8AA::drawAA(RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *pri
g /= 6;
b /= 6;
- if (r > 0x1f)
- r = 0x1f;
- if (g > 0x3f)
- g = 0x3f;
- if (b > 0x1f)
- b = 0x1f;
-
mybuf[0] = (r << 11) | (g << 5) | b;
}
}
diff --git a/engines/tony/mpal/loadmpc.cpp b/engines/tony/mpal/loadmpc.cpp
index 8d030f1e52..01892a40e6 100644
--- a/engines/tony/mpal/loadmpc.cpp
+++ b/engines/tony/mpal/loadmpc.cpp
@@ -331,7 +331,7 @@ static const byte *parseItem(const byte *lpBuf, LpMpalItem lpmiItem) {
byte len = *lpBuf;
lpBuf++;
- memcpy(lpmiItem->_lpszDescribe, lpBuf, MIN((byte)127, len));
+ memcpy(lpmiItem->_lpszDescribe, lpBuf, MIN((byte)MAX_DESCRIBE_SIZE, len));
lpBuf += len;
if (len >= MAX_DESCRIBE_SIZE)
diff --git a/engines/tony/mpal/mpal.cpp b/engines/tony/mpal/mpal.cpp
index 89cc28130d..9172843781 100644
--- a/engines/tony/mpal/mpal.cpp
+++ b/engines/tony/mpal/mpal.cpp
@@ -367,12 +367,18 @@ MpalHandle resLoad(uint32 dwId) {
temp = (byte *)globalAlloc(GMEM_FIXED | GMEM_ZEROINIT, nSizeComp);
nBytesRead = GLOBALS._hMpr.read(temp, nSizeComp);
- if (nBytesRead != nSizeComp)
+ if (nBytesRead != nSizeComp) {
+ globalDestroy(temp);
+ globalDestroy(h);
return NULL;
+ }
lzo1x_decompress(temp, nSizeComp, buf, &nBytesRead);
- if (nBytesRead != nSizeDecomp)
+ if (nBytesRead != nSizeDecomp) {
+ globalDestroy(temp);
+ globalDestroy(h);
return NULL;
+ }
globalDestroy(temp);
globalUnlock(h);
@@ -526,8 +532,10 @@ static LpItem getItemData(uint32 nOrdItem) {
globalFree(hDat);
// Check if we've got to the end of the file
- if (i != 0xABCD)
+ if (i != 0xABCD) {
+ globalDestroy(ret);
return NULL;
+ }
return ret;
}
@@ -1413,36 +1421,51 @@ bool mpalInit(const char *lpszMpcFileName, const char *lpszMprFileName,
if (bCompress) {
// Get the compressed size and read the data in
uint32 dwSizeComp = hMpc.readUint32LE();
- if (hMpc.err())
+ if (hMpc.err()) {
+ globalDestroy(lpMpcImage);
return false;
+ }
cmpbuf = (byte *)globalAlloc(GMEM_FIXED, dwSizeComp);
- if (cmpbuf == NULL)
+ if (cmpbuf == NULL) {
+ globalDestroy(lpMpcImage);
return false;
+ }
nBytesRead = hMpc.read(cmpbuf, dwSizeComp);
- if (nBytesRead != dwSizeComp)
+ if (nBytesRead != dwSizeComp) {
+ globalDestroy(cmpbuf);
+ globalDestroy(lpMpcImage);
return false;
+ }
// Decompress the data
lzo1x_decompress(cmpbuf, dwSizeComp, lpMpcImage, &nBytesRead);
- if (nBytesRead != dwSizeDecomp)
+ if (nBytesRead != dwSizeDecomp) {
+ globalDestroy(cmpbuf);
+ globalDestroy(lpMpcImage);
return false;
+ }
globalDestroy(cmpbuf);
} else {
// If the file is not compressed, we directly read in the data
nBytesRead = hMpc.read(lpMpcImage, dwSizeDecomp);
- if (nBytesRead != dwSizeDecomp)
+ if (nBytesRead != dwSizeDecomp) {
+ globalDestroy(lpMpcImage);
return false;
+ }
}
// Close the file
hMpc.close();
// Process the data
- if (parseMpc(lpMpcImage) == false)
+ if (parseMpc(lpMpcImage) == false) {
+ globalDestroy(lpMpcImage);
+
return false;
+ }
globalDestroy(lpMpcImage);
diff --git a/engines/tony/tony.h b/engines/tony/tony.h
index 40bace8db8..fc47e1a1bf 100644
--- a/engines/tony/tony.h
+++ b/engines/tony/tony.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef TONY_H
-#define TONY_H
+#ifndef TONY_TONY_H
+#define TONY_TONY_H
#include "common/scummsys.h"
#include "common/system.h"
@@ -242,4 +242,4 @@ extern TonyEngine *g_vm;
} // End of namespace Tony
-#endif /* TONY_H */
+#endif /* TONY_TONY_H */
diff --git a/engines/touche/touche.h b/engines/touche/touche.h
index 33c415d9dc..c76532b302 100644
--- a/engines/touche/touche.h
+++ b/engines/touche/touche.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef TOUCHE_ENGINE_H
-#define TOUCHE_ENGINE_H
+#ifndef TOUCHE_TOUCHE_H
+#define TOUCHE_TOUCHE_H
#include "common/array.h"
#include "common/endian.h"
diff --git a/engines/tsage/detection.cpp b/engines/tsage/detection.cpp
index fe555f2fdb..584ad87742 100644
--- a/engines/tsage/detection.cpp
+++ b/engines/tsage/detection.cpp
@@ -83,7 +83,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "(c) Tsunami Media";
+ return "(C) Tsunami Media";
}
virtual bool hasFeature(MetaEngineFeature f) const {
diff --git a/engines/tsage/graphics.cpp b/engines/tsage/graphics.cpp
index 58fa5b8094..7b7b41f0aa 100644
--- a/engines/tsage/graphics.cpp
+++ b/engines/tsage/graphics.cpp
@@ -229,14 +229,16 @@ void Rect::synchronize(Serializer &s) {
/*--------------------------------------------------------------------------*/
-GfxSurface::GfxSurface() : Graphics::ManagedSurface(), _bounds(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) {
+GfxSurface::GfxSurface() : Graphics::Screen(0, 0), _bounds(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) {
+ free(); // Free the 0x0 surface allocated by Graphics::Screen
_disableUpdates = false;
_lockSurfaceCtr = 0;
_transColor = -1;
_flags = 0;
}
-GfxSurface::GfxSurface(const GfxSurface &s): Graphics::ManagedSurface() {
+GfxSurface::GfxSurface(const GfxSurface &s): Graphics::Screen(0, 0) {
+ free(); // Free the 0x0 surface allocated by Graphics::Screen
_lockSurfaceCtr = 0;
operator=(s);
diff --git a/engines/tsage/graphics.h b/engines/tsage/graphics.h
index 3b395b7625..51636c4119 100644
--- a/engines/tsage/graphics.h
+++ b/engines/tsage/graphics.h
@@ -28,7 +28,7 @@
#include "common/list.h"
#include "common/rect.h"
#include "common/system.h"
-#include "graphics/managed_surface.h"
+#include "graphics/screen.h"
namespace TsAGE {
@@ -73,13 +73,23 @@ public:
enum FrameFlag { FRAME_FLIP_CENTROID_X = 4, FRAME_FLIP_CENTROID_Y = 8 };
-class GfxSurface: virtual public Graphics::ManagedSurface {
+/**
+ * Surface class. This derivces from Graphics::Screen because it has
+ * logic we'll need for our own Screen class that derives from this one
+ */
+ class GfxSurface: public Graphics::Screen {
private:
int _lockSurfaceCtr;
Graphics::ManagedSurface _rawSurface;
bool _disableUpdates;
Rect _bounds;
+ protected:
+ /**
+ * Override the addDirtyRect from Graphics::Screen, since for standard
+ * surfaces we don't need dirty rects to be tracked
+ */
+ virtual void addDirtyRect(const Common::Rect &r) {}
public:
Common::Point _centroid;
int _transColor;
diff --git a/engines/tsage/ringworld2/ringworld2_scenes2.cpp b/engines/tsage/ringworld2/ringworld2_scenes2.cpp
index bd8a0cdd0d..6b44ecc514 100644
--- a/engines/tsage/ringworld2/ringworld2_scenes2.cpp
+++ b/engines/tsage/ringworld2/ringworld2_scenes2.cpp
@@ -1440,7 +1440,7 @@ void Scene2425::postInit(SceneObjectList *OwnerList) {
case 2425:
_sceneMode = 10;
R2_GLOBALS._player.setPosition(Common::Point(280, 150));
- _action->signal();
+ signal();
break;
case 2455:
_sceneMode = 2428;
diff --git a/engines/tsage/screen.cpp b/engines/tsage/screen.cpp
index f11c384797..eaf2067c32 100644
--- a/engines/tsage/screen.cpp
+++ b/engines/tsage/screen.cpp
@@ -25,10 +25,15 @@
namespace TsAGE {
-Screen::Screen(): GfxSurface(), Graphics::Screen() {
+Screen::Screen(): GfxSurface() {
create(SCREEN_WIDTH, SCREEN_HEIGHT);
}
+Screen::~Screen() {
+ // Delete the screen's surface
+ free();
+}
+
void Screen::update() {
// When dialogs are active, the screen surface may be remapped to
// sub-sections of the screen. But for drawing we'll need to temporarily
diff --git a/engines/tsage/screen.h b/engines/tsage/screen.h
index bf5057e4d6..c5cfee754a 100644
--- a/engines/tsage/screen.h
+++ b/engines/tsage/screen.h
@@ -36,7 +36,14 @@ namespace TsAGE {
#define SCREEN_CENTER_Y 100
#define UI_INTERFACE_Y 168
-class Screen : virtual public Graphics::Screen, virtual public GfxSurface {
+class Screen : public GfxSurface {
+ /**
+ * Override the addDirtyRect from GfxSurface, since for our screen
+ * class we need to reintroduce the standard Graphics::Screen implementation
+ */
+ virtual void addDirtyRect(const Common::Rect &r) {
+ Graphics::Screen::addDirtyRect(r);
+ }
public:
/**
* Constructor
@@ -46,7 +53,7 @@ public:
/**
* Destructor
*/
- virtual ~Screen() {}
+ virtual ~Screen();
/**
* Update the screen
diff --git a/engines/tsage/tsage.h b/engines/tsage/tsage.h
index dd077e526f..ca29d68243 100644
--- a/engines/tsage/tsage.h
+++ b/engines/tsage/tsage.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef TSAGE_H
-#define TSAGE_H
+#ifndef TSAGE_TSAGE_H
+#define TSAGE_TSAGE_H
#include "engines/engine.h"
#include "gui/debugger.h"
diff --git a/engines/tucker/tucker.h b/engines/tucker/tucker.h
index 2ab94dedbc..1be4682508 100644
--- a/engines/tucker/tucker.h
+++ b/engines/tucker/tucker.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef TUCKER_ENGINE_H
-#define TUCKER_ENGINE_H
+#ifndef TUCKER_TUCKER_H
+#define TUCKER_TUCKER_H
#include "common/file.h"
#include "common/util.h"
diff --git a/engines/voyeur/detection.cpp b/engines/voyeur/detection.cpp
index 9e5320aac8..7b9fa6722e 100644
--- a/engines/voyeur/detection.cpp
+++ b/engines/voyeur/detection.cpp
@@ -75,7 +75,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "Voyeur (c) Philips P.O.V. Entertainment Group";
+ return "Voyeur (C) Philips P.O.V. Entertainment Group";
}
virtual bool hasFeature(MetaEngineFeature f) const;
diff --git a/engines/voyeur/files.h b/engines/voyeur/files.h
index 8726b38ddf..92b43958d3 100644
--- a/engines/voyeur/files.h
+++ b/engines/voyeur/files.h
@@ -325,9 +325,13 @@ private:
ViewPortAddPtr addFn, ViewPortRestorePtr restoreFn);
public:
ViewPortResource *_parent;
+ ViewPortSetupPtr _setupFn;
int _pageCount;
+ ViewPortAddPtr _addFn;
int _pageIndex;
+ ViewPortRestorePtr _restoreFn;
int _lastPage;
+ ScreenMethodPtr _fn1;
Common::Rect _bounds;
PictureResource *_currentPic;
PictureResource *_activePage;
@@ -340,10 +344,6 @@ public:
int _rectListCount[3];
Common::Rect _clipRect;
- ScreenMethodPtr _fn1;
- ViewPortSetupPtr _setupFn;
- ViewPortAddPtr _addFn;
- ViewPortRestorePtr _restoreFn;
Common::Rect _fontRect;
public:
ViewPortResource(BoltFilesState &state, const byte *src);
diff --git a/engines/wage/debugger.cpp b/engines/wage/debugger.cpp
index 7d01b0b85e..d34aca7d49 100644
--- a/engines/wage/debugger.cpp
+++ b/engines/wage/debugger.cpp
@@ -56,7 +56,7 @@ static int strToInt(const char *s) {
}
bool Debugger::Cmd_ListScenes(int argc, const char **argv) {
- int currentScene;
+ int currentScene = 0;
for (uint i = 1; i < _engine->_world->_orderedScenes.size(); i++) { // #0 is STORAGE@
if (_engine->_world->_player->_currentScene == _engine->_world->_orderedScenes[i])
diff --git a/engines/wage/design.cpp b/engines/wage/design.cpp
index 907a1ec435..eda28df159 100644
--- a/engines/wage/design.cpp
+++ b/engines/wage/design.cpp
@@ -45,20 +45,22 @@
*
*/
+#include "graphics/managed_surface.h"
#include "graphics/primitives.h"
-#include "wage/wage.h"
+
+#include "wage/macwindowmanager.h"
#include "wage/design.h"
namespace Wage {
struct PlotData {
- Graphics::Surface *surface;
+ Graphics::ManagedSurface *surface;
Patterns *patterns;
uint fillType;
int thickness;
Design *design;
- PlotData(Graphics::Surface *s, Patterns *p, int f, int t, Design *d) :
+ PlotData(Graphics::ManagedSurface *s, Patterns *p, int f, int t, Design *d) :
surface(s), patterns(p), fillType(f), thickness(t), design(d) {}
};
@@ -83,7 +85,7 @@ Design::~Design() {
delete _surface;
}
-void Design::paint(Graphics::Surface *surface, Patterns &patterns, int x, int y) {
+void Design::paint(Graphics::ManagedSurface *surface, Patterns &patterns, int x, int y) {
bool needRender = false;
if (_surface == NULL) {
@@ -96,11 +98,10 @@ void Design::paint(Graphics::Surface *surface, Patterns &patterns, int x, int y)
}
_bounds->debugPrint(4, "Calculated bounds:");
- _surface = new Graphics::Surface;
+ _surface = new Graphics::ManagedSurface;
_surface->create(_bounds->width(), _bounds->height(), Graphics::PixelFormat::createFormatCLUT8());
- Common::Rect r(0, 0, _bounds->width(), _bounds->height());
- _surface->fillRect(r, kColorGreen);
+ _surface->clear(kColorGreen);
needRender = true;
}
@@ -133,16 +134,10 @@ void Design::paint(Graphics::Surface *surface, Patterns &patterns, int x, int y)
if (_bounds->width() && _bounds->height()) {
const int padding = 3;
- for (int i = padding; i < _bounds->height() - 2 * padding; i++) {
- const byte *src = (const byte *)_surface->getBasePtr(padding, i);
- byte *dst = (byte *)surface->getBasePtr(x + padding, y+i);
- for (int j = padding; j < _bounds->width() - 2 * padding; j++) {
- if (*src != kColorGreen)
- *dst = *src;
- src++;
- dst++;
- }
- }
+ Common::Rect from(padding, padding, _bounds->width() - 2 * padding, _bounds->height() - 2 * padding);
+ Common::Rect to(from);
+ to.moveTo(x, y);
+ surface->transBlitFrom(*_surface, from, to, kColorGreen);
}
}
@@ -215,9 +210,9 @@ void drawPixel(int x, int y, int color, void *data) {
if (p->thickness == 1) {
p->design->adjustBounds(x, y);
} else {
- int x1 = x - p->thickness / 2;
+ int x1 = x;
int x2 = x1 + p->thickness;
- int y1 = y - p->thickness / 2;
+ int y1 = y;
int y2 = y1 + p->thickness;
for (y = y1; y < y2; y++)
@@ -240,9 +235,9 @@ void drawPixel(int x, int y, int color, void *data) {
color : kColorWhite;
}
} else {
- int x1 = x - p->thickness / 2;
+ int x1 = x;
int x2 = x1 + p->thickness;
- int y1 = y - p->thickness / 2;
+ int y1 = y;
int y2 = y1 + p->thickness;
for (y = y1; y < y2; y++)
@@ -269,7 +264,7 @@ void drawPixelPlain(int x, int y, int color, void *data) {
*((byte *)p->surface->getBasePtr(x, y)) = (byte)color;
}
-void Design::drawRect(Graphics::Surface *surface, Common::ReadStream &in,
+void Design::drawRect(Graphics::ManagedSurface *surface, Common::ReadStream &in,
Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType) {
int16 y1 = in.readSint16BE();
int16 x1 = in.readSint16BE();
@@ -298,7 +293,7 @@ void Design::drawRect(Graphics::Surface *surface, Common::ReadStream &in,
}
}
-void Design::drawRoundRect(Graphics::Surface *surface, Common::ReadStream &in,
+void Design::drawRoundRect(Graphics::ManagedSurface *surface, Common::ReadStream &in,
Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType) {
int16 y1 = in.readSint16BE();
int16 x1 = in.readSint16BE();
@@ -324,7 +319,7 @@ void Design::drawRoundRect(Graphics::Surface *surface, Common::ReadStream &in,
Graphics::drawRoundRect(r, arc / 2, kColorBlack, false, drawPixel, &pd);
}
-void Design::drawPolygon(Graphics::Surface *surface, Common::ReadStream &in,
+void Design::drawPolygon(Graphics::ManagedSurface *surface, Common::ReadStream &in,
Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType) {
byte ignored = in.readSint16BE(); // ignored
@@ -401,7 +396,7 @@ void Design::drawPolygon(Graphics::Surface *surface, Common::ReadStream &in,
free(ypoints);
}
-void Design::drawOval(Graphics::Surface *surface, Common::ReadStream &in,
+void Design::drawOval(Graphics::ManagedSurface *surface, Common::ReadStream &in,
Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType) {
int16 y1 = in.readSint16BE();
int16 x1 = in.readSint16BE();
@@ -419,7 +414,7 @@ void Design::drawOval(Graphics::Surface *surface, Common::ReadStream &in,
Graphics::drawEllipse(x1, y1, x2-1, y2-1, kColorBlack, false, drawPixel, &pd);
}
-void Design::drawBitmap(Graphics::Surface *surface, Common::SeekableReadStream &in) {
+void Design::drawBitmap(Graphics::ManagedSurface *surface, Common::SeekableReadStream &in) {
int numBytes = in.readSint16BE();
int y1 = in.readSint16BE();
int x1 = in.readSint16BE();
@@ -427,7 +422,7 @@ void Design::drawBitmap(Graphics::Surface *surface, Common::SeekableReadStream &
int x2 = in.readSint16BE();
int w = x2 - x1;
int h = y2 - y1;
- Graphics::Surface tmp;
+ Graphics::ManagedSurface tmp;
tmp.create(w, h, Graphics::PixelFormat::createFormatCLUT8());
@@ -507,11 +502,11 @@ void Design::drawBitmap(Graphics::Surface *surface, Common::SeekableReadStream &
tmp.free();
}
-void Design::drawRect(Graphics::Surface *surface, Common::Rect &rect, int thickness, int color, Patterns &patterns, byte fillType) {
+void Design::drawRect(Graphics::ManagedSurface *surface, Common::Rect &rect, int thickness, int color, Patterns &patterns, byte fillType) {
drawRect(surface, rect.left, rect.top, rect.right, rect.bottom, thickness, color, patterns, fillType);
}
-void Design::drawRect(Graphics::Surface *surface, int x1, int y1, int x2, int y2, int thickness, int color, Patterns &patterns, byte fillType) {
+void Design::drawRect(Graphics::ManagedSurface *surface, int x1, int y1, int x2, int y2, int thickness, int color, Patterns &patterns, byte fillType) {
PlotData pd(surface, &patterns, fillType, thickness, nullptr);
Graphics::drawLine(x1, y1, x2, y1, kColorBlack, drawPixel, &pd);
@@ -521,32 +516,32 @@ void Design::drawRect(Graphics::Surface *surface, int x1, int y1, int x2, int y2
}
-void Design::drawFilledRect(Graphics::Surface *surface, Common::Rect &rect, int color, Patterns &patterns, byte fillType) {
+void Design::drawFilledRect(Graphics::ManagedSurface *surface, Common::Rect &rect, int color, Patterns &patterns, byte fillType) {
PlotData pd(surface, &patterns, fillType, 1, nullptr);
for (int y = rect.top; y <= rect.bottom; y++)
Graphics::drawHLine(rect.left, rect.right, y, color, drawPixel, &pd);
}
-void Design::drawFilledRoundRect(Graphics::Surface *surface, Common::Rect &rect, int arc, int color, Patterns &patterns, byte fillType) {
+void Design::drawFilledRoundRect(Graphics::ManagedSurface *surface, Common::Rect &rect, int arc, int color, Patterns &patterns, byte fillType) {
PlotData pd(surface, &patterns, fillType, 1, nullptr);
Graphics::drawRoundRect(rect, arc, color, true, drawPixel, &pd);
}
-void Design::drawHLine(Graphics::Surface *surface, int x1, int x2, int y, int thickness, int color, Patterns &patterns, byte fillType) {
+void Design::drawHLine(Graphics::ManagedSurface *surface, int x1, int x2, int y, int thickness, int color, Patterns &patterns, byte fillType) {
PlotData pd(surface, &patterns, fillType, thickness, nullptr);
Graphics::drawHLine(x1, x2, y, color, drawPixel, &pd);
}
-void Design::drawVLine(Graphics::Surface *surface, int x, int y1, int y2, int thickness, int color, Patterns &patterns, byte fillType) {
+void Design::drawVLine(Graphics::ManagedSurface *surface, int x, int y1, int y2, int thickness, int color, Patterns &patterns, byte fillType) {
PlotData pd(surface, &patterns, fillType, thickness, nullptr);
Graphics::drawVLine(x, y1, y2, color, drawPixel, &pd);
}
-FloodFill::FloodFill(Graphics::Surface *surface, byte color1, byte color2) {
+FloodFill::FloodFill(Graphics::ManagedSurface *surface, byte color1, byte color2) {
_surface = surface;
_color1 = color1;
_color2 = color2;
diff --git a/engines/wage/design.h b/engines/wage/design.h
index e8f42f4e04..9b0231ca96 100644
--- a/engines/wage/design.h
+++ b/engines/wage/design.h
@@ -48,10 +48,11 @@
#ifndef WAGE_DESIGN_H
#define WAGE_DESIGN_H
-#include "graphics/surface.h"
#include "common/memstream.h"
#include "common/rect.h"
+#include "wage/macwindowmanager.h"
+
namespace Wage {
class Design {
@@ -67,14 +68,14 @@ public:
return _bounds;
}
- void paint(Graphics::Surface *canvas, Patterns &patterns, int x, int y);
+ void paint(Graphics::ManagedSurface *canvas, Patterns &patterns, int x, int y);
bool isPointOpaque(int x, int y);
- static void drawRect(Graphics::Surface *surface, Common::Rect &rect, int thickness, int color, Patterns &patterns, byte fillType);
- static void drawRect(Graphics::Surface *surface, int x1, int y1, int x2, int y2, int thickness, int color, Patterns &patterns, byte fillType);
- static void drawFilledRect(Graphics::Surface *surface, Common::Rect &rect, int color, Patterns &patterns, byte fillType);
- static void drawFilledRoundRect(Graphics::Surface *surface, Common::Rect &rect, int arc, int color, Patterns &patterns, byte fillType);
- static void drawHLine(Graphics::Surface *surface, int x1, int x2, int y, int thickness, int color, Patterns &patterns, byte fillType);
- static void drawVLine(Graphics::Surface *surface, int x, int y1, int y2, int thickness, int color, Patterns &patterns, byte fillType);
+ static void drawRect(Graphics::ManagedSurface *surface, Common::Rect &rect, int thickness, int color, Patterns &patterns, byte fillType);
+ static void drawRect(Graphics::ManagedSurface *surface, int x1, int y1, int x2, int y2, int thickness, int color, Patterns &patterns, byte fillType);
+ static void drawFilledRect(Graphics::ManagedSurface *surface, Common::Rect &rect, int color, Patterns &patterns, byte fillType);
+ static void drawFilledRoundRect(Graphics::ManagedSurface *surface, Common::Rect &rect, int arc, int color, Patterns &patterns, byte fillType);
+ static void drawHLine(Graphics::ManagedSurface *surface, int x1, int x2, int y, int thickness, int color, Patterns &patterns, byte fillType);
+ static void drawVLine(Graphics::ManagedSurface *surface, int x, int y1, int y2, int thickness, int color, Patterns &patterns, byte fillType);
bool isBoundsCalculation() { return _boundsCalculationMode; }
void adjustBounds(int16 x, int16 y);
@@ -83,32 +84,32 @@ private:
byte *_data;
int _len;
Common::Rect *_bounds;
- Graphics::Surface *_surface;
+ Graphics::ManagedSurface *_surface;
bool _boundsCalculationMode;
private:
void render(Patterns &patterns);
- void drawRect(Graphics::Surface *surface, Common::ReadStream &in,
+ void drawRect(Graphics::ManagedSurface *surface, Common::ReadStream &in,
Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType);
- void drawRoundRect(Graphics::Surface *surface, Common::ReadStream &in,
+ void drawRoundRect(Graphics::ManagedSurface *surface, Common::ReadStream &in,
Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType);
- void drawPolygon(Graphics::Surface *surface, Common::ReadStream &in,
+ void drawPolygon(Graphics::ManagedSurface *surface, Common::ReadStream &in,
Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType);
- void drawOval(Graphics::Surface *surface, Common::ReadStream &in,
+ void drawOval(Graphics::ManagedSurface *surface, Common::ReadStream &in,
Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType);
- void drawBitmap(Graphics::Surface *surface, Common::SeekableReadStream &in);
+ void drawBitmap(Graphics::ManagedSurface *surface, Common::SeekableReadStream &in);
};
class FloodFill {
public:
- FloodFill(Graphics::Surface *surface, byte color1, byte color2);
+ FloodFill(Graphics::ManagedSurface *surface, byte color1, byte color2);
~FloodFill();
void addSeed(int x, int y);
void fill();
private:
Common::List<Common::Point *> _queue;
- Graphics::Surface *_surface;
+ Graphics::ManagedSurface *_surface;
byte _color1, _color2;
byte *_visited;
int _w, _h;
diff --git a/engines/wage/dialog.cpp b/engines/wage/dialog.cpp
index 263570bddc..d9bb3e6a61 100644
--- a/engines/wage/dialog.cpp
+++ b/engines/wage/dialog.cpp
@@ -49,6 +49,7 @@
#include "common/events.h"
#include "wage/wage.h"
+#include "wage/macwindowmanager.h"
#include "wage/design.h"
#include "wage/gui.h"
#include "wage/dialog.h"
@@ -88,11 +89,11 @@ Dialog::~Dialog() {
}
const Graphics::Font *Dialog::getDialogFont() {
- return _gui->getFont("Chicago-12", Graphics::FontManager::kBigGUIFont);
+ return _gui->_wm.getFont("Chicago-12", Graphics::FontManager::kBigGUIFont);
}
void Dialog::paint() {
- Design::drawFilledRect(&_gui->_screen, _bbox, kColorWhite, _gui->_patterns, kPatternSolid);
+ Design::drawFilledRect(&_gui->_screen, _bbox, kColorWhite, _gui->_wm.getPatterns(), kPatternSolid);
_font->drawString(&_gui->_screen, _text, _bbox.left + 24, _bbox.top + 16, _bbox.width(), kColorBlack);
static int boxOutline[] = { 1, 0, 0, 1, 1 };
@@ -114,7 +115,7 @@ void Dialog::paint() {
Common::Rect bb(button->bounds.left + 5, button->bounds.top + 5,
button->bounds.right - 5, button->bounds.bottom - 5);
- Design::drawFilledRect(&_gui->_screen, bb, kColorBlack, _gui->_patterns, kPatternSolid);
+ Design::drawFilledRect(&_gui->_screen, bb, kColorBlack, _gui->_wm.getPatterns(), kPatternSolid);
color = kColorWhite;
}
@@ -137,7 +138,7 @@ void Dialog::drawOutline(Common::Rect &bounds, int *spec, int speclen) {
for (int i = 0; i < speclen; i++)
if (spec[i] != 0)
Design::drawRect(&_gui->_screen, bounds.left + i, bounds.top + i, bounds.right - i, bounds.bottom - i,
- 1, kColorBlack, _gui->_patterns, kPatternSolid);
+ 1, kColorBlack, _gui->_wm.getPatterns(), kPatternSolid);
}
int Dialog::run() {
@@ -145,7 +146,7 @@ int Dialog::run() {
Common::Rect r(_bbox);
_tempSurface.copyRectToSurface(_gui->_screen.getBasePtr(_bbox.left, _bbox.top), _gui->_screen.pitch, 0, 0, _bbox.width() + 1, _bbox.height() + 1);
- _gui->pushArrowCursor();
+ _gui->_wm.pushArrowCursor();
while (!shouldQuit) {
Common::Event event;
@@ -189,7 +190,7 @@ int Dialog::run() {
_gui->_screen.copyRectToSurface(_tempSurface.getBasePtr(0, 0), _tempSurface.pitch, _bbox.left, _bbox.top, _bbox.width() + 1, _bbox.height() + 1);
g_system->copyRectToScreen(_gui->_screen.getBasePtr(r.left, r.top), _gui->_screen.pitch, r.left, r.top, r.width() + 1, r.height() + 1);
- _gui->popCursor();
+ _gui->_wm.popCursor();
return _pressedButton;
}
diff --git a/engines/wage/dialog.h b/engines/wage/dialog.h
index c5878acc95..ec99fc06b2 100644
--- a/engines/wage/dialog.h
+++ b/engines/wage/dialog.h
@@ -74,7 +74,7 @@ public:
private:
Gui *_gui;
- Graphics::Surface _tempSurface;
+ Graphics::ManagedSurface _tempSurface;
Common::Rect _bbox;
Common::String _text;
diff --git a/engines/wage/entities.cpp b/engines/wage/entities.cpp
index adb053868a..43ac6c8cc7 100644
--- a/engines/wage/entities.cpp
+++ b/engines/wage/entities.cpp
@@ -52,6 +52,7 @@
#include "wage/world.h"
#include "common/memstream.h"
+#include "graphics/managed_surface.h"
namespace Wage {
@@ -134,20 +135,20 @@ Scene::~Scene() {
delete _textBounds;
}
-void Scene::paint(Graphics::Surface *surface, int x, int y) {
+void Scene::paint(Graphics::ManagedSurface *surface, int x, int y) {
Common::Rect r(x + 5, y + 5, _design->getBounds()->width() + x - 10, _design->getBounds()->height() + y - 10);
surface->fillRect(r, kColorWhite);
- _design->paint(surface, ((WageEngine *)g_engine)->_world->_patterns, x, y);
+ _design->paint(surface, *((WageEngine *)g_engine)->_world->_patterns, x, y);
for (ObjList::const_iterator it = _objs.begin(); it != _objs.end(); ++it) {
debug(2, "paining Obj: %s, index: %d, type: %d", (*it)->_name.c_str(), (*it)->_index, (*it)->_type);
- (*it)->_design->paint(surface, ((WageEngine *)g_engine)->_world->_patterns, x, y);
+ (*it)->_design->paint(surface, *((WageEngine *)g_engine)->_world->_patterns, x, y);
}
for (ChrList::const_iterator it = _chrs.begin(); it != _chrs.end(); ++it) {
debug(2, "paining Chr: %s", (*it)->_name.c_str());
- (*it)->_design->paint(surface, ((WageEngine *)g_engine)->_world->_patterns, x, y);
+ (*it)->_design->paint(surface, *((WageEngine *)g_engine)->_world->_patterns, x, y);
}
}
@@ -202,6 +203,22 @@ const char *Scene::getFontName() {
return "Unknown";
}
+Designed *Scene::lookUpEntity(int x, int y) {
+ for (ObjList::const_iterator it = _objs.end(); it != _objs.begin(); ) {
+ it--;
+ if ((*it)->_design->isPointOpaque(x, y))
+ return *it;
+ }
+
+ for (ChrList::const_iterator it = _chrs.end(); it != _chrs.begin(); ) {
+ it--;
+ if ((*it)->_design->isPointOpaque(x, y))
+ return *it;
+ }
+
+ return nullptr;
+}
+
Obj::Obj() : _currentOwner(NULL), _currentScene(NULL) {
_index = 0;
_namePlural = false;
diff --git a/engines/wage/entities.h b/engines/wage/entities.h
index 33cf087322..9e706f0d58 100644
--- a/engines/wage/entities.h
+++ b/engines/wage/entities.h
@@ -49,7 +49,7 @@
#define WAGE_ENTITIES_H
namespace Graphics {
- struct Surface;
+ class ManagedSurface;
}
namespace Wage {
@@ -322,11 +322,13 @@ public:
Scene(Common::String name, Common::SeekableReadStream *data);
~Scene();
+ Designed *lookUpEntity(int x, int y);
+
Common::Rect *getTextBounds() {
return _textBounds == NULL ? NULL : new Common::Rect(*_textBounds);
}
- void paint(Graphics::Surface *screen, int x, int y);
+ void paint(Graphics::ManagedSurface *screen, int x, int y);
const char *getFontName();
};
diff --git a/engines/wage/gui-console.cpp b/engines/wage/gui-console.cpp
index ab5df637ec..8b6fe43a17 100644
--- a/engines/wage/gui-console.cpp
+++ b/engines/wage/gui-console.cpp
@@ -45,6 +45,7 @@
*
*/
+#include "common/events.h"
#include "common/timer.h"
#include "common/unzip.h"
#include "graphics/cursorman.h"
@@ -54,7 +55,8 @@
#include "wage/wage.h"
#include "wage/design.h"
#include "wage/entities.h"
-#include "wage/menu.h"
+#include "wage/macwindow.h"
+#include "wage/macmenu.h"
#include "wage/gui.h"
#include "wage/world.h"
@@ -66,7 +68,7 @@ const Graphics::Font *Gui::getConsoleFont() {
snprintf(fontName, 128, "%s-%d", scene->getFontName(), scene->_fontSize);
- return getFont(fontName, Graphics::FontManager::kConsoleFont);
+ return _wm.getFont(fontName, Graphics::FontManager::kConsoleFont);
}
void Gui::clearOutput() {
@@ -114,7 +116,7 @@ enum {
void Gui::flowText(Common::String &str) {
Common::StringArray wrappedLines;
- int textW = _consoleTextArea.width() - kConWPadding * 2;
+ int textW = _consoleWindow->getInnerDimensions().width() - kConWPadding * 2;
const Graphics::Font *font = getConsoleFont();
font->wordWrapText(str, textW, wrappedLines);
@@ -142,7 +144,7 @@ void Gui::flowText(Common::String &str) {
draw();
}
-void Gui::renderConsole(Graphics::Surface *g, Common::Rect &r) {
+void Gui::renderConsole(Graphics::ManagedSurface *g, const Common::Rect &r) {
bool fullRedraw = _consoleFullRedraw;
bool textReflow = false;
int surfW = r.width() + kConWOverlap * 2;
@@ -150,7 +152,6 @@ void Gui::renderConsole(Graphics::Surface *g, Common::Rect &r) {
Common::Rect boundsR(kConWOverlap - kConOverscan, kConHOverlap - kConOverscan,
r.width() + kConWOverlap + kConOverscan, r.height() + kConHOverlap + kConOverscan);
- Common::Rect fullR(0, 0, surfW, surfH);
if (_console.w != surfW || _console.h != surfH) {
if (_console.w != surfW)
@@ -163,7 +164,7 @@ void Gui::renderConsole(Graphics::Surface *g, Common::Rect &r) {
}
if (fullRedraw)
- _console.fillRect(fullR, kColorWhite);
+ _console.clear(kColorWhite);
const Graphics::Font *font = getConsoleFont();
@@ -197,7 +198,7 @@ void Gui::renderConsole(Graphics::Surface *g, Common::Rect &r) {
color = kColorWhite;
Common::Rect trect(0, y1, _console.w, y1 + _consoleLineHeight);
- Design::drawFilledRect(&_console, trect, kColorBlack, _patterns, kPatternSolid);
+ Design::drawFilledRect(&_console, trect, kColorBlack, _wm.getPatterns(), kPatternSolid);
}
if (line == _selectionStartY || line == _selectionEndY) {
@@ -224,7 +225,7 @@ void Gui::renderConsole(Graphics::Surface *g, Common::Rect &r) {
else
trect.left = rectW;
- Design::drawFilledRect(&_console, trect, kColorBlack, _patterns, kPatternSolid);
+ Design::drawFilledRect(&_console, trect, kColorBlack, _wm.getPatterns(), kPatternSolid);
font->drawString(&_console, beg, x1, y1, textW, color1);
font->drawString(&_console, end, x1 + rectW - kConWPadding - kConWOverlap, y1, textW, color2);
@@ -243,7 +244,7 @@ void Gui::renderConsole(Graphics::Surface *g, Common::Rect &r) {
int rectW2 = rectW1 + font->getStringWidth(mid);
Common::Rect trect(rectW1, y1, rectW2, y1 + _consoleLineHeight);
- Design::drawFilledRect(&_console, trect, kColorBlack, _patterns, kPatternSolid);
+ Design::drawFilledRect(&_console, trect, kColorBlack, _wm.getPatterns(), kPatternSolid);
font->drawString(&_console, beg, x1, y1, textW, kColorBlack);
font->drawString(&_console, mid, x1 + rectW1 - kConWPadding - kConWOverlap, y1, textW, kColorWhite);
@@ -280,17 +281,13 @@ void Gui::renderConsole(Graphics::Surface *g, Common::Rect &r) {
rr.bottom = _screen.h - 1;
g->copyRectToSurface(_console, xcon, ycon, boundsR);
- g_system->copyRectToScreen(g->getBasePtr(rr.left, rr.top), g->pitch, rr.left, rr.top, rr.width(), rr.height());
}
void Gui::drawInput() {
if (!_screen.getPixels())
return;
- if (_sceneIsActive) {
- _sceneIsActive = false;
- _bordersDirty = true;
- }
+ _wm.setActive(_consoleWindow->getId());
_out.pop_back();
_lines.pop_back();
@@ -302,17 +299,17 @@ void Gui::drawInput() {
if (_engine->_inputText.contains('\n')) {
_consoleDirty = true;
} else {
- int x = kConWPadding + _consoleTextArea.left;
- int y = _cursorY + _consoleTextArea.top;
+ int x = kConWPadding + _consoleWindow->getInnerDimensions().left;
+ int y = _cursorY + _consoleWindow->getInnerDimensions().top;
- Common::Rect r(x, y, x + _consoleTextArea.width() - kConWPadding, y + font->getFontHeight());
+ Common::Rect r(x, y, x + _consoleWindow->getInnerDimensions().width() - kConWPadding, y + font->getFontHeight());
_screen.fillRect(r, kColorWhite);
undrawCursor();
font->drawString(&_screen, _out[_inputTextLineNum], x, y, _screen.w, kColorBlack);
- g_system->copyRectToScreen(_screen.getBasePtr(x, y), _screen.pitch, x, y, _consoleTextArea.width(), font->getFontHeight());
+ g_system->copyRectToScreen(_screen.getBasePtr(x, y), _screen.pitch, x, y, _consoleWindow->getInnerDimensions().width(), font->getFontHeight());
}
_cursorX = font->getStringWidth(_out[_inputTextLineNum]) + kConHPadding;
@@ -427,4 +424,140 @@ void Gui::enableNewGameMenus() {
_menu->enableCommand(kMenuFile, kMenuActionQuit, true);
}
+bool Gui::processConsoleEvents(WindowClick click, Common::Event &event) {
+ if (click == kBorderScrollUp || click == kBorderScrollDown) {
+ if (event.type == Common::EVENT_LBUTTONDOWN) {
+ int consoleHeight = _consoleWindow->getInnerDimensions().height();
+ int textFullSize = _lines.size() * _consoleLineHeight + consoleHeight;
+ float scrollPos = (float)_scrollPos / textFullSize;
+ float scrollSize = (float)consoleHeight / textFullSize;
+
+ _consoleWindow->setScroll(scrollPos, scrollSize);
+
+ return true;
+ } else if (event.type == Common::EVENT_LBUTTONUP) {
+ int oldScrollPos = _scrollPos;
+
+ switch (click) {
+ case kBorderScrollUp:
+ _scrollPos = MAX<int>(0, _scrollPos - _consoleLineHeight);
+ undrawCursor();
+ _cursorY -= (_scrollPos - oldScrollPos);
+ _consoleDirty = true;
+ _consoleFullRedraw = true;
+ break;
+ case kBorderScrollDown:
+ _scrollPos = MIN<int>((_lines.size() - 2) * _consoleLineHeight, _scrollPos + _consoleLineHeight);
+ undrawCursor();
+ _cursorY -= (_scrollPos - oldScrollPos);
+ _consoleDirty = true;
+ _consoleFullRedraw = true;
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ if (click == kBorderResizeButton) {
+ _consoleDirty = true;
+ _consoleFullRedraw = true;
+
+ return true;
+ }
+
+ if (click == kBorderInner) {
+ if (event.type == Common::EVENT_LBUTTONDOWN) {
+ startMarking(event.mouse.x, event.mouse.y);
+
+ return true;
+ } else if (event.type == Common::EVENT_LBUTTONUP) {
+ if (_inTextSelection) {
+ _inTextSelection = false;
+
+ if (_selectionEndY == -1 ||
+ (_selectionEndX == _selectionStartX && _selectionEndY == _selectionStartY)) {
+ _selectionStartY = _selectionEndY = -1;
+ _consoleFullRedraw = true;
+ _menu->enableCommand(kMenuEdit, kMenuActionCopy, false);
+ } else {
+ _menu->enableCommand(kMenuEdit, kMenuActionCopy, true);
+
+ bool cutAllowed = false;
+
+ if (_selectionStartY == _selectionEndY && _selectionStartY == (int)_lines.size() - 1)
+ cutAllowed = true;
+
+ _menu->enableCommand(kMenuEdit, kMenuActionCut, cutAllowed);
+ _menu->enableCommand(kMenuEdit, kMenuActionClear, cutAllowed);
+ }
+ }
+
+ return true;
+ } else if (event.type == Common::EVENT_MOUSEMOVE) {
+ if (_inTextSelection) {
+ updateTextSelection(event.mouse.x, event.mouse.y);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ return false;
+}
+
+int Gui::calcTextX(int x, int textLine) {
+ const Graphics::Font *font = getConsoleFont();
+
+ if ((uint)textLine >= _lines.size())
+ return 0;
+
+ Common::String str = _lines[textLine];
+
+ x -= _consoleWindow->getInnerDimensions().left;
+
+ for (int i = str.size(); i >= 0; i--) {
+ if (font->getStringWidth(str) < x) {
+ return i;
+ }
+
+ str.deleteLastChar();
+ }
+
+ return 0;
+}
+
+int Gui::calcTextY(int y) {
+ y -= _consoleWindow->getInnerDimensions().top;
+
+ if (y < 0)
+ y = 0;
+
+ const int firstLine = _scrollPos / _consoleLineHeight;
+ int textLine = (y - _scrollPos % _consoleLineHeight) / _consoleLineHeight + firstLine;
+
+ return textLine;
+}
+
+void Gui::startMarking(int x, int y) {
+ _selectionStartY = calcTextY(y);
+ _selectionStartX = calcTextX(x, _selectionStartY);
+
+ _selectionEndY = -1;
+
+ _inTextSelection = true;
+}
+
+void Gui::updateTextSelection(int x, int y) {
+ _selectionEndY = calcTextY(y);
+ _selectionEndX = calcTextX(x, _selectionEndY);
+
+ _consoleFullRedraw = true;
+}
+
} // End of namespace Wage
diff --git a/engines/wage/gui.cpp b/engines/wage/gui.cpp
index 50b8b00861..310e5734b7 100644
--- a/engines/wage/gui.cpp
+++ b/engines/wage/gui.cpp
@@ -46,73 +46,40 @@
*/
#include "common/timer.h"
-#include "common/unzip.h"
+#include "common/system.h"
#include "graphics/cursorman.h"
-#include "graphics/fonts/bdf.h"
-#include "graphics/palette.h"
#include "graphics/primitives.h"
#include "wage/wage.h"
#include "wage/design.h"
#include "wage/entities.h"
+#include "wage/gui.h"
#include "wage/macwindow.h"
#include "wage/macwindowmanager.h"
-#include "wage/menu.h"
-#include "wage/gui.h"
+#include "wage/macmenu.h"
#include "wage/world.h"
namespace Wage {
-static const byte palette[] = {
- 0, 0, 0, // Black
- 0x80, 0x80, 0x80, // Gray
- 0xff, 0xff, 0xff, // White
- 0x00, 0xff, 0x00, // Green
- 0x00, 0x7f, 0x00 // Green2
-};
-
-static byte fillPatterns[][8] = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, // kPatternSolid
- { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 }, // kPatternStripes
- { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 }, // kPatternCheckers
- { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa } // kPatternCheckers2
-};
-
-static const byte macCursorArrow[] = {
- 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 2, 0, 2, 3, 3, 3, 3, 3, 3, 3, 3,
- 2, 0, 0, 2, 3, 3, 3, 3, 3, 3, 3,
- 2, 0, 0, 0, 2, 3, 3, 3, 3, 3, 3,
- 2, 0, 0, 0, 0, 2, 3, 3, 3, 3, 3,
- 2, 0, 0, 0, 0, 0, 2, 3, 3, 3, 3,
- 2, 0, 0, 0, 0, 0, 0, 2, 3, 3, 3,
- 2, 0, 0, 0, 0, 0, 0, 0, 2, 3, 3,
- 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3,
- 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2,
- 2, 0, 0, 2, 0, 0, 2, 3, 3, 3, 3,
- 2, 0, 2, 3, 2, 0, 0, 2, 3, 3, 3,
- 2, 2, 3, 3, 2, 0, 0, 2, 3, 3, 3,
- 2, 3, 3, 3, 3, 2, 0, 0, 2, 3, 3,
- 3, 3, 3, 3, 3, 2, 0, 0, 2, 3, 3,
- 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 3
-};
-
-static const byte macCursorBeam[] = {
- 0, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3,
- 3, 3, 0, 3, 0, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 0, 3, 0, 3, 3, 3, 3, 3, 3,
- 0, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3,
+static const MenuData menuSubItems[] = {
+ { kMenuHighLevel, "File", 0, 0, false },
+ { kMenuHighLevel, "Edit", 0, 0, false },
+ { kMenuFile, "New", kMenuActionNew, 0, false },
+ { kMenuFile, "Open...", kMenuActionOpen, 0, false },
+ { kMenuFile, "Close", kMenuActionClose, 0, true },
+ { kMenuFile, "Save", kMenuActionSave, 0, false },
+ { kMenuFile, "Save as...", kMenuActionSaveAs, 0, true },
+ { kMenuFile, "Revert", kMenuActionRevert, 0, false },
+ { kMenuFile, "Quit", kMenuActionQuit, 0, true },
+
+ { kMenuEdit, "Undo", kMenuActionUndo, 'Z', false },
+ { kMenuEdit, NULL, 0, 0, false },
+ { kMenuEdit, "Cut", kMenuActionCut, 'K', false },
+ { kMenuEdit, "Copy", kMenuActionCopy, 'C', false },
+ { kMenuEdit, "Paste", kMenuActionPaste, 'V', false },
+ { kMenuEdit, "Clear", kMenuActionClear, 'B', false },
+
+ { 0, NULL, 0, 0, false }
};
static void cursorTimerHandler(void *refCon) {
@@ -127,8 +94,8 @@ static void cursorTimerHandler(void *refCon) {
if (!gui->_screen.getPixels())
return;
- x += gui->_consoleTextArea.left;
- y += gui->_consoleTextArea.top;
+ x += gui->_consoleWindow->getInnerDimensions().left;
+ y += gui->_consoleWindow->getInnerDimensions().top;
gui->_screen.vLine(x, y, y + kCursorHeight, gui->_cursorState ? kColorBlack : kColorWhite);
@@ -143,22 +110,25 @@ static void cursorTimerHandler(void *refCon) {
gui->_cursorDirty = true;
}
+static bool sceneWindowCallback(WindowClick click, Common::Event &event, void *gui);
+static bool consoleWindowCallback(WindowClick click, Common::Event &event, void *gui);
+static void menuCommandsCallback(int action, Common::String &text, void *data);
+
+
Gui::Gui(WageEngine *engine) {
_engine = engine;
_scene = NULL;
_sceneDirty = true;
_consoleDirty = true;
- _bordersDirty = true;
- _menuDirty = true;
_cursorDirty = false;
_consoleFullRedraw = true;
_screen.create(g_system->getWidth(), g_system->getHeight(), Graphics::PixelFormat::createFormatCLUT8());
+ _wm.setScreen(&_screen);
+
_scrollPos = 0;
_consoleLineHeight = 8; // Dummy value which makes sense
_consoleNumLines = 24; // Dummy value
- _builtInFonts = false;
- _sceneIsActive = false;
_cursorX = 0;
_cursorY = 0;
@@ -171,31 +141,39 @@ Gui::Gui(WageEngine *engine) {
_inputTextLineNum = 0;
- g_system->getPaletteManager()->setPalette(palette, 0, 4);
+ g_system->getTimerManager()->installTimerProc(&cursorTimerHandler, 200000, this, "wageCursor");
- CursorMan.replaceCursorPalette(palette, 0, 4);
- CursorMan.replaceCursor(macCursorArrow, 11, 16, 1, 1, 3);
- _cursorIsArrow = true;
- CursorMan.showMouse(true);
+ _menu = _wm.addMenu();
- for (int i = 0; i < ARRAYSIZE(fillPatterns); i++)
- _patterns.push_back(fillPatterns[i]);
+ _menu->setCommandsCallback(menuCommandsCallback, this);
- loadFonts();
+ _menu->addStaticMenus(menuSubItems);
+ _menu->addMenuSubItem(kMenuAbout, _engine->_world->getAboutMenuItemName(), kMenuActionAbout);
- g_system->getTimerManager()->installTimerProc(&cursorTimerHandler, 200000, this, "wageCursor");
+ _commandsMenuId = _menu->addMenuItem(_engine->_world->_commandsMenuName.c_str());
+ regenCommandsMenu();
- _menu = new Menu(this);
+ if (!_engine->_world->_weaponMenuDisabled) {
+ _weaponsMenuId = _menu->addMenuItem(_engine->_world->_weaponsMenuName.c_str());
- _sceneWindowId = _wm.add(false);
- _consoleWindowId = _wm.add(true);
+ regenWeaponsMenu();
+ } else {
+ _weaponsMenuId = -1;
+ }
+
+ _menu->calcDimensions();
+
+ _sceneWindow = _wm.addWindow(false, false, false);
+ _sceneWindow->setCallback(sceneWindowCallback, this);
+
+ _consoleWindow = _wm.addWindow(true, true, true);
+ _consoleWindow->setCallback(consoleWindowCallback, this);
}
Gui::~Gui() {
_screen.free();
_console.free();
g_system->getTimerManager()->removeTimerProc(&cursorTimerHandler);
- delete _menu;
}
void Gui::undrawCursor() {
@@ -205,63 +183,34 @@ void Gui::undrawCursor() {
_cursorOff = false;
}
-const Graphics::Font *Gui::getFont(const char *name, Graphics::FontManager::FontUsage fallback) {
- const Graphics::Font *font = 0;
-
- if (!_builtInFonts) {
- font = FontMan.getFontByName(name);
-
- if (!font)
- warning("Cannot load font %s", name);
- }
-
- if (_builtInFonts || !font)
- font = FontMan.getFontByUsage(fallback);
-
- return font;
-}
-
-const Graphics::Font *Gui::getTitleFont() {
- return getFont("Chicago-12", Graphics::FontManager::kBigGUIFont);
-}
-
-void Gui::drawDesktop() {
- // Draw desktop
- Common::Rect r(0, 0, _screen.w - 1, _screen.h - 1);
- Design::drawFilledRoundRect(&_screen, r, kDesktopArc, kColorBlack, _patterns, kPatternCheckers);
- g_system->copyRectToScreen(_screen.getPixels(), _screen.pitch, 0, 0, _screen.w, _screen.h);
-}
-
void Gui::draw() {
if (_engine->_isGameOver) {
- if (_menuDirty) {
- drawDesktop();
- _menu->render();
- }
-
- _menuDirty = false;
+ _wm.draw();
return;
}
- if (_scene != _engine->_world->_player->_currentScene)
+ if (!_engine->_world->_player->_currentScene)
+ return;
+
+ if (_scene != _engine->_world->_player->_currentScene) {
_sceneDirty = true;
- if (_sceneDirty || _bordersDirty)
- drawDesktop();
+ _scene = _engine->_world->_player->_currentScene;
- if (_sceneIsActive) {
- drawConsole();
- drawScene();
- } else {
- drawScene();
- drawConsole();
+ _sceneWindow->setDimensions(*_scene->_designBounds);
+ _sceneWindow->setTitle(_scene->_name);
+ _consoleWindow->setDimensions(*_scene->_textBounds);
+
+ _wm.setFullRefresh(true);
}
- if (_menuDirty)
- _menu->render();
+ drawScene();
+ drawConsole();
- if (_cursorDirty) {
+ _wm.draw();
+
+ if (_cursorDirty && _cursorRect.left < _screen.w && _cursorRect.bottom < _screen.h) {
g_system->copyRectToScreen(_screen.getBasePtr(_cursorRect.left, _cursorRect.top), _screen.pitch,
_cursorRect.left, _cursorRect.top, _cursorRect.width(), _cursorRect.height());
@@ -270,438 +219,141 @@ void Gui::draw() {
_sceneDirty = false;
_consoleDirty = false;
- _bordersDirty = false;
- _menuDirty = false;
_consoleFullRedraw = false;
}
void Gui::drawScene() {
- if (!_sceneDirty && !_bordersDirty)
+ if (!_sceneDirty)
return;
- _scene = _engine->_world->_player->_currentScene;
-
- MacWindow *w = _wm.getWindow(_sceneWindowId);
-
- w->setDimensions(*_scene->_designBounds);
+ _scene->paint(_sceneWindow->getSurface(), 0, 0);
+ _sceneWindow->setDirty(true);
_sceneDirty = true;
_consoleDirty = true;
- _menuDirty = true;
+ _menu->setDirty(true);
_consoleFullRedraw = true;
-
- _scene->paint(&_screen, _scene->_designBounds->left, _scene->_designBounds->top);
-
- _sceneArea.left = _scene->_designBounds->left + kBorderWidth - 2;
- _sceneArea.top = _scene->_designBounds->top + kBorderWidth - 2;
- _sceneArea.setWidth(_scene->_designBounds->width() - 2 * kBorderWidth);
- _sceneArea.setHeight(_scene->_designBounds->height() - 2 * kBorderWidth);
-
- _consoleTextArea.left = _scene->_textBounds->left + kBorderWidth - 2;
- _consoleTextArea.top = _scene->_textBounds->top + kBorderWidth - 2;
- _consoleTextArea.setWidth(_scene->_textBounds->width() - 2 * kBorderWidth);
- _consoleTextArea.setHeight(_scene->_textBounds->height() - 2 * kBorderWidth);
-
- paintBorder(&_screen, _sceneArea, kWindowScene);
-}
-
-// Render console
-void Gui::drawConsole() {
- if (!_consoleDirty && !_consoleFullRedraw && !_bordersDirty && !_sceneDirty)
- return;
-
- renderConsole(&_screen, _consoleTextArea);
- paintBorder(&_screen, _consoleTextArea, kWindowConsole);
-}
-
-void Gui::drawBox(Graphics::Surface *g, int x, int y, int w, int h) {
- Common::Rect r(x, y, x + w + 1, y + h + 1);
-
- g->fillRect(r, kColorWhite);
- g->frameRect(r, kColorBlack);
}
-void Gui::fillRect(Graphics::Surface *g, int x, int y, int w, int h, int color) {
- Common::Rect r(x, y, x + w, y + h);
-
- g->fillRect(r, color);
-}
-
-#define ARROW_W 12
-#define ARROW_H 6
-const int arrowPixels[ARROW_H][ARROW_W] = {
- {0,0,0,0,0,1,1,0,0,0,0,0},
- {0,0,0,0,1,1,1,1,0,0,0,0},
- {0,0,0,1,1,1,1,1,1,0,0,0},
- {0,0,1,1,1,1,1,1,1,1,0,0},
- {0,1,1,1,1,1,1,1,1,1,1,0},
- {1,1,1,1,1,1,1,1,1,1,1,1}};
-
-static void drawPixelInverted(int x, int y, int color, void *data) {
- Graphics::Surface *surface = (Graphics::Surface *)data;
+static bool sceneWindowCallback(WindowClick click, Common::Event &event, void *g) {
+ Gui *gui = (Gui *)g;
- if (x >= 0 && x < surface->w && y >= 0 && y < surface->h) {
- byte *p = (byte *)surface->getBasePtr(x, y);
-
- *p = *p == kColorWhite ? kColorBlack : kColorWhite;
- }
+ return gui->processSceneEvents(click, event);
}
-void Gui::paintBorder(Graphics::Surface *g, Common::Rect &r, WindowType windowType, int highlightedPart, float scrollPos, float scrollSize) {
- bool active = false, scrollable = false, closeable = false, drawTitle = false;
- const int size = kBorderWidth;
- int x = r.left - size;
- int y = r.top - size;
- int width = r.width() + 2 * size;
- int height = r.height() + 2 * size;
-
- switch (windowType) {
- case kWindowScene:
- active = _sceneIsActive;
- scrollable = false;
- closeable = _sceneIsActive;
- drawTitle = true;
- break;
- case kWindowConsole:
- active = !_sceneIsActive;
- scrollable = true;
- closeable = !_sceneIsActive;
- drawTitle = false;
- break;
- }
-
- drawBox(g, x, y, size, size);
- drawBox(g, x + width - size - 1, y, size, size);
- drawBox(g, x + width - size - 1, y + height - size - 1, size, size);
- drawBox(g, x, y + height - size - 1, size, size);
- drawBox(g, x + size, y + 2, width - 2 * size - 1, size - 4);
- drawBox(g, x + size, y + height - size + 1, width - 2 * size - 1, size - 4);
- drawBox(g, x + 2, y + size, size - 4, height - 2 * size - 1);
- drawBox(g, x + width - size + 1, y + size, size - 4, height - 2 * size - 1);
-
- if (active) {
- fillRect(g, x + size, y + 5, width - 2 * size - 1, 8);
- fillRect(g, x + size, y + height - 13, width - 2 * size - 1, 8);
- fillRect(g, x + 5, y + size, 8, height - 2 * size - 1);
- if (!scrollable) {
- fillRect(g, x + width - 13, y + size, 8, height - 2 * size - 1);
- } else {
- int x1 = x + width - 15;
- int y1 = y + size + 1;
-
- for (int yy = 0; yy < ARROW_H; yy++) {
- for (int xx = 0; xx < ARROW_W; xx++)
- g->hLine(x1 + xx, y1 + yy, x1 + xx, (arrowPixels[yy][xx] != 0 ? kColorBlack : kColorWhite));
- }
-
- fillRect(g, x + width - 13, y + size + ARROW_H, 8, height - 2 * size - 1 - ARROW_H * 2);
-
- y1 += height - 2 * size - ARROW_H - 2;
- for (int yy = 0; yy < ARROW_H; yy++) {
- for (int xx = 0; xx < ARROW_W; xx++)
- g->hLine(x1 + xx, y1 + yy, x1 + xx, (arrowPixels[ARROW_H - yy - 1][xx] != 0 ? kColorBlack : kColorWhite));
- }
-
- if (highlightedPart == kBorderScrollUp || highlightedPart == kBorderScrollDown) {
- int rx1 = x + width - kBorderWidth + 2;
- int ry1 = y + size + r.height() * scrollPos;
- int rx2 = rx1 + size - 4;
- int ry2 = ry1 + r.height() * scrollSize;
- Common::Rect rr(rx1, ry1, rx2, ry2);
-
- Graphics::drawFilledRect(rr, kColorBlack, drawPixelInverted, g);
- }
- }
- if (closeable) {
- if (highlightedPart == kBorderCloseButton) {
- fillRect(g, x + 6, y + 6, 6, 6);
- } else {
- drawBox(g, x + 5, y + 5, 7, 7);
- }
- }
- }
-
- if (drawTitle) {
- const Graphics::Font *font = getTitleFont();
- int yOff = _builtInFonts ? 3 : 1;
+bool Gui::processSceneEvents(WindowClick click, Common::Event &event) {
+ if (click == kBorderInner && event.type == Common::EVENT_LBUTTONUP) {
+ Designed *obj = _scene->lookUpEntity(event.mouse.x - _sceneWindow->getDimensions().left,
+ event.mouse.y - _sceneWindow->getDimensions().top);
- int w = font->getStringWidth(_scene->_name) + 10;
- int maxWidth = width - size * 2 - 7;
- if (w > maxWidth)
- w = maxWidth;
- drawBox(g, x + (width - w) / 2, y, w, size);
- font->drawString(g, _scene->_name, x + (width - w) / 2 + 5, y + yOff, w, kColorBlack);
- }
+ if (obj != nullptr)
+ _engine->processTurn(NULL, obj);
- if (x < 0) {
- width += x;
- x = 0;
- }
- if (y < 0) {
- height += y;
- y = 0;
+ return true;
}
- if (x + width > _screen.w)
- width = _screen.w - x;
- if (y + height > _screen.h)
- height = _screen.h - y;
- g_system->copyRectToScreen(g->getBasePtr(x, y), g->pitch, x, y, width, height);
+ return false;
}
-void Gui::loadFonts() {
- Common::Archive *dat;
-
- dat = Common::makeZipArchive("wage.dat");
-
- if (!dat) {
- warning("Could not find wage.dat. Falling back to built-in fonts");
- _builtInFonts = true;
-
+// Render console
+void Gui::drawConsole() {
+ if (!_consoleDirty && !_consoleFullRedraw && !_sceneDirty)
return;
- }
- Common::ArchiveMemberList list;
- dat->listMembers(list);
-
- for (Common::ArchiveMemberList::iterator it = list.begin(); it != list.end(); ++it) {
- Common::SeekableReadStream *stream = dat->createReadStreamForMember((*it)->getName());
-
- Graphics::BdfFont *font = Graphics::BdfFont::loadFont(*stream);
-
- delete stream;
-
- Common::String fontName = (*it)->getName();
-
- // Trim the .bdf extension
- for (int i = fontName.size() - 1; i >= 0; --i) {
- if (fontName[i] == '.') {
- while ((uint)i < fontName.size()) {
- fontName.deleteLastChar();
- }
- break;
- }
- }
-
- FontMan.assignFontToName(fontName, font);
-
- debug(2, " %s", fontName.c_str());
- }
+ renderConsole(_consoleWindow->getSurface(), Common::Rect(kBorderWidth - 2, kBorderWidth - 2,
+ _consoleWindow->getDimensions().width(), _consoleWindow->getDimensions().height()));
+ _consoleWindow->setDirty(true);
+}
- _builtInFonts = false;
+static bool consoleWindowCallback(WindowClick click, Common::Event &event, void *g) {
+ Gui *gui = (Gui *)g;
- delete dat;
+ return gui->processConsoleEvents(click, event);
}
+////////////////
+// Menu stuff
+////////////////
void Gui::regenCommandsMenu() {
- _menu->regenCommandsMenu();
+ _menu->createSubMenuFromString(_commandsMenuId, _engine->_world->_commandsMenu.c_str());
}
void Gui::regenWeaponsMenu() {
- _menu->regenWeaponsMenu();
-}
-
-void Gui::processMenuShortCut(byte flags, uint16 ascii) {
- _menu->processMenuShortCut(flags, ascii);
-}
-
-void Gui::mouseMove(int x, int y) {
- if (_menu->_menuActivated) {
- if (_menu->mouseMove(x, y))
- _menuDirty = true;
-
+ if (_engine->_world->_weaponMenuDisabled)
return;
- }
- if (_inTextSelection) {
- updateTextSelection(x, y);
- return;
- }
+ _menu->clearSubMenu(_weaponsMenuId);
- if (_consoleTextArea.contains(x, y)) {
- if (_cursorIsArrow) {
- CursorMan.replaceCursor(macCursorBeam, 11, 16, 3, 8, 3);
- _cursorIsArrow = false;
- }
- } else if (_cursorIsArrow == false) {
- CursorMan.replaceCursor(macCursorArrow, 11, 16, 1, 1, 3);
- _cursorIsArrow = true;
- }
-}
-
-void Gui::pushArrowCursor() {
- CursorMan.pushCursor(macCursorArrow, 11, 16, 1, 1, 3);
-}
-
-void Gui::popCursor() {
- CursorMan.popCursor();
-}
-
-static int isInBorder(Common::Rect &rect, int x, int y) {
- if (x >= rect.left - kBorderWidth && x < rect.left && y >= rect.top - kBorderWidth && y < rect.top)
- return kBorderCloseButton;
-
- if (x >= rect.right && x < rect.right + kBorderWidth) {
- if (y < rect.top - kBorderWidth)
- return kBorderNone;
-
- if (y >= rect.bottom + kBorderWidth)
- return kBorderNone;
+ Chr *player = _engine->_world->_player;
+ ObjArray *weapons = player->getWeapons(true);
- if (y >= rect.top + rect.height() / 2)
- return kBorderScrollDown;
+ bool empty = true;
- return kBorderScrollUp;
- }
+ for (uint i = 0; i < weapons->size(); i++) {
+ Obj *obj = (*weapons)[i];
+ if (obj->_type == Obj::REGULAR_WEAPON ||
+ obj->_type == Obj::THROW_WEAPON ||
+ obj->_type == Obj::MAGICAL_OBJECT) {
+ Common::String command(obj->_operativeVerb);
+ command += " ";
+ command += obj->_name;
- return kBorderNone;
-}
+ _menu->addMenuSubItem(_weaponsMenuId, command.c_str(), kMenuActionCommand, 0, 0, true);
-Designed *Gui::mouseUp(int x, int y) {
- if (_menu->_menuActivated) {
- if (_menu->mouseRelease(x, y)) {
- _sceneDirty = true;
- _consoleDirty = true;
- _bordersDirty = true;
- _menuDirty = true;
+ empty = false;
}
-
- return NULL;
}
+ delete weapons;
- if (_inTextSelection) {
- _inTextSelection = false;
-
- if (_selectionEndY == -1 ||
- (_selectionEndX == _selectionStartX && _selectionEndY == _selectionStartY)) {
- _selectionStartY = _selectionEndY = -1;
- _consoleFullRedraw = true;
- _menu->enableCommand(kMenuEdit, kMenuActionCopy, false);
- } else {
- _menu->enableCommand(kMenuEdit, kMenuActionCopy, true);
-
- bool cutAllowed = false;
-
- if (_selectionStartY == _selectionEndY && _selectionStartY == (int)_lines.size() - 1)
- cutAllowed = true;
-
- _menu->enableCommand(kMenuEdit, kMenuActionCut, cutAllowed);
- _menu->enableCommand(kMenuEdit, kMenuActionClear, cutAllowed);
- }
- }
-
- int borderClick;
-
- if (_sceneArea.contains(x, y)) {
- if (!_sceneIsActive) {
- _sceneIsActive = true;
- _bordersDirty = true;
- }
-
- for (ObjList::const_iterator it = _scene->_objs.end(); it != _scene->_objs.begin(); ) {
- it--;
- if ((*it)->_design->isPointOpaque(x - _sceneArea.left + kBorderWidth, y - _sceneArea.top + kBorderWidth))
- return *it;
- }
-
- for (ChrList::const_iterator it = _scene->_chrs.end(); it != _scene->_chrs.begin(); ) {
- it--;
- if ((*it)->_design->isPointOpaque(x - _sceneArea.left + kBorderWidth, y - _sceneArea.top + kBorderWidth))
- return *it;
- }
- } else if (_consoleTextArea.contains(x, y)) {
- if (_sceneIsActive) {
- _sceneIsActive = false;
- _bordersDirty = true;
- }
- } else if ((borderClick = isInBorder(_consoleTextArea, x, y)) != kBorderNone) {
- _bordersDirty = true;
- int _oldScrollPos = _scrollPos;
-
- switch (borderClick) {
- case kBorderScrollUp:
- _scrollPos = MAX<int>(0, _scrollPos - _consoleLineHeight);
- undrawCursor();
- _cursorY -= (_scrollPos - _oldScrollPos);
- _consoleDirty = true;
- _consoleFullRedraw = true;
- break;
- case kBorderScrollDown:
- _scrollPos = MIN<int>((_lines.size() - 2) * _consoleLineHeight, _scrollPos + _consoleLineHeight);
- undrawCursor();
- _cursorY -= (_scrollPos - _oldScrollPos);
- _consoleDirty = true;
- _consoleFullRedraw = true;
- break;
- }
- }
-
- return NULL;
+ if (empty)
+ _menu->addMenuSubItem(_weaponsMenuId, "You have no weapons", 0, 0, 0, false);
}
-void Gui::mouseDown(int x, int y) {
- int borderClick;
-
- if (_menu->mouseClick(x, y)) {
- _menuDirty = true;
- } else if (_consoleTextArea.contains(x, y)) {
- startMarking(x, y);
- } else if ((borderClick = isInBorder(_consoleTextArea, x, y)) != kBorderNone) {
- int textFullSize = _lines.size() * _consoleLineHeight + _consoleTextArea.height();
- float scrollPos = (float)_scrollPos / textFullSize;
- float scrollSize = (float)_consoleTextArea.height() / textFullSize;
-
- paintBorder(&_screen, _consoleTextArea, kWindowConsole, borderClick, scrollPos, scrollSize);
- }
-}
-
-int Gui::calcTextX(int x, int textLine) {
- const Graphics::Font *font = getConsoleFont();
-
- if ((uint)textLine >= _lines.size())
- return 0;
-
- Common::String str = _lines[textLine];
-
- x -= _consoleTextArea.left;
-
- for (int i = str.size(); i >= 0; i--) {
- if (font->getStringWidth(str) < x) {
- return i;
- }
-
- str.deleteLastChar();
- }
-
- return 0;
+bool Gui::processEvent(Common::Event &event) {
+ return _wm.processEvent(event);
}
-int Gui::calcTextY(int y) {
- y -= _consoleTextArea.top;
-
- if (y < 0)
- y = 0;
+void menuCommandsCallback(int action, Common::String &text, void *data) {
+ Gui *g = (Gui *)data;
- const int firstLine = _scrollPos / _consoleLineHeight;
- int textLine = (y - _scrollPos % _consoleLineHeight) / _consoleLineHeight + firstLine;
-
- return textLine;
+ g->executeMenuCommand(action, text);
}
-void Gui::startMarking(int x, int y) {
- _selectionStartY = calcTextY(y);
- _selectionStartX = calcTextX(x, _selectionStartY);
-
- _selectionEndY = -1;
+void Gui::executeMenuCommand(int action, Common::String &text) {
+ switch(action) {
+ case kMenuActionAbout:
+ case kMenuActionNew:
+ case kMenuActionOpen:
+ case kMenuActionClose:
+ case kMenuActionSave:
+ case kMenuActionSaveAs:
+ case kMenuActionRevert:
+ case kMenuActionQuit:
+
+ case kMenuActionUndo:
+ actionUndo();
+ break;
+ case kMenuActionCut:
+ actionCut();
+ break;
+ case kMenuActionCopy:
+ actionCopy();
+ break;
+ case kMenuActionPaste:
+ actionPaste();
+ break;
+ case kMenuActionClear:
+ actionClear();
+ break;
- _inTextSelection = true;
-}
+ case kMenuActionCommand:
+ _engine->processTurn(&text, NULL);
+ break;
-void Gui::updateTextSelection(int x, int y) {
- _selectionEndY = calcTextY(y);
- _selectionEndX = calcTextX(x, _selectionEndY);
+ default:
+ warning("Unknown action: %d", action);
- _consoleFullRedraw = true;
+ }
}
} // End of namespace Wage
diff --git a/engines/wage/gui.h b/engines/wage/gui.h
index 11e001b274..ba1bb5ef3b 100644
--- a/engines/wage/gui.h
+++ b/engines/wage/gui.h
@@ -50,8 +50,8 @@
#include "common/str-array.h"
#include "graphics/font.h"
-#include "graphics/fontman.h"
-#include "graphics/surface.h"
+#include "graphics/managed_surface.h"
+#include "common/events.h"
#include "common/rect.h"
#include "wage/macwindow.h"
@@ -60,27 +60,13 @@
namespace Wage {
class Menu;
+class Scene;
+class WageEngine;
enum {
- kMenuHeight = 20,
- kMenuLeftMargin = 7,
- kMenuSpacing = 13,
- kMenuPadding = 16,
- kMenuDropdownPadding = 14,
- kMenuDropdownItemHeight = 16,
- kMenuItemHeight = 20,
- kDesktopArc = 7,
- kComponentsPadding = 10,
kCursorHeight = 12
};
-enum {
- kPatternSolid = 1,
- kPatternStripes = 2,
- kPatternCheckers = 3,
- kPatternCheckers2 = 4
-};
-
class Gui {
public:
Gui(WageEngine *engine);
@@ -89,17 +75,12 @@ public:
void draw();
void appendText(const char *str);
void clearOutput();
- void mouseMove(int x, int y);
- void mouseDown(int x, int y);
- Designed *mouseUp(int x, int y);
+ bool processEvent(Common::Event &event);
+
void drawInput();
void setSceneDirty() { _sceneDirty = true; }
- const Graphics::Font *getFont(const char *name, Graphics::FontManager::FontUsage fallback);
void regenCommandsMenu();
void regenWeaponsMenu();
- void processMenuShortCut(byte flags, uint16 ascii);
- void pushArrowCursor();
- void popCursor();
void actionCopy();
void actionPaste();
@@ -110,19 +91,15 @@ public:
void disableAllMenus();
void enableNewGameMenus();
- bool builtInFonts() { return _builtInFonts; }
+ bool processSceneEvents(WindowClick click, Common::Event &event);
+ bool processConsoleEvents(WindowClick click, Common::Event &event);
+ void executeMenuCommand(int action, Common::String &text);
private:
void drawScene();
void drawConsole();
void undrawCursor();
- void drawDesktop();
- void paintBorder(Graphics::Surface *g, Common::Rect &r, WindowType windowType, int highlightedPart = kBorderNone,
- float scrollPos = 0.0, float scrollSize = 0.0);
- void renderConsole(Graphics::Surface *g, Common::Rect &r);
- void drawBox(Graphics::Surface *g, int x, int y, int w, int h);
- void fillRect(Graphics::Surface *g, int x, int y, int w, int h, int color = kColorBlack);
- void loadFonts();
+ void renderConsole(Graphics::ManagedSurface *g, const Common::Rect &r);
void flowText(Common::String &str);
const Graphics::Font *getConsoleFont();
const Graphics::Font *getTitleFont();
@@ -132,29 +109,27 @@ private:
void updateTextSelection(int x, int y);
public:
- Graphics::Surface _screen;
+ Graphics::ManagedSurface _screen;
int _cursorX, _cursorY;
bool _cursorState;
- Common::Rect _consoleTextArea;
- bool _builtInFonts;
WageEngine *_engine;
- Patterns _patterns;
-
bool _cursorDirty;
Common::Rect _cursorRect;
bool _cursorOff;
- bool _menuDirty;
+ Scene *_scene;
+
+ MacWindowManager _wm;
+ MacWindow *_sceneWindow;
+ MacWindow *_consoleWindow;
private:
- Graphics::Surface _console;
+ Graphics::ManagedSurface _console;
Menu *_menu;
- Scene *_scene;
bool _sceneDirty;
bool _consoleDirty;
- bool _bordersDirty;
Common::StringArray _out;
Common::StringArray _lines;
@@ -163,10 +138,6 @@ private:
uint _consoleNumLines;
bool _consoleFullRedraw;
- Common::Rect _sceneArea;
- bool _sceneIsActive;
- bool _cursorIsArrow;
-
bool _inTextSelection;
int _selectionStartX;
int _selectionStartY;
@@ -178,9 +149,8 @@ private:
int _inputTextLineNum;
- MacWindowManager _wm;
- int _sceneWindowId;
- int _consoleWindowId;
+ int _commandsMenuId;
+ int _weaponsMenuId;
};
} // End of namespace Wage
diff --git a/engines/wage/menu.cpp b/engines/wage/macmenu.cpp
index 12ef8c2219..ed5f5070ff 100644
--- a/engines/wage/menu.cpp
+++ b/engines/wage/macmenu.cpp
@@ -48,15 +48,25 @@
#include "common/system.h"
#include "common/keyboard.h"
-#include "wage/wage.h"
-#include "wage/entities.h"
-#include "wage/design.h"
-#include "wage/gui.h"
-#include "wage/menu.h"
-#include "wage/world.h"
+#include "graphics/primitives.h"
+#include "graphics/font.h"
+
+#include "wage/macwindowmanager.h"
+#include "wage/macwindow.h"
+#include "wage/macmenu.h"
namespace Wage {
+enum {
+ kMenuHeight = 20,
+ kMenuLeftMargin = 7,
+ kMenuSpacing = 13,
+ kMenuPadding = 16,
+ kMenuDropdownPadding = 14,
+ kMenuDropdownItemHeight = 16,
+ kMenuItemHeight = 20
+};
+
struct MenuSubItem {
Common::String text;
int action;
@@ -79,66 +89,65 @@ struct MenuItem {
MenuItem(const char *n) : name(n) {}
};
-struct MenuData {
- int menunum;
- const char *title;
- int action;
- byte shortcut;
- bool enabled;
-} static const menuSubItems[] = {
- { kMenuFile, "New", kMenuActionNew, 0, false },
- { kMenuFile, "Open...", kMenuActionOpen, 0, false },
- { kMenuFile, "Close", kMenuActionClose, 0, true },
- { kMenuFile, "Save", kMenuActionSave, 0, false },
- { kMenuFile, "Save as...", kMenuActionSaveAs, 0, true },
- { kMenuFile, "Revert", kMenuActionRevert, 0, false },
- { kMenuFile, "Quit", kMenuActionQuit, 0, true },
-
- { kMenuEdit, "Undo", kMenuActionUndo, 'Z', false },
- { kMenuEdit, NULL, 0, 0, false },
- { kMenuEdit, "Cut", kMenuActionCut, 'K', false },
- { kMenuEdit, "Copy", kMenuActionCopy, 'C', false },
- { kMenuEdit, "Paste", kMenuActionPaste, 'V', false },
- { kMenuEdit, "Clear", kMenuActionClear, 'B', false },
-
- { 0, NULL, 0, 0, false }
-};
+Menu::Menu(int id, const Common::Rect &bounds, MacWindowManager *wm)
+ : BaseMacWindow(id, false, wm) {
+ _font = getMenuFont();
-Menu::Menu(Gui *gui) : _gui(gui) {
- assert(_gui->_engine);
- assert(_gui->_engine->_world);
+ _screen.create(bounds.width(), bounds.height(), Graphics::PixelFormat::createFormatCLUT8());
- _font = getMenuFont();
+ _bbox.left = 0;
+ _bbox.top = 0;
+ _bbox.right = _screen.w;
+ _bbox.bottom = kMenuHeight;
+
+ _menuActivated = false;
+ _activeItem = -1;
+ _activeSubItem = -1;
+
+ _ccallback = NULL;
+ _cdata = NULL;
+
+ _tempSurface.create(_screen.w, _font->getFontHeight(), Graphics::PixelFormat::createFormatCLUT8());
+}
+
+Menu::~Menu() {
+ for (uint i = 0; i < _items.size(); i++) {
+ for (uint j = 0; j < _items[i]->subitems.size(); j++)
+ delete _items[i]->subitems[j];
+ delete _items[i];
+ }
+}
- MenuItem *about = new MenuItem(_gui->_builtInFonts ? "\xa9" : "\xf0"); // (c) Symbol as the most resembling apple
+void Menu::addStaticMenus(const MenuData *data) {
+ MenuItem *about = new MenuItem(_wm->hasBuiltInFonts() ? "\xa9" : "\xf0"); // (c) Symbol as the most resembling apple
_items.push_back(about);
- _items[0]->subitems.push_back(new MenuSubItem(_gui->_engine->_world->getAboutMenuItemName(), kMenuActionAbout));
- MenuItem *file = new MenuItem("File");
- _items.push_back(file);
+ for (int i = 0; data[i].menunum; i++) {
+ const MenuData *m = &data[i];
- MenuItem *edit = new MenuItem("Edit");
- _items.push_back(edit);
+ if (m->menunum == kMenuHighLevel) {
+ MenuItem *item = new MenuItem(m->title);
+ _items.push_back(item);
- for (int i = 0; menuSubItems[i].menunum; i++) {
- const MenuData *m = &menuSubItems[i];
+ continue;
+ }
_items[m->menunum]->subitems.push_back(new MenuSubItem(m->title, m->action, 0, m->shortcut, m->enabled));
}
+}
- _commands = new MenuItem(_gui->_engine->_world->_commandsMenuName.c_str());
- _items.push_back(_commands);
- regenCommandsMenu();
-
- _weapons = NULL;
+int Menu::addMenuItem(const char *name) {
+ MenuItem *i = new MenuItem(name);
+ _items.push_back(i);
- if (!_gui->_engine->_world->_weaponMenuDisabled) {
- _weapons = new MenuItem(_gui->_engine->_world->_weaponsMenuName.c_str());
- _items.push_back(_weapons);
+ return _items.size() - 1;
+}
- regenWeaponsMenu();
- }
+void Menu::addMenuSubItem(int id, const char *text, int action, int style, char shortcut, bool enabled) {
+ _items[id]->subitems.push_back(new MenuSubItem(text, action, style, shortcut, enabled));
+}
+void Menu::calcDimensions() {
// Calculate menu dimensions
int y = 1;
int x = 18;
@@ -150,47 +159,29 @@ Menu::Menu(Gui *gui) : _gui(gui) {
_items[i]->bbox.left = x - kMenuLeftMargin;
_items[i]->bbox.top = y;
_items[i]->bbox.right = x + w + kMenuSpacing - kMenuLeftMargin;
- _items[i]->bbox.bottom = y + _font->getFontHeight() + (_gui->_builtInFonts ? 3 : 2);
+ _items[i]->bbox.bottom = y + _font->getFontHeight() + (_wm->hasBuiltInFonts() ? 3 : 2);
}
calcMenuBounds(_items[i]);
x += w + kMenuSpacing;
}
-
- _bbox.left = 0;
- _bbox.top = 0;
- _bbox.right = _gui->_screen.w - 1;
- _bbox.bottom = kMenuHeight - 1;
-
- _menuActivated = false;
- _activeItem = -1;
- _activeSubItem = -1;
-
- _screenCopy.create(_gui->_screen.w, _gui->_screen.h, Graphics::PixelFormat::createFormatCLUT8());
- _tempSurface.create(_gui->_screen.w, _font->getFontHeight(), Graphics::PixelFormat::createFormatCLUT8());
-}
-
-Menu::~Menu() {
- for (uint i = 0; i < _items.size(); i++) {
- for (uint j = 0; j < _items[i]->subitems.size(); j++)
- delete _items[i]->subitems[j];
- delete _items[i];
- }
}
-void Menu::regenCommandsMenu() {
- for (uint j = 0; j < _commands->subitems.size(); j++)
- delete _commands->subitems[j];
+void Menu::clearSubMenu(int id) {
+ MenuItem *menu = _items[id];
- _commands->subitems.clear();
+ for (uint j = 0; j < menu->subitems.size(); j++)
+ delete menu->subitems[j];
- createCommandsMenu(_commands);
- calcMenuBounds(_commands);
+ menu->subitems.clear();
}
-void Menu::createCommandsMenu(MenuItem *menu) {
- Common::String string(_gui->_engine->_world->_commandsMenu);
+void Menu::createSubMenuFromString(int id, const char *str) {
+ clearSubMenu(id);
+
+ MenuItem *menu = _items[id];
+ Common::String string(str);
Common::String item;
@@ -253,45 +244,12 @@ void Menu::createCommandsMenu(MenuItem *menu) {
item.clear();
}
-}
-
-void Menu::regenWeaponsMenu() {
- if (_gui->_engine->_world->_weaponMenuDisabled)
- return;
-
- for (uint j = 0; j < _weapons->subitems.size(); j++)
- delete _weapons->subitems[j];
-
- _weapons->subitems.clear();
-
- createWeaponsMenu(_weapons);
- calcMenuBounds(_weapons);
-}
-
-void Menu::createWeaponsMenu(MenuItem *menu) {
- Chr *player = _gui->_engine->_world->_player;
- ObjArray *weapons = player->getWeapons(true);
-
- for (uint i = 0; i < weapons->size(); i++) {
- Obj *obj = (*weapons)[i];
- if (obj->_type == Obj::REGULAR_WEAPON ||
- obj->_type == Obj::THROW_WEAPON ||
- obj->_type == Obj::MAGICAL_OBJECT) {
- Common::String command(obj->_operativeVerb);
- command += " ";
- command += obj->_name;
-
- menu->subitems.push_back(new MenuSubItem(command.c_str(), kMenuActionCommand, 0, 0, true));
- }
- }
- delete weapons;
- if (menu->subitems.empty())
- menu->subitems.push_back(new MenuSubItem("You have no weapons", 0, 0, 0, false));
+ calcMenuBounds(menu);
}
const Graphics::Font *Menu::getMenuFont() {
- return _gui->getFont("Chicago-12", Graphics::FontManager::kBigGUIFont);
+ return _wm->getFont("Chicago-12", Graphics::FontManager::kBigGUIFont);
}
const char *Menu::getAcceleratorString(MenuSubItem *item, const char *prefix) {
@@ -299,7 +257,7 @@ const char *Menu::getAcceleratorString(MenuSubItem *item, const char *prefix) {
*res = 0;
if (item->shortcut != 0)
- sprintf(res, "%s%c%c", prefix, (_gui->_builtInFonts ? '^' : '\x11'), item->shortcut);
+ sprintf(res, "%s%c%c", prefix, (_wm->hasBuiltInFonts() ? '^' : '\x11'), item->shortcut);
return res;
}
@@ -338,14 +296,35 @@ void Menu::calcMenuBounds(MenuItem *menu) {
menu->subbbox.bottom = y2;
}
-void Menu::render() {
+static void drawPixelPlain(int x, int y, int color, void *data) {
+ Graphics::ManagedSurface *surface = (Graphics::ManagedSurface *)data;
+
+ if (x >= 0 && x < surface->w && y >= 0 && y < surface->h)
+ *((byte *)surface->getBasePtr(x, y)) = (byte)color;
+}
+
+static void drawFilledRoundRect(Graphics::ManagedSurface *surface, Common::Rect &rect, int arc, int color) {
+ Graphics::drawRoundRect(rect, arc, color, true, drawPixelPlain, surface);
+}
+
+bool Menu::draw(Graphics::ManagedSurface *g, bool forceRedraw) {
Common::Rect r(_bbox);
- Design::drawFilledRoundRect(&_gui->_screen, r, kDesktopArc, kColorWhite, _gui->_patterns, kPatternSolid);
+ if (!_contentIsDirty && !forceRedraw)
+ return false;
+
+ _contentIsDirty = false;
+
+ _screen.clear(kColorGreen);
+
+ drawFilledRoundRect(&_screen, r, kDesktopArc, kColorWhite);
r.top = 7;
- Design::drawFilledRect(&_gui->_screen, r, kColorWhite, _gui->_patterns, kPatternSolid);
+ _screen.fillRect(r, kColorWhite);
r.top = kMenuHeight - 1;
- Design::drawFilledRect(&_gui->_screen, r, kColorBlack, _gui->_patterns, kPatternSolid);
+ r.bottom++;
+ _screen.fillRect(r, kColorGreen);
+ r.bottom--;
+ _screen.fillRect(r, kColorBlack);
for (uint i = 0; i < _items.size(); i++) {
int color = kColorBlack;
@@ -355,19 +334,24 @@ void Menu::render() {
Common::Rect hbox = it->bbox;
hbox.left -= 1;
- hbox.right += 2;
+ hbox.right += 3;
+ hbox.bottom += 1;
- Design::drawFilledRect(&_gui->_screen, hbox, kColorBlack, _gui->_patterns, kPatternSolid);
+ _screen.fillRect(hbox, kColorBlack);
color = kColorWhite;
if (!it->subitems.empty())
renderSubmenu(it);
}
- _font->drawString(&_gui->_screen, it->name, it->bbox.left + kMenuLeftMargin, it->bbox.top + (_gui->_builtInFonts ? 2 : 1), it->bbox.width(), color);
+ _font->drawString(&_screen, it->name, it->bbox.left + kMenuLeftMargin, it->bbox.top + (_wm->hasBuiltInFonts() ? 2 : 1), it->bbox.width(), color);
}
- g_system->copyRectToScreen(_gui->_screen.getPixels(), _gui->_screen.pitch, 0, 0, _gui->_screen.w, kMenuHeight);
+ g->transBlitFrom(_screen, kColorGreen);
+
+ g_system->copyRectToScreen(g->getPixels(), g->pitch, 0, 0, g->w, g->h);
+
+ return true;
}
void Menu::renderSubmenu(MenuItem *menu) {
@@ -376,10 +360,12 @@ void Menu::renderSubmenu(MenuItem *menu) {
if (r->width() == 0 || r->height() == 0)
return;
- Design::drawFilledRect(&_gui->_screen, *r, kColorWhite, _gui->_patterns, kPatternSolid);
- Design::drawRect(&_gui->_screen, *r, 1, kColorBlack, _gui->_patterns, kPatternSolid);
- Design::drawVLine(&_gui->_screen, r->right + 1, r->top + 3, r->bottom + 1, 1, kColorBlack, _gui->_patterns, kPatternSolid);
- Design::drawHLine(&_gui->_screen, r->left + 3, r->right + 1, r->bottom + 1, 1, kColorBlack, _gui->_patterns, kPatternSolid);
+ _screen.fillRect(*r, kColorWhite);
+ _screen.frameRect(*r, kColorBlack);
+ _screen.vLine(r->right, r->top + 3, r->bottom + 1, kColorBlack);
+ _screen.vLine(r->right + 1, r->top + 3, r->bottom + 1, kColorBlack);
+ _screen.hLine(r->left + 3, r->bottom, r->right + 1, kColorBlack);
+ _screen.hLine(r->left + 3, r->bottom + 1, r->right + 1, kColorBlack);
int x = r->left + kMenuDropdownPadding;
int y = r->top + 1;
@@ -391,13 +377,13 @@ void Menu::renderSubmenu(MenuItem *menu) {
int color = kColorBlack;
if (i == (uint)_activeSubItem && !text.empty() && menu->subitems[i]->enabled) {
color = kColorWhite;
- Common::Rect trect(r->left, y - (_gui->_builtInFonts ? 1 : 0), r->right, y + _font->getFontHeight());
+ Common::Rect trect(r->left, y - (_wm->hasBuiltInFonts() ? 1 : 0), r->right, y + _font->getFontHeight());
- Design::drawFilledRect(&_gui->_screen, trect, kColorBlack, _gui->_patterns, kPatternSolid);
+ _screen.fillRect(trect, kColorBlack);
}
if (!text.empty()) {
- Graphics::Surface *s = &_gui->_screen;
+ Graphics::ManagedSurface *s = &_screen;
int tx = x, ty = y;
if (!menu->subitems[i]->enabled) {
@@ -406,7 +392,7 @@ void Menu::renderSubmenu(MenuItem *menu) {
ty = 0;
accelX -= x;
- _tempSurface.fillRect(Common::Rect(0, 0, _tempSurface.w, _tempSurface.h), kColorGreen);
+ _tempSurface.clear(kColorGreen);
}
_font->drawString(s, text, tx, ty, r->width(), color);
@@ -419,8 +405,8 @@ void Menu::renderSubmenu(MenuItem *menu) {
// fake it here
for (int ii = 0; ii < _tempSurface.h; ii++) {
const byte *src = (const byte *)_tempSurface.getBasePtr(0, ii);
- byte *dst = (byte *)_gui->_screen.getBasePtr(x, y+ii);
- byte pat = _gui->_patterns[kPatternCheckers2 - 1][ii % 8];
+ byte *dst = (byte *)_screen.getBasePtr(x, y+ii);
+ byte pat = _wm->getPatterns()[kPatternCheckers2 - 1][ii % 8];
for (int j = 0; j < r->width(); j++) {
if (*src != kColorGreen && (pat & (1 << (7 - (x + j) % 8))))
*dst = *src;
@@ -430,20 +416,51 @@ void Menu::renderSubmenu(MenuItem *menu) {
}
}
} else { // Delimiter
- Design::drawHLine(&_gui->_screen, r->left + 1, r->right - 1, y + kMenuDropdownItemHeight / 2, 1, kColorBlack, _gui->_patterns, kPatternStripes);
+ bool flip = r->left & 2;
+ byte *ptr = (byte *)_screen.getBasePtr(r->left + 1, y + kMenuDropdownItemHeight / 2);
+ for (int xx = r->left + 1; xx <= r->right - 1; xx++, ptr++) {
+ *ptr = flip ? kColorBlack : kColorWhite;
+ flip = !flip;
+ }
}
y += kMenuDropdownItemHeight;
}
- g_system->copyRectToScreen(_gui->_screen.getBasePtr(r->left, r->top), _gui->_screen.pitch, r->left, r->top, r->width() + 3, r->height() + 3);
+ _contentIsDirty = true;
+ //g_system->copyRectToScreen(_screen.getBasePtr(r->left, r->top), _screen.pitch, r->left, r->top, r->width() + 2, r->height() + 2);
+}
+
+bool Menu::processEvent(Common::Event &event) {
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ return keyEvent(event);
+ case Common::EVENT_LBUTTONDOWN:
+ return mouseClick(event.mouse.x, event.mouse.y);
+ case Common::EVENT_LBUTTONUP:
+ return mouseRelease(event.mouse.x, event.mouse.y);
+ case Common::EVENT_MOUSEMOVE:
+ return mouseMove(event.mouse.x, event.mouse.y);
+ default:
+ return false;
+ }
+}
+
+bool Menu::keyEvent(Common::Event &event) {
+ if (event.type != Common::EVENT_KEYDOWN)
+ return false;
+
+ if (event.kbd.flags & (Common::KBD_ALT | Common::KBD_CTRL | Common::KBD_META)) {
+ if (event.kbd.ascii >= 0x20 && event.kbd.ascii <= 0x7f) {
+ return processMenuShortCut(event.kbd.flags, event.kbd.ascii);
+ }
+ }
+
+ return false;
}
bool Menu::mouseClick(int x, int y) {
if (_bbox.contains(x, y)) {
- if (!_menuActivated)
- _screenCopy.copyFrom(_gui->_screen);
-
for (uint i = 0; i < _items.size(); i++)
if (_items[i]->bbox.contains(x, y)) {
if ((uint)_activeItem == i)
@@ -454,14 +471,15 @@ bool Menu::mouseClick(int x, int y) {
r.right += 3;
r.bottom += 3;
- _gui->_screen.copyRectToSurface(_screenCopy, r.left, r.top, r);
- g_system->copyRectToScreen(_gui->_screen.getBasePtr(r.left, r.top), _gui->_screen.pitch, r.left, r.top, r.width() + 1, r.height() + 1);
+ _wm->setFullRefresh(true);
}
_activeItem = i;
_activeSubItem = -1;
_menuActivated = true;
+ _contentIsDirty = true;
+
return true;
}
} else if (_menuActivated && _items[_activeItem]->subbbox.contains(x, y)) {
@@ -472,11 +490,13 @@ bool Menu::mouseClick(int x, int y) {
_activeSubItem = numSubItem;
renderSubmenu(_items[_activeItem]);
+ _contentIsDirty = true;
}
} else if (_menuActivated && _activeItem != -1) {
_activeSubItem = -1;
renderSubmenu(_items[_activeItem]);
+ _contentIsDirty = true;
}
return false;
@@ -495,77 +515,49 @@ bool Menu::mouseRelease(int x, int y) {
_menuActivated = false;
if (_activeItem != -1 && _activeSubItem != -1 && _items[_activeItem]->subitems[_activeSubItem]->enabled)
- executeCommand(_items[_activeItem]->subitems[_activeSubItem]);
+ (*_ccallback)(_items[_activeItem]->subitems[_activeSubItem]->action,
+ _items[_activeItem]->subitems[_activeSubItem]->text, _cdata);
_activeItem = -1;
_activeSubItem = -1;
+ _wm->setFullRefresh(true);
+
return true;
}
return false;
}
-void Menu::executeCommand(MenuSubItem *subitem) {
- switch(subitem->action) {
- case kMenuActionAbout:
- case kMenuActionNew:
- case kMenuActionOpen:
- case kMenuActionClose:
- case kMenuActionSave:
- case kMenuActionSaveAs:
- case kMenuActionRevert:
- case kMenuActionQuit:
-
- case kMenuActionUndo:
- _gui->actionUndo();
- break;
- case kMenuActionCut:
- _gui->actionCut();
- break;
- case kMenuActionCopy:
- _gui->actionCopy();
- break;
- case kMenuActionPaste:
- _gui->actionPaste();
- break;
- case kMenuActionClear:
- _gui->actionClear();
- break;
-
- case kMenuActionCommand:
- _gui->_engine->processTurn(&subitem->text, NULL);
- break;
-
- default:
- warning("Unknown action: %d", subitem->action);
-
- }
-}
-
-void Menu::processMenuShortCut(byte flags, uint16 ascii) {
+bool Menu::processMenuShortCut(byte flags, uint16 ascii) {
ascii = tolower(ascii);
if (flags & (Common::KBD_CTRL | Common::KBD_META)) {
for (uint i = 0; i < _items.size(); i++)
for (uint j = 0; j < _items[i]->subitems.size(); j++)
if (_items[i]->subitems[j]->enabled && tolower(_items[i]->subitems[j]->shortcut) == ascii) {
- executeCommand(_items[i]->subitems[j]);
- break;
+ (*_ccallback)(_items[i]->subitems[j]->action, _items[i]->subitems[j]->text, _cdata);
+ return true;
}
}
+
+ return false;
}
void Menu::enableCommand(int menunum, int action, bool state) {
for (uint i = 0; i < _items[menunum]->subitems.size(); i++)
if (_items[menunum]->subitems[i]->action == action)
_items[menunum]->subitems[i]->enabled = state;
+
+ _contentIsDirty = true;
}
void Menu::disableAllMenus() {
for (uint i = 1; i < _items.size(); i++) // Leave About menu on
for (uint j = 0; j < _items[i]->subitems.size(); j++)
_items[i]->subitems[j]->enabled = false;
+
+ _contentIsDirty = true;
}
} // End of namespace Wage
diff --git a/engines/wage/menu.h b/engines/wage/macmenu.h
index 3550356bc6..e73e4c48a9 100644
--- a/engines/wage/menu.h
+++ b/engines/wage/macmenu.h
@@ -45,8 +45,8 @@
*
*/
-#ifndef WAGE_MENU_H
-#define WAGE_MENU_H
+#ifndef WAGE_MACMENU_H
+#define WAGE_MACMENU_H
namespace Wage {
@@ -64,6 +64,7 @@ enum {
};
enum {
+ kMenuHighLevel = -1,
kMenuAbout = 0,
kMenuFile = 1,
kMenuEdit = 2,
@@ -90,29 +91,43 @@ enum {
kMenuActionCommand
};
-class Menu {
+struct MenuData {
+ int menunum;
+ const char *title;
+ int action;
+ byte shortcut;
+ bool enabled;
+};
+
+class Menu : public BaseMacWindow {
public:
- Menu(Gui *gui);
+ Menu(int id, const Common::Rect &bounds, MacWindowManager *wm);
~Menu();
- void render();
- bool mouseClick(int x, int y);
- bool mouseRelease(int x, int y);
- bool mouseMove(int x, int y);
+ void setCommandsCallback(void (*callback)(int, Common::String &, void *), void *data) { _ccallback = callback; _cdata = data; }
+
+ void addStaticMenus(const MenuData *data);
+ void calcDimensions();
+
+ int addMenuItem(const char *name);
+ void addMenuSubItem(int id, const char *text, int action, int style = 0, char shortcut = 0, bool enabled = true);
+ void createSubMenuFromString(int id, const char *string);
+ void clearSubMenu(int id);
+
+ bool draw(Graphics::ManagedSurface *g, bool forceRedraw = false);
+ bool processEvent(Common::Event &event);
- void regenCommandsMenu();
- void regenWeaponsMenu();
- void processMenuShortCut(byte flags, uint16 ascii);
void enableCommand(int menunum, int action, bool state);
void disableAllMenus();
- bool _menuActivated;
+ void setActive(bool active) { _menuActivated = active; }
+ bool hasAllFocus() { return _menuActivated; }
+
Common::Rect _bbox;
private:
- Gui *_gui;
- Graphics::Surface _screenCopy;
- Graphics::Surface _tempSurface;
+ Graphics::ManagedSurface _screen;
+ Graphics::ManagedSurface _tempSurface;
private:
const Graphics::Font *getMenuFont();
@@ -120,18 +135,25 @@ private:
int calculateMenuWidth(MenuItem *menu);
void calcMenuBounds(MenuItem *menu);
void renderSubmenu(MenuItem *menu);
- void createCommandsMenu(MenuItem *menu);
- void createWeaponsMenu(MenuItem *menu);
- void executeCommand(MenuSubItem *subitem);
+
+ bool keyEvent(Common::Event &event);
+ bool mouseClick(int x, int y);
+ bool mouseRelease(int x, int y);
+ bool mouseMove(int x, int y);
+
+ bool processMenuShortCut(byte flags, uint16 ascii);
Common::Array<MenuItem *> _items;
- MenuItem *_weapons;
- MenuItem *_commands;
const Graphics::Font *_font;
+ bool _menuActivated;
+
int _activeItem;
int _activeSubItem;
+
+ void (*_ccallback)(int action, Common::String &text, void *data);
+ void *_cdata;
};
} // End of namespace Wage
diff --git a/engines/wage/macwindow.cpp b/engines/wage/macwindow.cpp
index 3abfdf6017..8903936061 100644
--- a/engines/wage/macwindow.cpp
+++ b/engines/wage/macwindow.cpp
@@ -45,26 +45,49 @@
*
*/
+#include "graphics/font.h"
#include "graphics/primitives.h"
+#include "common/events.h"
-#include "wage/wage.h"
-#include "wage/gui.h"
#include "wage/macwindow.h"
+#include "wage/macwindowmanager.h"
namespace Wage {
-MacWindow::MacWindow(bool scrollable) : _scrollable(scrollable) {
+BaseMacWindow::BaseMacWindow(int id, bool editable, MacWindowManager *wm) :
+ _id(id), _editable(editable), _wm(wm) {
+ _callback = 0;
+ _dataPtr = 0;
+
+ _contentIsDirty = true;
+
+ _type = kWindowUnknown;
+}
+
+MacWindow::MacWindow(int id, bool scrollable, bool resizable, bool editable, MacWindowManager *wm) :
+ BaseMacWindow(id, editable, wm), _scrollable(scrollable), _resizable(resizable) {
_active = false;
_borderIsDirty = true;
_highlightedPart = kBorderNone;
_scrollPos = _scrollSize = 0.0;
+
+ _beingDragged = false;
+ _beingResized = false;
+
+ _draggedX = _draggedY = 0;
+
+ _type = kWindowWindow;
}
MacWindow::~MacWindow() {
}
+const Graphics::Font *MacWindow::getTitleFont() {
+ return _wm->getFont("Chicago-12", Graphics::FontManager::kBigGUIFont);
+}
+
void MacWindow::setActive(bool active) {
if (active == _active)
return;
@@ -80,37 +103,53 @@ void MacWindow::resize(int w, int h) {
_surface.free();
_surface.create(w, h, Graphics::PixelFormat::createFormatCLUT8());
_borderSurface.free();
- _borderSurface.create(w + 2 * kBorderWidth, h + 2 * kBorderWidth, Graphics::PixelFormat::createFormatCLUT8());
+ _borderSurface.create(w, h, Graphics::PixelFormat::createFormatCLUT8());
+ _composeSurface.free();
+ _composeSurface.create(w, h, Graphics::PixelFormat::createFormatCLUT8());
_dims.setWidth(w);
_dims.setHeight(h);
- _borderDims.setWidth(w + 2 * kBorderWidth);
- _borderDims.setHeight(h + 2 * kBorderWidth);
- move(_dims.left, _dims.top); // Update _borderDims position
+ updateInnerDims();
+
+ _contentIsDirty = true;
+ _borderIsDirty = true;
}
void MacWindow::move(int x, int y) {
+ if (_dims.left == x && _dims.top == y)
+ return;
+
_dims.moveTo(x, y);
- _borderDims.moveTo(x - kBorderWidth, y - kBorderWidth);
+ updateInnerDims();
+
+ _contentIsDirty = true;
}
void MacWindow::setDimensions(const Common::Rect &r) {
resize(r.width(), r.height());
- move(r.left, r.top);
+ _dims.moveTo(r.left, r.top);
+ updateInnerDims();
+
+ _contentIsDirty = true;
}
-void MacWindow::draw(Graphics::Surface *g, bool forceRedraw) {
+bool MacWindow::draw(Graphics::ManagedSurface *g, bool forceRedraw) {
+ if (!_borderIsDirty && !_contentIsDirty && !forceRedraw)
+ return false;
+
if (_borderIsDirty || forceRedraw)
drawBorder();
-}
-const Graphics::Font *MacWindow::getTitleFont() {
- return ((WageEngine *)g_engine)->_gui->getFont("Chicago-12", Graphics::FontManager::kBigGUIFont);
-}
+ _contentIsDirty = false;
-bool MacWindow::builtInFonts() {
- return ((WageEngine *)g_engine)->_gui->builtInFonts();
+ // Compose
+ _composeSurface.blitFrom(_surface, Common::Rect(0, 0, _surface.w - 2, _surface.h - 2), Common::Point(2, 2));
+ _composeSurface.transBlitFrom(_borderSurface, kColorGreen);
+
+ g->transBlitFrom(_composeSurface, _composeSurface.getBounds(), Common::Point(_dims.left - 2, _dims.top - 2), kColorGreen2);
+
+ return true;
}
#define ARROW_W 12
@@ -124,7 +163,7 @@ const int arrowPixels[ARROW_H][ARROW_W] = {
{1,1,1,1,1,1,1,1,1,1,1,1}};
static void drawPixelInverted(int x, int y, int color, void *data) {
- Graphics::Surface *surface = (Graphics::Surface *)data;
+ Graphics::ManagedSurface *surface = (Graphics::ManagedSurface *)data;
if (x >= 0 && x < surface->w && y >= 0 && y < surface->h) {
byte *p = (byte *)surface->getBasePtr(x, y);
@@ -133,10 +172,15 @@ static void drawPixelInverted(int x, int y, int color, void *data) {
}
}
+void MacWindow::updateInnerDims() {
+ _innerDims = _dims;
+ _innerDims.grow(-kBorderWidth);
+}
+
void MacWindow::drawBorder() {
_borderIsDirty = false;
- bool active = _active, scrollable = _scrollable, closeable = _active, drawTitle = _title.empty();
+ bool active = _active, scrollable = _scrollable, closeable = _active, drawTitle = !_title.empty();
const int size = kBorderWidth;
int x = 0;
int y = 0;
@@ -144,7 +188,11 @@ void MacWindow::drawBorder() {
int height = _borderSurface.h;
Graphics::ManagedSurface *g = &_borderSurface;
- g->fillRect(_borderDims, kColorGreen2);
+ // We draw rect with outer kColorGreen2 and inner kColorGreen, so on 2 passes we cut out
+ // scene by external shape of the border
+ int sz = kBorderWidth / 2;
+ g->clear(kColorGreen2);
+ g->fillRect(Common::Rect(sz, sz, width - sz, height - sz), kColorGreen);
drawBox(g, x, y, size, size);
drawBox(g, x + width - size - 1, y, size, size);
@@ -156,11 +204,11 @@ void MacWindow::drawBorder() {
drawBox(g, x + width - size + 1, y + size, size - 4, height - 2 * size - 1);
if (active) {
- fillRect(g, x + size, y + 5, width - 2 * size - 1, 8);
- fillRect(g, x + size, y + height - 13, width - 2 * size - 1, 8);
- fillRect(g, x + 5, y + size, 8, height - 2 * size - 1);
+ fillRect(g, x + size, y + 5, width - 2 * size - 1, 8, kColorBlack);
+ fillRect(g, x + size, y + height - 13, width - 2 * size - 1, 8, kColorBlack);
+ fillRect(g, x + 5, y + size, 8, height - 2 * size - 1, kColorBlack);
if (!scrollable) {
- fillRect(g, x + width - 13, y + size, 8, height - 2 * size - 1);
+ fillRect(g, x + width - 13, y + size, 8, height - 2 * size - 1, kColorBlack);
} else {
int x1 = x + width - 15;
int y1 = y + size + 1;
@@ -170,7 +218,7 @@ void MacWindow::drawBorder() {
g->hLine(x1 + xx, y1 + yy, x1 + xx, (arrowPixels[yy][xx] != 0 ? kColorBlack : kColorWhite));
}
- fillRect(g, x + width - 13, y + size + ARROW_H, 8, height - 2 * size - 1 - ARROW_H * 2);
+ fillRect(g, x + width - 13, y + size + ARROW_H, 8, height - 2 * size - 1 - ARROW_H * 2, kColorBlack);
y1 += height - 2 * size - ARROW_H - 2;
for (int yy = 0; yy < ARROW_H; yy++) {
@@ -190,7 +238,7 @@ void MacWindow::drawBorder() {
}
if (closeable) {
if (_highlightedPart == kBorderCloseButton) {
- fillRect(g, x + 6, y + 6, 6, 6);
+ fillRect(g, x + 6, y + 6, 6, 6, kColorBlack);
} else {
drawBox(g, x + 5, y + 5, 7, 7);
}
@@ -199,7 +247,7 @@ void MacWindow::drawBorder() {
if (drawTitle) {
const Graphics::Font *font = getTitleFont();
- int yOff = builtInFonts() ? 3 : 1;
+ int yOff = _wm->hasBuiltInFonts() ? 3 : 1;
int w = font->getStringWidth(_title) + 10;
int maxWidth = width - size * 2 - 7;
@@ -210,6 +258,24 @@ void MacWindow::drawBorder() {
}
}
+void MacWindow::setHighlight(WindowClick highlightedPart) {
+ if (_highlightedPart == highlightedPart)
+ return;
+
+ _highlightedPart = highlightedPart;
+ _borderIsDirty = true;
+ }
+
+ void MacWindow::setScroll(float scrollPos, float scrollSize) {
+ if (_scrollPos == scrollPos && _scrollSize == scrollSize)
+ return;
+
+ _scrollPos = scrollPos;
+ _scrollSize = scrollSize;
+ _borderIsDirty = true;
+ }
+
+
void MacWindow::drawBox(Graphics::ManagedSurface *g, int x, int y, int w, int h) {
Common::Rect r(x, y, x + w + 1, y + h + 1);
@@ -223,4 +289,88 @@ void MacWindow::fillRect(Graphics::ManagedSurface *g, int x, int y, int w, int h
g->fillRect(r, color);
}
+WindowClick MacWindow::isInBorder(int x, int y) {
+ if (_innerDims.contains(x, y))
+ return kBorderInner;
+
+ if (x >= _innerDims.left - kBorderWidth && x < _innerDims.left && y >= _innerDims.top - kBorderWidth && y < _innerDims.top)
+ return kBorderCloseButton;
+
+ if (_resizable)
+ if (x >= _innerDims.right && x < _innerDims.right + kBorderWidth && y >= _innerDims.bottom && y < _innerDims.bottom + kBorderWidth)
+ return kBorderResizeButton;
+
+ if (_scrollable && x >= _innerDims.right && x < _innerDims.right + kBorderWidth) {
+ if (y < _innerDims.top - kBorderWidth)
+ return kBorderBorder;
+
+ if (y >= _innerDims.bottom + kBorderWidth)
+ return kBorderBorder;
+
+ if (y >= _innerDims.top + _innerDims.height() / 2)
+ return kBorderScrollDown;
+
+ return kBorderScrollUp;
+ }
+
+ return kBorderBorder;
+}
+
+bool MacWindow::processEvent(Common::Event &event) {
+ WindowClick click = isInBorder(event.mouse.x, event.mouse.y);
+
+ switch (event.type) {
+ case Common::EVENT_MOUSEMOVE:
+ if (_beingDragged) {
+ _dims.translate(event.mouse.x - _draggedX, event.mouse.y - _draggedY);
+ updateInnerDims();
+
+ _draggedX = event.mouse.x;
+ _draggedY = event.mouse.y;
+
+ _wm->setFullRefresh(true);
+ }
+
+ if (_beingResized) {
+ resize(MAX(kBorderWidth * 4, _dims.width() + event.mouse.x - _draggedX),
+ MAX(kBorderWidth * 4, _dims.height() + event.mouse.y - _draggedY));
+
+ _draggedX = event.mouse.x;
+ _draggedY = event.mouse.y;
+
+ _wm->setFullRefresh(true);
+ (*_callback)(click, event, _dataPtr);
+ }
+ break;
+ case Common::EVENT_LBUTTONDOWN:
+ setHighlight(click);
+
+ if (click == kBorderBorder) {
+ _beingDragged = true;
+
+ _draggedX = event.mouse.x;
+ _draggedY = event.mouse.y;
+ }
+
+ if (click == kBorderResizeButton) {
+ _beingResized = true;
+
+ _draggedX = event.mouse.x;
+ _draggedY = event.mouse.y;
+ }
+
+ break;
+ case Common::EVENT_LBUTTONUP:
+ _beingDragged = false;
+ _beingResized = false;
+
+ setHighlight(kBorderNone);
+ break;
+ default:
+ return false;
+ }
+
+ return (*_callback)(click, event, _dataPtr);
+}
+
} // End of namespace Wage
diff --git a/engines/wage/macwindow.h b/engines/wage/macwindow.h
index 0d7d49f06d..4c6e9efeff 100644
--- a/engines/wage/macwindow.h
+++ b/engines/wage/macwindow.h
@@ -52,55 +52,106 @@
namespace Wage {
+class MacWindowManager;
+
enum WindowType {
- kWindowScene,
- kWindowConsole
+ kWindowUnknown,
+ kWindowWindow,
+ kWindowMenu
};
enum {
kBorderWidth = 17
};
-enum BorderHighlight {
+enum WindowClick {
kBorderNone = 0,
kBorderScrollUp,
kBorderScrollDown,
- kBorderCloseButton
+ kBorderCloseButton,
+ kBorderInner,
+ kBorderBorder,
+ kBorderResizeButton
};
-class MacWindow {
+class BaseMacWindow {
public:
- MacWindow(bool scrollable);
- ~MacWindow();
+ BaseMacWindow(int id, bool editable, MacWindowManager *wm);
+ virtual ~BaseMacWindow() {}
+
+ const Common::Rect &getDimensions() { return _dims; }
+ int getId() { return _id; }
+ WindowType getType() { return _type; }
+ bool isEditable() { return _editable; }
+ Graphics::ManagedSurface *getSurface() { return &_surface; }
+ virtual void setActive(bool active) = 0;
+ void setDirty(bool dirty) { _contentIsDirty = dirty; }
+
+ virtual bool draw(Graphics::ManagedSurface *g, bool forceRedraw = false) = 0;
+ virtual bool processEvent(Common::Event &event) = 0;
+
+ virtual bool hasAllFocus() = 0;
+
+ void setCallback(bool (*callback)(WindowClick, Common::Event &, void *), void *data) { _callback = callback; _dataPtr = data; }
+
+protected:
+ int _id;
+ WindowType _type;
+
+ bool _editable;
+
+ Graphics::ManagedSurface _surface;
+ bool _contentIsDirty;
+
+ Common::Rect _dims;
+
+ bool (*_callback)(WindowClick, Common::Event &, void *);
+ void *_dataPtr;
+
+ MacWindowManager *_wm;
+};
+
+class MacWindow : public BaseMacWindow {
+public:
+ MacWindow(int id, bool scrollable, bool resizable, bool editable, MacWindowManager *wm);
+ virtual ~MacWindow();
void move(int x, int y);
void resize(int w, int h);
void setDimensions(const Common::Rect &r);
- void draw(Graphics::Surface *g, bool forceRedraw = false);
+ const Common::Rect &getInnerDimensions() { return _innerDims; }
+
+ bool draw(Graphics::ManagedSurface *g, bool forceRedraw = false);
+
void setActive(bool active);
- Graphics::ManagedSurface *getSurface() { return &_surface; }
void setTitle(Common::String &title) { _title = title; }
- void setHighlight(BorderHighlight highlightedPart) { _highlightedPart = highlightedPart; }
- void setScroll(float scrollPos, float scrollSize) { _scrollPos = scrollPos; _scrollSize = scrollSize; }
+ void setHighlight(WindowClick highlightedPart);
+ void setScroll(float scrollPos, float scrollSize);
+ bool processEvent(Common::Event &event);
+ bool hasAllFocus() { return _beingDragged || _beingResized; }
private:
void drawBorder();
void drawBox(Graphics::ManagedSurface *g, int x, int y, int w, int h);
- void fillRect(Graphics::ManagedSurface *g, int x, int y, int w, int h, int color = kColorBlack);
+ void fillRect(Graphics::ManagedSurface *g, int x, int y, int w, int h, int color);
const Graphics::Font *getTitleFont();
- bool builtInFonts();
+ void updateInnerDims();
+ WindowClick isInBorder(int x, int y);
private:
- Graphics::ManagedSurface _surface;
Graphics::ManagedSurface _borderSurface;
+ Graphics::ManagedSurface _composeSurface;
bool _scrollable;
+ bool _resizable;
bool _active;
bool _borderIsDirty;
- BorderHighlight _highlightedPart;
+ bool _beingDragged, _beingResized;
+ int _draggedX, _draggedY;
+
+ WindowClick _highlightedPart;
float _scrollPos, _scrollSize;
- Common::Rect _dims;
- Common::Rect _borderDims;
+ Common::Rect _innerDims;
Common::String _title;
};
diff --git a/engines/wage/macwindowmanager.cpp b/engines/wage/macwindowmanager.cpp
index 14c3f236e8..5cc54d648a 100644
--- a/engines/wage/macwindowmanager.cpp
+++ b/engines/wage/macwindowmanager.cpp
@@ -45,38 +45,127 @@
*
*/
-#include "common/list.h"
#include "common/array.h"
+#include "common/events.h"
+#include "common/list.h"
+#include "common/unzip.h"
+#include "common/system.h"
+#include "common/stream.h"
-#include "graphics/surface.h"
+#include "graphics/cursorman.h"
+#include "graphics/fonts/bdf.h"
+#include "graphics/managed_surface.h"
+#include "graphics/palette.h"
+#include "graphics/primitives.h"
-#include "wage/wage.h"
-#include "wage/macwindow.h"
#include "wage/macwindowmanager.h"
+#include "wage/macwindow.h"
+#include "wage/macmenu.h"
namespace Wage {
+static const byte palette[] = {
+ 0, 0, 0, // Black
+ 0x80, 0x80, 0x80, // Gray
+ 0xff, 0xff, 0xff, // White
+ 0x00, 0xff, 0x00, // Green
+ 0x00, 0xcf, 0x00 // Green2
+};
+
+static byte fillPatterns[][8] = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, // kPatternSolid
+ { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 }, // kPatternStripes
+ { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 }, // kPatternCheckers
+ { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa } // kPatternCheckers2
+};
+
+static const byte macCursorArrow[] = {
+ 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 2, 0, 2, 3, 3, 3, 3, 3, 3, 3, 3,
+ 2, 0, 0, 2, 3, 3, 3, 3, 3, 3, 3,
+ 2, 0, 0, 0, 2, 3, 3, 3, 3, 3, 3,
+ 2, 0, 0, 0, 0, 2, 3, 3, 3, 3, 3,
+ 2, 0, 0, 0, 0, 0, 2, 3, 3, 3, 3,
+ 2, 0, 0, 0, 0, 0, 0, 2, 3, 3, 3,
+ 2, 0, 0, 0, 0, 0, 0, 0, 2, 3, 3,
+ 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3,
+ 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2,
+ 2, 0, 0, 2, 0, 0, 2, 3, 3, 3, 3,
+ 2, 0, 2, 3, 2, 0, 0, 2, 3, 3, 3,
+ 2, 2, 3, 3, 2, 0, 0, 2, 3, 3, 3,
+ 2, 3, 3, 3, 3, 2, 0, 0, 2, 3, 3,
+ 3, 3, 3, 3, 3, 2, 0, 0, 2, 3, 3,
+ 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 3
+};
+
+static const byte macCursorBeam[] = {
+ 0, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3,
+ 3, 3, 0, 3, 0, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 0, 3, 0, 3, 3, 3, 3, 3, 3,
+ 0, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3,
+};
+
MacWindowManager::MacWindowManager() {
+ _screen = 0;
_lastId = 0;
_activeWindow = -1;
+
+ _menu = 0;
+
+ _fullRefresh = true;
+
+ _builtInFonts = true;
+
+ for (int i = 0; i < ARRAYSIZE(fillPatterns); i++)
+ _patterns.push_back(fillPatterns[i]);
+
+ loadFonts();
+
+ g_system->getPaletteManager()->setPalette(palette, 0, ARRAYSIZE(palette) / 3);
+
+ CursorMan.replaceCursorPalette(palette, 0, ARRAYSIZE(palette) / 3);
+ CursorMan.replaceCursor(macCursorArrow, 11, 16, 1, 1, 3);
+ _cursorIsArrow = true;
+ CursorMan.showMouse(true);
}
MacWindowManager::~MacWindowManager() {
- for (uint i = 0; i < _lastId; i++)
+ for (int i = 0; i < _lastId; i++)
delete _windows[i];
}
-int MacWindowManager::add(bool scrollable) {
- MacWindow *w = new MacWindow(scrollable);
+MacWindow *MacWindowManager::addWindow(bool scrollable, bool resizable, bool editable) {
+ MacWindow *w = new MacWindow(_lastId, scrollable, resizable, editable, this);
_windows.push_back(w);
_windowStack.push_back(w);
- _activeWindow = _lastId;
+ setActive(_lastId);
_lastId++;
- return _activeWindow;
+ return w;
+}
+
+Menu *MacWindowManager::addMenu() {
+ _menu = new Menu(_lastId, _screen->getBounds(), this);
+
+ _windows.push_back(_menu);
+
+ _lastId++;
+
+ return _menu;
}
void MacWindowManager::setActive(int id) {
@@ -86,6 +175,8 @@ void MacWindowManager::setActive(int id) {
if (_activeWindow != -1)
_windows[_activeWindow]->setActive(false);
+ _activeWindow = id;
+
_windows[id]->setActive(true);
_windowStack.remove(_windows[id]);
@@ -94,11 +185,196 @@ void MacWindowManager::setActive(int id) {
_fullRefresh = true;
}
-void MacWindowManager::draw(Graphics::Surface *g) {
- for (Common::List<MacWindow *>::const_iterator it = _windowStack.begin(); it != _windowStack.end(); it++)
- (*it)->draw(g, _fullRefresh);
+struct PlotData {
+ Graphics::ManagedSurface *surface;
+ Patterns *patterns;
+ uint fillType;
+ int thickness;
+
+ PlotData(Graphics::ManagedSurface *s, Patterns *p, int f, int t) :
+ surface(s), patterns(p), fillType(f), thickness(t) {}
+};
+
+static void drawPixel(int x, int y, int color, void *data) {
+ PlotData *p = (PlotData *)data;
+
+ if (p->fillType > p->patterns->size())
+ return;
+
+ byte *pat = p->patterns->operator[](p->fillType - 1);
+
+ if (p->thickness == 1) {
+ if (x >= 0 && x < p->surface->w && y >= 0 && y < p->surface->h) {
+ uint xu = (uint)x; // for letting compiler optimize it
+ uint yu = (uint)y;
+
+ *((byte *)p->surface->getBasePtr(xu, yu)) =
+ (pat[yu % 8] & (1 << (7 - xu % 8))) ?
+ color : kColorWhite;
+ }
+ } else {
+ int x1 = x;
+ int x2 = x1 + p->thickness;
+ int y1 = y;
+ int y2 = y1 + p->thickness;
+
+ for (y = y1; y < y2; y++)
+ for (x = x1; x < x2; x++)
+ if (x >= 0 && x < p->surface->w && y >= 0 && y < p->surface->h) {
+ uint xu = (uint)x; // for letting compiler optimize it
+ uint yu = (uint)y;
+ *((byte *)p->surface->getBasePtr(xu, yu)) =
+ (pat[yu % 8] & (1 << (7 - xu % 8))) ?
+ color : kColorWhite;
+ }
+ }
+}
+
+void MacWindowManager::drawDesktop() {
+ Common::Rect r(_screen->getBounds());
+
+ PlotData pd(_screen, &_patterns, kPatternCheckers, 1);
+
+ Graphics::drawRoundRect(r, kDesktopArc, kColorBlack, true, drawPixel, &pd);
+
+ g_system->copyRectToScreen(_screen->getPixels(), _screen->pitch, 0, 0, _screen->w, _screen->h);
+}
+
+void MacWindowManager::draw() {
+ assert(_screen);
+
+ if (_fullRefresh)
+ drawDesktop();
+
+ for (Common::List<BaseMacWindow *>::const_iterator it = _windowStack.begin(); it != _windowStack.end(); it++) {
+ BaseMacWindow *w = *it;
+ if (w->draw(_screen, _fullRefresh)) {
+ w->setDirty(false);
+
+ Common::Rect clip(w->getDimensions().left - 2, w->getDimensions().top - 2, w->getDimensions().right - 2, w->getDimensions().bottom - 2);
+ clip.clip(_screen->getBounds());
+
+ g_system->copyRectToScreen(_screen->getBasePtr(clip.left, clip.top), _screen->pitch, clip.left, clip.top, clip.width(), clip.height());
+ }
+ }
+
+ // Menu is drawn on top of everything and always
+ if (_menu)
+ _menu->draw(_screen, _fullRefresh);
_fullRefresh = false;
}
+bool MacWindowManager::processEvent(Common::Event &event) {
+ // Menu gets events first fir shortcuts and menu bar
+ if (_menu && _menu->processEvent(event))
+ return true;
+
+ if (event.type != Common::EVENT_MOUSEMOVE && event.type != Common::EVENT_LBUTTONDOWN &&
+ event.type != Common::EVENT_LBUTTONUP)
+ return false;
+
+ if (_windows[_activeWindow]->isEditable() && _windows[_activeWindow]->getType() == kWindowWindow &&
+ ((MacWindow *)_windows[_activeWindow])->getInnerDimensions().contains(event.mouse.x, event.mouse.y)) {
+ if (_cursorIsArrow) {
+ CursorMan.replaceCursor(macCursorBeam, 11, 16, 3, 8, 3);
+ _cursorIsArrow = false;
+ }
+ } else {
+ if (_cursorIsArrow == false) {
+ CursorMan.replaceCursor(macCursorArrow, 11, 16, 1, 1, 3);
+ _cursorIsArrow = true;
+ }
+ }
+
+ for (Common::List<BaseMacWindow *>::const_iterator it = _windowStack.end(); it != _windowStack.begin();) {
+ it--;
+ BaseMacWindow *w = *it;
+
+ if (w->hasAllFocus() || w->getDimensions().contains(event.mouse.x, event.mouse.y)) {
+ if (event.type == Common::EVENT_LBUTTONDOWN || event.type == Common::EVENT_LBUTTONUP)
+ setActive(w->getId());
+
+ return w->processEvent(event);
+ }
+ }
+
+ return false;
+}
+
+//////////////////////
+// Font stuff
+//////////////////////
+void MacWindowManager::loadFonts() {
+ Common::Archive *dat;
+
+ dat = Common::makeZipArchive("classicmacfonts.dat");
+
+ if (!dat) {
+ warning("Could not find classicmacfonts.dat. Falling back to built-in fonts");
+ _builtInFonts = true;
+
+ return;
+ }
+
+ Common::ArchiveMemberList list;
+ dat->listMembers(list);
+
+ for (Common::ArchiveMemberList::iterator it = list.begin(); it != list.end(); ++it) {
+ Common::SeekableReadStream *stream = dat->createReadStreamForMember((*it)->getName());
+
+ Graphics::BdfFont *font = Graphics::BdfFont::loadFont(*stream);
+
+ delete stream;
+
+ Common::String fontName = (*it)->getName();
+
+ // Trim the .bdf extension
+ for (int i = fontName.size() - 1; i >= 0; --i) {
+ if (fontName[i] == '.') {
+ while ((uint)i < fontName.size()) {
+ fontName.deleteLastChar();
+ }
+ break;
+ }
+ }
+
+ FontMan.assignFontToName(fontName, font);
+
+ debug(2, " %s", fontName.c_str());
+ }
+
+ _builtInFonts = false;
+
+ delete dat;
+}
+
+const Graphics::Font *MacWindowManager::getFont(const char *name, Graphics::FontManager::FontUsage fallback) {
+ const Graphics::Font *font = 0;
+
+ if (!_builtInFonts) {
+ font = FontMan.getFontByName(name);
+
+ if (!font)
+ warning("Cannot load font %s", name);
+ }
+
+ if (_builtInFonts || !font)
+ font = FontMan.getFontByUsage(fallback);
+
+ return font;
+}
+
+/////////////////
+// Cursor stuff
+/////////////////
+void MacWindowManager::pushArrowCursor() {
+ CursorMan.pushCursor(macCursorArrow, 11, 16, 1, 1, 3);
+}
+
+void MacWindowManager::popCursor() {
+ CursorMan.popCursor();
+}
+
+
} // End of namespace Wage
diff --git a/engines/wage/macwindowmanager.h b/engines/wage/macwindowmanager.h
index b15c7737c6..13f85cddd4 100644
--- a/engines/wage/macwindowmanager.h
+++ b/engines/wage/macwindowmanager.h
@@ -48,30 +48,92 @@
#ifndef WAGE_MACWINDOWMANAGER_H
#define WAGE_MACWINDOWMANAGER_H
+#include "common/array.h"
+#include "common/list.h"
+#include "common/events.h"
+#include "common/archive.h"
+
+#include "graphics/fontman.h"
+
+namespace Graphics {
+class ManagedSurface;
+}
+
namespace Wage {
+enum {
+ kDesktopArc = 7
+};
+
+enum {
+ kColorBlack = 0,
+ kColorGray = 1,
+ kColorWhite = 2,
+ kColorGreen = 3,
+ kColorGreen2 = 4
+};
+
+enum {
+ kPatternSolid = 1,
+ kPatternStripes = 2,
+ kPatternCheckers = 3,
+ kPatternCheckers2 = 4
+};
+
+class BaseMacWindow;
class MacWindow;
+class Menu;
+
+typedef Common::Array<byte *> Patterns;
class MacWindowManager {
public:
MacWindowManager();
~MacWindowManager();
- int add(bool scrollable);
+ void setScreen(Graphics::ManagedSurface *screen) { _screen = screen; }
+ bool hasBuiltInFonts() { return _builtInFonts; }
+ const Graphics::Font *getFont(const char *name, Graphics::FontManager::FontUsage fallback);
+
+ MacWindow *addWindow(bool scrollable, bool resizable, bool editable);
+ Menu *addMenu();
void setActive(int id);
- void draw(Graphics::Surface *g);
+ void setFullRefresh(bool redraw) { _fullRefresh = true; }
- MacWindow *getWindow(int id) { return _windows[id]; }
+ void draw();
+
+ bool processEvent(Common::Event &event);
+
+ BaseMacWindow *getWindow(int id) { return _windows[id]; }
+
+ Patterns &getPatterns() { return _patterns; }
+ void drawFilledRoundRect(Graphics::ManagedSurface *surface, Common::Rect &rect, int arc, int color);
+
+ void pushArrowCursor();
+ void popCursor();
+
+private:
+ void drawDesktop();
+ void loadFonts();
private:
- Common::List<MacWindow *> _windowStack;
- Common::Array<MacWindow *> _windows;
+ Graphics::ManagedSurface *_screen;
+
+ Common::List<BaseMacWindow *> _windowStack;
+ Common::Array<BaseMacWindow *> _windows;
int _lastId;
int _activeWindow;
bool _fullRefresh;
+
+ Patterns _patterns;
+
+ Menu *_menu;
+
+ bool _builtInFonts;
+ bool _cursorIsArrow;
};
} // End of namespace Wage
diff --git a/engines/wage/module.mk b/engines/wage/module.mk
index d65934fc2b..e150d5f27e 100644
--- a/engines/wage/module.mk
+++ b/engines/wage/module.mk
@@ -9,9 +9,9 @@ MODULE_OBJS := \
entities.o \
gui.o \
gui-console.o \
+ macmenu.o \
macwindow.o \
macwindowmanager.o \
- menu.o \
randomhat.o \
script.o \
sound.o \
diff --git a/engines/wage/wage.cpp b/engines/wage/wage.cpp
index 3a52aed1c4..567e2768d8 100644
--- a/engines/wage/wage.cpp
+++ b/engines/wage/wage.cpp
@@ -86,6 +86,7 @@ WageEngine::WageEngine(OSystem *syst, const ADGameDescription *desc) : Engine(sy
_offer = NULL;
_resManager = NULL;
+ _debugger = NULL;
debug("WageEngine::WageEngine()");
}
@@ -148,24 +149,14 @@ void WageEngine::processEvents() {
Common::Event event;
while (_eventMan->pollEvent(event)) {
+ if (_gui->processEvent(event))
+ continue;
+
switch (event.type) {
case Common::EVENT_QUIT:
if (saveDialog())
_shouldQuit = true;
break;
- case Common::EVENT_MOUSEMOVE:
- _gui->mouseMove(event.mouse.x, event.mouse.y);
- break;
- case Common::EVENT_LBUTTONDOWN:
- _gui->mouseDown(event.mouse.x, event.mouse.y);
- break;
- case Common::EVENT_LBUTTONUP:
- {
- Designed *obj = _gui->mouseUp(event.mouse.x, event.mouse.y);
- if (obj != NULL)
- processTurn(NULL, obj);
- }
- break;
case Common::EVENT_KEYDOWN:
switch (event.kbd.keycode) {
case Common::KEYCODE_BACKSPACE:
@@ -189,13 +180,6 @@ void WageEngine::processEvents() {
break;
}
- if (event.kbd.flags & (Common::KBD_ALT | Common::KBD_CTRL | Common::KBD_META)) {
- if (event.kbd.ascii >= 0x20 && event.kbd.ascii <= 0x7f) {
- _gui->processMenuShortCut(event.kbd.flags, event.kbd.ascii);
- }
- break;
- }
-
if (event.kbd.ascii >= 0x20 && event.kbd.ascii <= 0x7f) {
_inputText += (char)event.kbd.ascii;
_gui->drawInput();
@@ -236,7 +220,6 @@ void WageEngine::gameOver() {
_gui->disableAllMenus();
_gui->enableNewGameMenus();
- _gui->_menuDirty = true;
}
bool WageEngine::saveDialog() {
diff --git a/engines/wage/wage.h b/engines/wage/wage.h
index 87009c2350..eb50a2e3dd 100644
--- a/engines/wage/wage.h
+++ b/engines/wage/wage.h
@@ -103,14 +103,6 @@ enum {
// the current limitation is 32 debug levels (1 << 31 is the last one)
};
-enum {
- kColorBlack = 0,
- kColorGray = 1,
- kColorWhite = 2,
- kColorGreen = 3,
- kColorGreen2 = 4
-};
-
Common::String readPascalString(Common::SeekableReadStream *in);
Common::Rect *readRect(Common::SeekableReadStream *in);
const char *getIndefiniteArticle(const Common::String &word);
@@ -118,8 +110,6 @@ const char *prependGenderSpecificPronoun(int gender);
const char *getGenderSpecificPronoun(int gender, bool capitalize);
bool isStorageScene(const Common::String &name);
-typedef Common::Array<byte *> Patterns;
-
class WageEngine : public Engine {
friend class Dialog;
public:
diff --git a/engines/wage/world.cpp b/engines/wage/world.cpp
index 954a425b7b..53fc1b4742 100644
--- a/engines/wage/world.cpp
+++ b/engines/wage/world.cpp
@@ -73,6 +73,8 @@ World::World(WageEngine *engine) {
_weaponMenuDisabled = true;
_engine = engine;
+
+ _patterns = new Patterns;
}
World::~World() {
@@ -88,8 +90,10 @@ World::~World() {
for (uint i = 0; i < _orderedScenes.size(); i++)
delete _orderedScenes[i];
- for (uint i = 0; i < _patterns.size(); i++)
- free(_patterns[i]);
+ for (uint i = 0; i < _patterns->size(); i++)
+ free(_patterns->operator[](i));
+
+ delete _patterns;
delete _globalScript;
@@ -261,7 +265,7 @@ bool World::loadWorld(Common::MacResManager *resMan) {
byte *pattern = (byte *)malloc(8);
res->read(pattern, 8);
- _patterns.push_back(pattern);
+ _patterns->push_back(pattern);
}
delete res;
@@ -274,7 +278,7 @@ bool World::loadWorld(Common::MacResManager *resMan) {
byte *pattern = (byte *)malloc(8);
res->read(pattern, 8);
- _patterns.push_back(pattern);
+ _patterns->push_back(pattern);
}
}
delete res;
diff --git a/engines/wage/world.h b/engines/wage/world.h
index 355d660c8d..468bedbc59 100644
--- a/engines/wage/world.h
+++ b/engines/wage/world.h
@@ -48,6 +48,8 @@
#ifndef WAGE_WORLD_H
#define WAGE_WORLD_H
+#include "wage/macwindowmanager.h"
+
namespace Wage {
class Sound;
@@ -85,7 +87,7 @@ public:
ObjArray _orderedObjs;
ChrArray _orderedChrs;
Common::Array<Sound *> _orderedSounds;
- Patterns _patterns;
+ Patterns *_patterns;
Scene *_storageScene;
Chr *_player;
//List<MoveListener> moveListeners;
diff --git a/engines/wintermute/base/base_engine.cpp b/engines/wintermute/base/base_engine.cpp
index 2166a3e070..4ce334aceb 100644
--- a/engines/wintermute/base/base_engine.cpp
+++ b/engines/wintermute/base/base_engine.cpp
@@ -84,7 +84,7 @@ void BaseEngine::LOG(bool res, const char *fmt, ...) {
va_end(va);
if (instance()._gameRef) {
- instance()._gameRef->LOG("%s", buff);
+ instance()._gameRef->LOG(res, "%s", buff);
} else {
debugCN(kWintermuteDebugLog, "%02d:%02d:%02d: %s\n", hours, mins, secs, buff);
}
diff --git a/engines/wintermute/base/sound/base_sound_manager.cpp b/engines/wintermute/base/sound/base_sound_manager.cpp
index f1e0c3b1f9..74c0086817 100644
--- a/engines/wintermute/base/sound/base_sound_manager.cpp
+++ b/engines/wintermute/base/sound/base_sound_manager.cpp
@@ -100,15 +100,14 @@ BaseSoundBuffer *BaseSoundMgr::addSound(const Common::String &filename, Audio::M
BaseSoundBuffer *sound;
Common::String useFilename = filename;
+ useFilename.toLowercase();
// try to switch WAV to OGG file (if available)
- AnsiString ext = PathUtil::getExtension(filename);
- if (StringUtil::compareNoCase(ext, "wav")) {
- AnsiString path = PathUtil::getDirectoryName(filename);
- AnsiString name = PathUtil::getFileNameWithoutExtension(filename);
-
- AnsiString newFile = PathUtil::combine(path, name + "ogg");
- if (BaseFileManager::getEngineInstance()->hasFile(newFile)) {
- useFilename = newFile;
+ if (useFilename.hasSuffix(".wav")) {
+ Common::String oggFilename = useFilename;
+ oggFilename.erase(oggFilename.size() - 4);
+ oggFilename = oggFilename + ".ogg";
+ if (BaseFileManager::getEngineInstance()->hasFile(oggFilename)) {
+ useFilename = oggFilename;
}
}
diff --git a/engines/wintermute/detection.cpp b/engines/wintermute/detection.cpp
index f77eb5c64d..4e8eab505f 100644
--- a/engines/wintermute/detection.cpp
+++ b/engines/wintermute/detection.cpp
@@ -85,7 +85,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "Copyright (c) 2011 Jan Nedoma";
+ return "Copyright (C) 2011 Jan Nedoma";
}
virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
diff --git a/engines/wintermute/ui/ui_window.cpp b/engines/wintermute/ui/ui_window.cpp
index 9f3cdeaaa3..34341d1db2 100644
--- a/engines/wintermute/ui/ui_window.cpp
+++ b/engines/wintermute/ui/ui_window.cpp
@@ -139,13 +139,12 @@ bool UIWindow::display(int offsetX, int offsetY) {
_shieldButton->setListener(this, _shieldButton, 0);
_shieldButton->_parent = this;
}
- if (_shieldButton) {
- _shieldButton->_posX = _shieldButton->_posY = 0;
- _shieldButton->setWidth(_gameRef->_renderer->getWidth());
- _shieldButton->setHeight(_gameRef->_renderer->getHeight());
- _shieldButton->display();
- }
+ _shieldButton->_posX = _shieldButton->_posY = 0;
+ _shieldButton->setWidth(_gameRef->_renderer->getWidth());
+ _shieldButton->setHeight(_gameRef->_renderer->getHeight());
+
+ _shieldButton->display();
}
if (!_visible) {
diff --git a/engines/wintermute/wintermute.h b/engines/wintermute/wintermute.h
index f8f5fc7deb..f61a809b22 100644
--- a/engines/wintermute/wintermute.h
+++ b/engines/wintermute/wintermute.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef WINTERMUTE_H
-#define WINTERMUTE_H
+#ifndef WINTERMUTE_WINTERMUTE_H
+#define WINTERMUTE_WINTERMUTE_H
#include "engines/engine.h"
#include "engines/advancedDetector.h"